| /* | |
| * Copyright 2019 Google LLC. | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #ifndef AtlasPathRenderer_DEFINED | |
| #define AtlasPathRenderer_DEFINED | |
| #include "include/core/SkRefCnt.h" | |
| #include "include/private/base/SkTArray.h" | |
| #include "src/core/SkChecksum.h" | |
| #include "src/core/SkIPoint16.h" | |
| #include "src/core/SkTHash.h" | |
| #include "src/gpu/ganesh/GrFragmentProcessor.h" | |
| #include "src/gpu/ganesh/GrOnFlushResourceProvider.h" | |
| #include "src/gpu/ganesh/PathRenderer.h" | |
| #include "src/gpu/ganesh/ops/AtlasRenderTask.h" | |
| #include <cstdint> | |
| #include <cstring> | |
| #include <functional> | |
| #include <memory> | |
| class GrDirectContext; | |
| class GrOp; | |
| class GrRecordingContext; | |
| class GrStyledShape; | |
| class GrSurfaceProxy; | |
| class SkMatrix; | |
| class SkPath; | |
| enum class GrAAType : unsigned int; | |
| struct SkIRect; | |
| struct SkRect; | |
| namespace skgpu::ganesh { | |
| class SurfaceDrawContext; | |
| // Draws paths by first rendering their coverage mask into an offscreen atlas. | |
| class AtlasPathRenderer final : public PathRenderer, public GrOnFlushCallbackObject { | |
| public: | |
| static bool IsSupported(GrRecordingContext*); | |
| // Returns a GrAtlasPathRenderer if it is supported, otherwise null. | |
| static sk_sp<AtlasPathRenderer> Make(GrRecordingContext* rContext); | |
| const char* name() const override { return "GrAtlasPathRenderer"; } | |
| // Returns a fragment processor that modulates inputFP by the given deviceSpacePath's coverage, | |
| // implemented using an internal atlas. | |
| // | |
| // Returns 'inputFP' wrapped in GrFPFailure() if the path was too large, or if the current atlas | |
| // is full and already used by either opBeingClipped or inputFP. (Currently, "too large" means | |
| // larger than fMaxAtlasSize in either dimension, more than 256^2 total pixels, or more than | |
| // 128^2 total pixels if the surfaceDrawContext supports MSAA or DMSAA.) | |
| // | |
| // Also returns GrFPFailure() if the view matrix has perspective. | |
| GrFPResult makeAtlasClipEffect(const skgpu::ganesh::SurfaceDrawContext*, | |
| const GrOp* opBeingClipped, | |
| std::unique_ptr<GrFragmentProcessor> inputFP, | |
| const SkIRect& drawBounds, | |
| const SkMatrix&, | |
| const SkPath&); | |
| private: | |
| // The atlas is not compatible with DDL. We can only use it on direct contexts. | |
| AtlasPathRenderer(GrDirectContext*); | |
| StencilSupport onGetStencilSupport(const GrStyledShape&) const override { | |
| return kNoSupport_StencilSupport; | |
| } | |
| CanDrawPath onCanDrawPath(const CanDrawPathArgs&) const override; | |
| bool onDrawPath(const DrawPathArgs&) override; | |
| // Returns true if the given device-space path bounds are small enough to fit in an atlas and to | |
| // benefit from atlasing. (Currently, "small enough" means no larger than fMaxAtlasSize in | |
| // either dimension, no more than 256^2 total pixels, or no more than 128^2 total pixels if the | |
| // fallbackAAType is kMSAA.) | |
| bool pathFitsInAtlas(const SkRect& pathDevBounds, GrAAType fallbackAAType) const; | |
| // Returns true if the draw being set up already uses the given atlasProxy. | |
| using DrawRefsAtlasCallback = std::function<bool(const GrSurfaceProxy* atlasProxy)>; | |
| // Adds the filled path to an atlas. | |
| // | |
| // pathFitsInAtlas() and is_visible() both must have returned true before making this call. | |
| // | |
| // Fails and returns false if the current atlas is full and already in use according to | |
| // DrawRefsAtlasCallback. | |
| bool addPathToAtlas(GrRecordingContext*, | |
| const SkMatrix&, | |
| const SkPath&, | |
| const SkRect& pathDevBounds, | |
| SkIRect* devIBounds, | |
| SkIPoint16* locationInAtlas, | |
| bool* transposedInAtlas, | |
| const DrawRefsAtlasCallback&); | |
| // Instantiates texture(s) for all atlases we've created since the last flush. Atlases that are | |
| // the same size will be instantiated with the same backing texture. | |
| bool preFlush(GrOnFlushResourceProvider*) override; | |
| float fAtlasMaxSize = 0; | |
| float fAtlasMaxPathWidth = 0; | |
| int fAtlasInitialSize = 0; | |
| // A collection of all atlases we've created and used since the last flush. We instantiate these | |
| // at flush time during preFlush(). | |
| skia_private::STArray<4, sk_sp<AtlasRenderTask>> fAtlasRenderTasks; | |
| // This simple cache remembers the locations of cacheable path masks in the most recent atlas. | |
| // Its main motivation is for clip paths. | |
| struct AtlasPathKey { | |
| void set(const SkMatrix&, const SkPath&); | |
| bool operator==(const AtlasPathKey& k) const { | |
| static_assert(sizeof(*this) == sizeof(uint32_t) * 8); | |
| return !memcmp(this, &k, sizeof(*this)); | |
| } | |
| uint32_t fPathGenID; | |
| float fAffineMatrix[6]; | |
| uint32_t fFillRule; | |
| using Hash = SkForceDirectHash<AtlasPathKey>; | |
| }; | |
| skia_private::THashMap<AtlasPathKey, SkIPoint16, AtlasPathKey::Hash> fAtlasPathCache; | |
| }; | |
| } // namespace skgpu::ganesh | |
| #endif // GrAtlasPathRenderer_DEFINED |