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