1 /* 2 * Copyright 2019 Google LLC. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef AtlasPathRenderer_DEFINED 9 #define AtlasPathRenderer_DEFINED 10 11 #include "include/core/SkRefCnt.h" 12 #include "include/private/base/SkTArray.h" 13 #include "src/core/SkChecksum.h" 14 #include "src/core/SkIPoint16.h" 15 #include "src/core/SkTHash.h" 16 #include "src/gpu/ganesh/GrFragmentProcessor.h" 17 #include "src/gpu/ganesh/GrOnFlushResourceProvider.h" 18 #include "src/gpu/ganesh/PathRenderer.h" 19 #include "src/gpu/ganesh/ops/AtlasRenderTask.h" 20 21 #include <cstdint> 22 #include <cstring> 23 #include <functional> 24 #include <memory> 25 26 class GrDirectContext; 27 class GrOp; 28 class GrRecordingContext; 29 class GrStyledShape; 30 class GrSurfaceProxy; 31 class SkMatrix; 32 class SkPath; 33 enum class GrAAType : unsigned int; 34 struct SkIRect; 35 struct SkRect; 36 37 namespace skgpu::ganesh { 38 39 class SurfaceDrawContext; 40 41 // Draws paths by first rendering their coverage mask into an offscreen atlas. 42 class AtlasPathRenderer final : public PathRenderer, public GrOnFlushCallbackObject { 43 public: 44 static bool IsSupported(GrRecordingContext*); 45 46 // Returns a GrAtlasPathRenderer if it is supported, otherwise null. 47 static sk_sp<AtlasPathRenderer> Make(GrRecordingContext* rContext); 48 name()49 const char* name() const override { return "GrAtlasPathRenderer"; } 50 51 // Returns a fragment processor that modulates inputFP by the given deviceSpacePath's coverage, 52 // implemented using an internal atlas. 53 // 54 // Returns 'inputFP' wrapped in GrFPFailure() if the path was too large, or if the current atlas 55 // is full and already used by either opBeingClipped or inputFP. (Currently, "too large" means 56 // larger than fMaxAtlasSize in either dimension, more than 256^2 total pixels, or more than 57 // 128^2 total pixels if the surfaceDrawContext supports MSAA or DMSAA.) 58 // 59 // Also returns GrFPFailure() if the view matrix has perspective. 60 GrFPResult makeAtlasClipEffect(const skgpu::ganesh::SurfaceDrawContext*, 61 const GrOp* opBeingClipped, 62 std::unique_ptr<GrFragmentProcessor> inputFP, 63 const SkIRect& drawBounds, 64 const SkMatrix&, 65 const SkPath&); 66 67 private: 68 // The atlas is not compatible with DDL. We can only use it on direct contexts. 69 AtlasPathRenderer(GrDirectContext*); 70 onGetStencilSupport(const GrStyledShape &)71 StencilSupport onGetStencilSupport(const GrStyledShape&) const override { 72 return kNoSupport_StencilSupport; 73 } 74 75 CanDrawPath onCanDrawPath(const CanDrawPathArgs&) const override; 76 77 bool onDrawPath(const DrawPathArgs&) override; 78 79 // Returns true if the given device-space path bounds are small enough to fit in an atlas and to 80 // benefit from atlasing. (Currently, "small enough" means no larger than fMaxAtlasSize in 81 // either dimension, no more than 256^2 total pixels, or no more than 128^2 total pixels if the 82 // fallbackAAType is kMSAA.) 83 bool pathFitsInAtlas(const SkRect& pathDevBounds, GrAAType fallbackAAType) const; 84 85 // Returns true if the draw being set up already uses the given atlasProxy. 86 using DrawRefsAtlasCallback = std::function<bool(const GrSurfaceProxy* atlasProxy)>; 87 88 // Adds the filled path to an atlas. 89 // 90 // pathFitsInAtlas() and is_visible() both must have returned true before making this call. 91 // 92 // Fails and returns false if the current atlas is full and already in use according to 93 // DrawRefsAtlasCallback. 94 bool addPathToAtlas(GrRecordingContext*, 95 const SkMatrix&, 96 const SkPath&, 97 const SkRect& pathDevBounds, 98 SkIRect* devIBounds, 99 SkIPoint16* locationInAtlas, 100 bool* transposedInAtlas, 101 const DrawRefsAtlasCallback&); 102 103 // Instantiates texture(s) for all atlases we've created since the last flush. Atlases that are 104 // the same size will be instantiated with the same backing texture. 105 bool preFlush(GrOnFlushResourceProvider*) override; 106 107 float fAtlasMaxSize = 0; 108 float fAtlasMaxPathWidth = 0; 109 int fAtlasInitialSize = 0; 110 111 // A collection of all atlases we've created and used since the last flush. We instantiate these 112 // at flush time during preFlush(). 113 skia_private::STArray<4, sk_sp<AtlasRenderTask>> fAtlasRenderTasks; 114 115 // This simple cache remembers the locations of cacheable path masks in the most recent atlas. 116 // Its main motivation is for clip paths. 117 struct AtlasPathKey { 118 void set(const SkMatrix&, const SkPath&); 119 bool operator==(const AtlasPathKey& k) const { 120 static_assert(sizeof(*this) == sizeof(uint32_t) * 8); 121 return !memcmp(this, &k, sizeof(*this)); 122 } 123 uint32_t fPathGenID; 124 float fAffineMatrix[6]; 125 uint32_t fFillRule; 126 127 using Hash = SkForceDirectHash<AtlasPathKey>; 128 }; 129 130 skia_private::THashMap<AtlasPathKey, SkIPoint16, AtlasPathKey::Hash> fAtlasPathCache; 131 }; 132 133 } // namespace skgpu::ganesh 134 135 #endif // GrAtlasPathRenderer_DEFINED 136