1 /* 2 * Copyright 2022 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 sktext_gpu_SubRunContainer_DEFINED 9 #define sktext_gpu_SubRunContainer_DEFINED 10 11 #include "include/core/SkMatrix.h" 12 #include "include/core/SkRefCnt.h" 13 #include "include/core/SkSpan.h" 14 #include "src/text/gpu/SubRunAllocator.h" 15 16 #include <cstddef> 17 #include <functional> 18 #include <iterator> 19 #include <memory> 20 #include <tuple> 21 #include <utility> 22 23 class SkCanvas; 24 class SkPaint; 25 class SkReadBuffer; 26 class SkStrikeClient; 27 class SkWriteBuffer; 28 struct SkIRect; 29 struct SkPoint; 30 struct SkStrikeDeviceInfo; 31 32 namespace sktext { 33 class GlyphRunList; 34 class StrikeForGPUCacheInterface; 35 } 36 37 namespace skgpu { 38 enum class MaskFormat : int; 39 } 40 41 #if defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS) 42 #include "src/gpu/ganesh/GrColor.h" 43 #include "src/gpu/ganesh/ops/GrOp.h" 44 45 class GrClip; 46 namespace skgpu::ganesh { 47 class SurfaceDrawContext; 48 } 49 #endif 50 51 namespace sktext::gpu { 52 class GlyphVector; 53 class Glyph; 54 class StrikeCache; 55 class VertexFiller; 56 57 using RegenerateAtlasDelegate = std::function<std::tuple<bool, int>(GlyphVector*, 58 int begin, 59 int end, 60 skgpu::MaskFormat, 61 int padding)>; 62 63 struct RendererData { 64 bool isSDF = false; 65 bool isLCD = false; 66 }; 67 68 // -- AtlasSubRun -------------------------------------------------------------------------------- 69 // AtlasSubRun is the API that AtlasTextOp uses to generate vertex data for drawing. 70 // There are three different ways AtlasSubRun is specialized. 71 // * DirectMaskSubRun* - this is by far the most common type of SubRun. The mask pixels are 72 // in 1:1 correspondence with the pixels on the device. The destination rectangles in this 73 // SubRun are in device space. This SubRun handles color glyphs. 74 // * TransformedMaskSubRun* - handles glyph where the image in the atlas needs to be 75 // transformed to the screen. It is usually used for large color glyph which can't be 76 // drawn with paths or scaled distance fields, but will be used to draw bitmap glyphs to 77 // the screen, if the matrix does not map 1:1 to the screen. The destination rectangles 78 // are in source space. 79 // * SDFTSubRun* - scaled distance field text handles largish single color glyphs that still 80 // can fit in the atlas; the sizes between direct SubRun, and path SubRun. The destination 81 // rectangles are in source space. 82 class AtlasSubRun { 83 public: 84 virtual ~AtlasSubRun() = default; 85 86 virtual SkSpan<const Glyph*> glyphs() const = 0; 87 virtual int glyphCount() const = 0; 88 virtual skgpu::MaskFormat maskFormat() const = 0; 89 virtual int glyphSrcPadding() const = 0; 90 virtual unsigned short instanceFlags() const = 0; 91 92 #if defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS) 93 virtual size_t vertexStride(const SkMatrix& drawMatrix) const = 0; 94 95 virtual std::tuple<const GrClip*, GrOp::Owner> makeAtlasTextOp( 96 const GrClip*, 97 const SkMatrix& viewMatrix, 98 SkPoint drawOrigin, 99 const SkPaint&, 100 sk_sp<SkRefCnt>&& subRunStorage, 101 skgpu::ganesh::SurfaceDrawContext*) const = 0; 102 103 virtual void fillVertexData( 104 void* vertexDst, int offset, int count, 105 GrColor color, 106 const SkMatrix& drawMatrix, 107 SkPoint drawOrigin, 108 SkIRect clip) const = 0; 109 #endif 110 // This call is not thread safe. It should only be called from a known single-threaded env. 111 virtual std::tuple<bool, int> regenerateAtlas( 112 int begin, int end, RegenerateAtlasDelegate) const = 0; 113 114 virtual const VertexFiller& vertexFiller() const = 0; 115 116 virtual void testingOnly_packedGlyphIDToGlyph(StrikeCache* cache) const = 0; 117 }; 118 119 using AtlasDrawDelegate = std::function<void(const sktext::gpu::AtlasSubRun* subRun, 120 SkPoint drawOrigin, 121 const SkPaint& paint, 122 sk_sp<SkRefCnt> subRunStorage, 123 sktext::gpu::RendererData)>; 124 125 // -- SubRun ------------------------------------------------------------------------------------- 126 // SubRun defines the most basic functionality of a SubRun; the ability to draw, and the 127 // ability to be in a list. 128 class SubRun; 129 using SubRunOwner = std::unique_ptr<SubRun, SubRunAllocator::Destroyer>; 130 class SubRun { 131 public: 132 virtual ~SubRun(); 133 134 virtual void draw(SkCanvas*, SkPoint drawOrigin, const SkPaint&, sk_sp<SkRefCnt> subRunStorage, 135 const AtlasDrawDelegate&) const = 0; 136 137 void flatten(SkWriteBuffer& buffer) const; 138 static SubRunOwner MakeFromBuffer(SkReadBuffer& buffer, 139 sktext::gpu::SubRunAllocator* alloc, 140 const SkStrikeClient* client); 141 142 // Size hint for unflattening this run. If this is accurate, it will help with the allocation 143 // of the slug. If it's off then there may be more allocations needed to unflatten. 144 virtual int unflattenSize() const = 0; 145 146 // Given an already cached subRun, can this subRun handle this combination paint, matrix, and 147 // position. 148 virtual bool canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const = 0; 149 150 // Return the underlying atlas SubRun if it exists. Otherwise, return nullptr. 151 // * Don't use this API. It is only to support testing. 152 virtual const AtlasSubRun* testingOnly_atlasSubRun() const = 0; 153 154 protected: 155 enum SubRunStreamTag : int; 156 virtual SubRunStreamTag subRunStreamTag() const = 0; 157 virtual void doFlatten(SkWriteBuffer& buffer) const = 0; 158 159 private: 160 friend class SubRunList; 161 SubRunOwner fNext; 162 }; 163 164 // -- SubRunList ----------------------------------------------------------------------------------- 165 class SubRunList { 166 public: 167 class Iterator { 168 public: 169 using value_type = SubRun; 170 using difference_type = ptrdiff_t; 171 using pointer = value_type*; 172 using reference = value_type&; 173 using iterator_category = std::input_iterator_tag; Iterator(SubRun * subRun)174 Iterator(SubRun* subRun) : fPtr{subRun} { } 175 Iterator& operator++() { fPtr = fPtr->fNext.get(); return *this; } 176 Iterator operator++(int) { Iterator tmp(*this); operator++(); return tmp; } 177 bool operator==(const Iterator& rhs) const { return fPtr == rhs.fPtr; } 178 bool operator!=(const Iterator& rhs) const { return fPtr != rhs.fPtr; } 179 reference operator*() { return *fPtr; } 180 181 private: 182 SubRun* fPtr; 183 }; 184 append(SubRunOwner subRun)185 void append(SubRunOwner subRun) { 186 SubRunOwner* newTail = &subRun->fNext; 187 *fTail = std::move(subRun); 188 fTail = newTail; 189 } isEmpty()190 bool isEmpty() const { return fHead == nullptr; } begin()191 Iterator begin() { return Iterator{ fHead.get()}; } end()192 Iterator end() { return Iterator{nullptr}; } begin()193 Iterator begin() const { return Iterator{ fHead.get()}; } end()194 Iterator end() const { return Iterator{nullptr}; } front()195 SubRun& front() const {return *fHead; } 196 197 private: 198 SubRunOwner fHead{nullptr}; 199 SubRunOwner* fTail{&fHead}; 200 }; 201 202 // -- SubRunContainer ------------------------------------------------------------------------------ 203 class SubRunContainer; 204 using SubRunContainerOwner = std::unique_ptr<SubRunContainer, SubRunAllocator::Destroyer>; 205 class SubRunContainer { 206 public: 207 explicit SubRunContainer(const SkMatrix& initialPositionMatrix); 208 SubRunContainer() = delete; 209 SubRunContainer(const SubRunContainer&) = delete; 210 SubRunContainer& operator=(const SubRunContainer&) = delete; 211 212 // Delete the move operations because the SubRuns contain pointers to fInitialPositionMatrix. 213 SubRunContainer(SubRunContainer&&) = delete; 214 SubRunContainer& operator=(SubRunContainer&&) = delete; 215 216 void flattenAllocSizeHint(SkWriteBuffer& buffer) const; 217 static int AllocSizeHintFromBuffer(SkReadBuffer& buffer); 218 219 void flattenRuns(SkWriteBuffer& buffer) const; 220 static SubRunContainerOwner MakeFromBufferInAlloc(SkReadBuffer& buffer, 221 const SkStrikeClient* client, 222 SubRunAllocator* alloc); 223 224 enum SubRunCreationBehavior {kAddSubRuns, kStrikeCalculationsOnly}; 225 // The returned SubRunContainerOwner will never be null. If subRunCreation == 226 // kStrikeCalculationsOnly, then the returned container will be empty. 227 [[nodiscard]] static SubRunContainerOwner MakeInAlloc(const GlyphRunList& glyphRunList, 228 const SkMatrix& positionMatrix, 229 const SkPaint& runPaint, 230 SkStrikeDeviceInfo strikeDeviceInfo, 231 StrikeForGPUCacheInterface* strikeCache, 232 sktext::gpu::SubRunAllocator* alloc, 233 SubRunCreationBehavior creationBehavior, 234 const char* tag); 235 236 static size_t EstimateAllocSize(const GlyphRunList& glyphRunList); 237 238 void draw(SkCanvas*, SkPoint drawOrigin, const SkPaint&, const SkRefCnt* subRunStorage, 239 const AtlasDrawDelegate&) const; 240 initialPosition()241 const SkMatrix& initialPosition() const { return fInitialPositionMatrix; } isEmpty()242 bool isEmpty() const { return fSubRuns.isEmpty(); } 243 bool canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const; 244 245 private: 246 friend class TextBlobTools; 247 const SkMatrix fInitialPositionMatrix; 248 SubRunList fSubRuns; 249 }; 250 251 // Returns the empty span if there is a problem reading the positions. 252 SkSpan<SkPoint> MakePointsFromBuffer(SkReadBuffer&, SubRunAllocator*); 253 254 } // namespace sktext::gpu 255 256 #endif // sktext_gpu_SubRunContainer_DEFINED 257