/* * 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 #include #include #include 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 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 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; // 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> 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; }; skia_private::THashMap fAtlasPathCache; }; } // namespace skgpu::ganesh #endif // GrAtlasPathRenderer_DEFINED