1 /* 2 * Copyright 2015 Google Inc. 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 skgpu_ganesh_AtlasTextOp_DEFINED 9 #define skgpu_ganesh_AtlasTextOp_DEFINED 10 11 #include "src/gpu/AtlasTypes.h" 12 #include "src/gpu/ganesh/GrColorSpaceXform.h" 13 #include "src/gpu/ganesh/effects/GrDistanceFieldGeoProc.h" 14 #include "src/gpu/ganesh/ops/GrMeshDrawOp.h" 15 #include "src/text/gpu/TextBlob.h" 16 17 class GrProgramInfo; 18 class GrRecordingContext; 19 20 namespace skgpu::ganesh { 21 22 class AtlasTextOp final : public GrMeshDrawOp { 23 public: 24 DEFINE_OP_CLASS_ID 25 ~AtlasTextOp()26 ~AtlasTextOp() override { 27 for (const Geometry* g = fHead; g != nullptr;) { 28 const Geometry* next = g->fNext; 29 g->~Geometry(); 30 g = next; 31 } 32 } 33 34 void* operator new(size_t s); 35 void operator delete(void* b) noexcept; 36 static void ClearCache(); 37 38 struct Geometry { GeometryGeometry39 Geometry(const sktext::gpu::AtlasSubRun& subRun, 40 const SkMatrix& drawMatrix, 41 SkPoint drawOrigin, 42 SkIRect clipRect, 43 sk_sp<SkRefCnt>&& supportData, 44 const SkPMColor4f& color) 45 : fSubRun{subRun} 46 , fSupportDataKeepAlive{std::move(supportData)} 47 , fDrawMatrix{drawMatrix} 48 , fDrawOrigin{drawOrigin} 49 , fClipRect{clipRect} 50 , fColor{color} { 51 SkASSERT(fSupportDataKeepAlive != nullptr); 52 } 53 54 static Geometry* Make(const sktext::gpu::AtlasSubRun& subRun, 55 const SkMatrix& drawMatrix, 56 SkPoint drawOrigin, 57 SkIRect clipRect, 58 sk_sp<SkRefCnt>&& supportData, 59 const SkPMColor4f& color, 60 SkArenaAlloc* alloc); 61 62 void fillVertexData(void* dst, int offset, int count) const; 63 64 const sktext::gpu::AtlasSubRun& fSubRun; 65 66 // Keep the TextBlob or Slug alive until the op is deleted. 67 sk_sp<SkRefCnt> fSupportDataKeepAlive; 68 69 const SkMatrix fDrawMatrix; 70 const SkPoint fDrawOrigin; 71 72 // fClipRect is only used in the DirectMaskSubRun case to do geometric clipping. 73 // TransformedMaskSubRun, and SDFTSubRun don't use this field, and expect an empty rect. 74 const SkIRect fClipRect; 75 76 // Color is updated after processor analysis if it was determined the shader resolves to 77 // a constant color that we then evaluate on the CPU. 78 // TODO: This can be made const once processor analysis is separated from op creation. 79 SkPMColor4f fColor; 80 Geometry* fNext{nullptr}; 81 }; 82 name()83 const char* name() const override { return "AtlasTextOp"; } 84 85 void visitProxies(const GrVisitProxyFunc&) const override; 86 87 FixedFunctionFlags fixedFunctionFlags() const override; 88 89 GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override; 90 91 enum class MaskType : uint32_t { 92 kGrayscaleCoverage, 93 kLCDCoverage, 94 kColorBitmap, 95 #if !defined(SK_DISABLE_SDF_TEXT) 96 kAliasedDistanceField, 97 kGrayscaleDistanceField, 98 kLCDDistanceField, 99 kLCDBGRDistanceField, 100 101 kLast = kLCDBGRDistanceField 102 #else 103 kLast = kColorBitmap 104 #endif 105 }; 106 inline static constexpr int kMaskTypeCount = static_cast<int>(MaskType::kLast) + 1; 107 108 #if GR_TEST_UTILS 109 static GrOp::Owner CreateOpTestingOnly(skgpu::v1::SurfaceDrawContext*, 110 const SkPaint&, 111 const SkFont&, 112 const SkMatrixProvider&, 113 const char* text, 114 int x, 115 int y); 116 #endif 117 118 private: 119 friend class GrOp; // for ctor 120 121 struct FlushInfo { 122 sk_sp<const GrBuffer> fVertexBuffer; 123 sk_sp<const GrBuffer> fIndexBuffer; 124 GrGeometryProcessor* fGeometryProcessor; 125 const GrSurfaceProxy** fPrimProcProxies; 126 int fGlyphsToFlush = 0; 127 int fVertexOffset = 0; 128 int fNumDraws = 0; 129 }; 130 131 AtlasTextOp(MaskType maskType, 132 bool needsTransform, 133 int glyphCount, 134 SkRect deviceRect, 135 Geometry* geo, 136 const GrColorInfo& dstColorInfo, 137 GrPaint&& paint); 138 139 AtlasTextOp(MaskType maskType, 140 bool needsTransform, 141 int glyphCount, 142 SkRect deviceRect, 143 SkColor luminanceColor, 144 bool useGammaCorrectDistanceTable, 145 uint32_t DFGPFlags, 146 Geometry* geo, 147 GrPaint&& paint); 148 programInfo()149 GrProgramInfo* programInfo() override { 150 // TODO [PI]: implement 151 return nullptr; 152 } 153 addGeometry(Geometry * geometry)154 void addGeometry(Geometry* geometry) { 155 *fTail = geometry; 156 // The geometry may have many entries. Find the end. 157 do { 158 fTail = &(*fTail)->fNext; 159 } while (*fTail != nullptr); 160 } 161 onCreateProgramInfo(const GrCaps *,SkArenaAlloc *,const GrSurfaceProxyView & writeView,bool usesMSAASurface,GrAppliedClip &&,const GrDstProxyView &,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)162 void onCreateProgramInfo(const GrCaps*, 163 SkArenaAlloc*, 164 const GrSurfaceProxyView& writeView, 165 bool usesMSAASurface, 166 GrAppliedClip&&, 167 const GrDstProxyView&, 168 GrXferBarrierFlags renderPassXferBarriers, 169 GrLoadOp colorLoadOp) override { 170 // We cannot surface the AtlasTextOp's programInfo at record time. As currently 171 // implemented, the GP is modified at flush time based on the number of pages in the 172 // atlas. 173 } 174 onPrePrepareDraws(GrRecordingContext *,const GrSurfaceProxyView & writeView,GrAppliedClip *,const GrDstProxyView &,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)175 void onPrePrepareDraws(GrRecordingContext*, 176 const GrSurfaceProxyView& writeView, 177 GrAppliedClip*, 178 const GrDstProxyView&, 179 GrXferBarrierFlags renderPassXferBarriers, 180 GrLoadOp colorLoadOp) override { 181 // TODO [PI]: implement 182 } 183 184 void onPrepareDraws(GrMeshDrawTarget*) override; 185 void onExecute(GrOpFlushState*, const SkRect& chainBounds) override; 186 187 #if GR_TEST_UTILS 188 SkString onDumpInfo() const override; 189 #endif 190 maskFormat()191 skgpu::MaskFormat maskFormat() const { 192 switch (this->maskType()) { 193 case MaskType::kLCDCoverage: 194 return skgpu::MaskFormat::kA565; 195 case MaskType::kColorBitmap: 196 return skgpu::MaskFormat::kARGB; 197 case MaskType::kGrayscaleCoverage: 198 #if !defined(SK_DISABLE_SDF_TEXT) 199 case MaskType::kAliasedDistanceField: 200 case MaskType::kGrayscaleDistanceField: 201 case MaskType::kLCDDistanceField: 202 case MaskType::kLCDBGRDistanceField: 203 #endif 204 return skgpu::MaskFormat::kA8; 205 } 206 // SkUNREACHABLE; 207 return skgpu::MaskFormat::kA8; 208 } 209 210 #if !defined(SK_DISABLE_SDF_TEXT) usesDistanceFields()211 bool usesDistanceFields() const { 212 return MaskType::kAliasedDistanceField == this->maskType() || 213 MaskType::kGrayscaleDistanceField == this->maskType() || 214 MaskType::kLCDDistanceField == this->maskType() || 215 MaskType::kLCDBGRDistanceField == this->maskType(); 216 } 217 isLCD()218 bool isLCD() const { 219 return MaskType::kLCDCoverage == this->maskType() || 220 MaskType::kLCDDistanceField == this->maskType() || 221 MaskType::kLCDBGRDistanceField == this->maskType(); 222 } 223 #else isLCD()224 bool isLCD() const { 225 return MaskType::kLCDCoverage == this->maskType(); 226 } 227 #endif 228 229 inline void createDrawForGeneratedGlyphs( 230 GrMeshDrawTarget* target, FlushInfo* flushInfo) const; 231 maskType()232 MaskType maskType() const { return static_cast<MaskType>(fMaskType); } 233 234 CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) override; 235 236 #if !defined(SK_DISABLE_SDF_TEXT) 237 GrGeometryProcessor* setupDfProcessor(SkArenaAlloc*, 238 const GrShaderCaps&, 239 const SkMatrix& localMatrix, 240 const GrSurfaceProxyView* views, 241 unsigned int numActiveViews) const; 242 #endif 243 244 GrProcessorSet fProcessors; 245 int fNumGlyphs; // Sum of glyphs in each geometry's subrun 246 247 // All combinable atlas ops have equal bit field values 248 uint32_t fDFGPFlags : 10; // Distance field properties 249 uint32_t fMaskType : 3; // MaskType 250 uint32_t fUsesLocalCoords : 1; // Filled in post processor analysis 251 uint32_t fNeedsGlyphTransform : 1; 252 uint32_t fHasPerspective : 1; // True if perspective affects draw 253 uint32_t fUseGammaCorrectDistanceTable : 1; 254 static_assert(kMaskTypeCount <= 8, "MaskType does not fit in 3 bits"); 255 #if !defined(SK_DISABLE_SDF_TEXT) 256 static_assert(kInvalid_DistanceFieldEffectFlag <= (1 << 9), "DFGP Flags do not fit in 10 bits"); 257 #endif 258 259 // Only needed for color emoji 260 sk_sp<GrColorSpaceXform> fColorSpaceXform; 261 262 // Only used for distance fields; per-channel luminance for LCD, or gamma-corrected luminance 263 // for single-channel distance fields. 264 const SkColor fLuminanceColor{0}; 265 266 Geometry* fHead{nullptr}; 267 Geometry** fTail{&fHead}; 268 269 using INHERITED = GrMeshDrawOp; 270 }; 271 272 } // namespace skgpu::ganesh 273 274 #endif // skgpu_ganesh_AtlasTextOp_DEFINED 275