/* * Copyright 2022 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef sktext_gpu_SubRunContainer_DEFINED #define sktext_gpu_SubRunContainer_DEFINED #include "include/core/SkMatrix.h" #include "include/core/SkRefCnt.h" #include "include/core/SkSpan.h" #include "src/text/gpu/SubRunAllocator.h" #include #include #include #include #include #include class SkCanvas; class SkPaint; class SkReadBuffer; class SkStrikeClient; class SkWriteBuffer; struct SkPoint; struct SkStrikeDeviceInfo; namespace sktext { class GlyphRunList; class StrikeForGPUCacheInterface; } namespace skgpu { enum class MaskFormat : int; } #if defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS) #include "src/gpu/ganesh/GrColor.h" #include "src/gpu/ganesh/ops/GrOp.h" class GrClip; struct SkIRect; namespace skgpu::ganesh { class SurfaceDrawContext; } #endif namespace sktext::gpu { class GlyphVector; class Glyph; class StrikeCache; class VertexFiller; using RegenerateAtlasDelegate = std::function(GlyphVector*, int begin, int end, skgpu::MaskFormat, int padding)>; struct RendererData { bool isSDF = false; bool isLCD = false; skgpu::MaskFormat maskFormat; }; // -- AtlasSubRun -------------------------------------------------------------------------------- // AtlasSubRun is the API that AtlasTextOp uses to generate vertex data for drawing. // There are three different ways AtlasSubRun is specialized. // * DirectMaskSubRun* - this is by far the most common type of SubRun. The mask pixels are // in 1:1 correspondence with the pixels on the device. The destination rectangles in this // SubRun are in device space. This SubRun handles color glyphs. // * TransformedMaskSubRun* - handles glyph where the image in the atlas needs to be // transformed to the screen. It is usually used for large color glyph which can't be // drawn with paths or scaled distance fields, but will be used to draw bitmap glyphs to // the screen, if the matrix does not map 1:1 to the screen. The destination rectangles // are in source space. // * SDFTSubRun* - scaled distance field text handles largish single color glyphs that still // can fit in the atlas; the sizes between direct SubRun, and path SubRun. The destination // rectangles are in source space. class AtlasSubRun { public: virtual ~AtlasSubRun() = default; virtual SkSpan glyphs() const = 0; virtual int glyphCount() const = 0; virtual skgpu::MaskFormat maskFormat() const = 0; virtual int glyphSrcPadding() const = 0; virtual unsigned short instanceFlags() const = 0; #if defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS) virtual size_t vertexStride(const SkMatrix& drawMatrix) const = 0; virtual std::tuple makeAtlasTextOp( const GrClip*, const SkMatrix& viewMatrix, SkPoint drawOrigin, const SkPaint&, sk_sp&& subRunStorage, skgpu::ganesh::SurfaceDrawContext*) const = 0; virtual void fillVertexData( void* vertexDst, int offset, int count, GrColor color, const SkMatrix& drawMatrix, SkPoint drawOrigin, SkIRect clip) const = 0; #endif // This call is not thread safe. It should only be called from a known single-threaded env. virtual std::tuple regenerateAtlas( int begin, int end, RegenerateAtlasDelegate) const = 0; virtual const VertexFiller& vertexFiller() const = 0; virtual void testingOnly_packedGlyphIDToGlyph(StrikeCache* cache) const = 0; }; using AtlasDrawDelegate = std::function subRunStorage, sktext::gpu::RendererData)>; // -- SubRun ------------------------------------------------------------------------------------- // SubRun defines the most basic functionality of a SubRun; the ability to draw, and the // ability to be in a list. class SubRun; using SubRunOwner = std::unique_ptr; class SubRun { public: virtual ~SubRun(); virtual void draw(SkCanvas*, SkPoint drawOrigin, const SkPaint&, sk_sp subRunStorage, const AtlasDrawDelegate&) const = 0; void flatten(SkWriteBuffer& buffer) const; static SubRunOwner MakeFromBuffer(SkReadBuffer& buffer, sktext::gpu::SubRunAllocator* alloc, const SkStrikeClient* client); // Size hint for unflattening this run. If this is accurate, it will help with the allocation // of the slug. If it's off then there may be more allocations needed to unflatten. virtual int unflattenSize() const = 0; // Given an already cached subRun, can this subRun handle this combination paint, matrix, and // position. virtual bool canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const = 0; // Return the underlying atlas SubRun if it exists. Otherwise, return nullptr. // * Don't use this API. It is only to support testing. virtual const AtlasSubRun* testingOnly_atlasSubRun() const = 0; protected: enum SubRunStreamTag : int; virtual SubRunStreamTag subRunStreamTag() const = 0; virtual void doFlatten(SkWriteBuffer& buffer) const = 0; private: friend class SubRunList; SubRunOwner fNext; }; // -- SubRunList ----------------------------------------------------------------------------------- class SubRunList { public: class Iterator { public: using value_type = SubRun; using difference_type = ptrdiff_t; using pointer = value_type*; using reference = value_type&; using iterator_category = std::input_iterator_tag; Iterator(SubRun* subRun) : fPtr{subRun} { } Iterator& operator++() { fPtr = fPtr->fNext.get(); return *this; } Iterator operator++(int) { Iterator tmp(*this); operator++(); return tmp; } bool operator==(const Iterator& rhs) const { return fPtr == rhs.fPtr; } bool operator!=(const Iterator& rhs) const { return fPtr != rhs.fPtr; } reference operator*() { return *fPtr; } private: SubRun* fPtr; }; void append(SubRunOwner subRun) { SubRunOwner* newTail = &subRun->fNext; *fTail = std::move(subRun); fTail = newTail; } bool isEmpty() const { return fHead == nullptr; } Iterator begin() { return Iterator{ fHead.get()}; } Iterator end() { return Iterator{nullptr}; } Iterator begin() const { return Iterator{ fHead.get()}; } Iterator end() const { return Iterator{nullptr}; } SubRun& front() const {return *fHead; } private: SubRunOwner fHead{nullptr}; SubRunOwner* fTail{&fHead}; }; // -- SubRunContainer ------------------------------------------------------------------------------ class SubRunContainer; using SubRunContainerOwner = std::unique_ptr; class SubRunContainer { public: explicit SubRunContainer(const SkMatrix& initialPositionMatrix); SubRunContainer() = delete; SubRunContainer(const SubRunContainer&) = delete; SubRunContainer& operator=(const SubRunContainer&) = delete; // Delete the move operations because the SubRuns contain pointers to fInitialPositionMatrix. SubRunContainer(SubRunContainer&&) = delete; SubRunContainer& operator=(SubRunContainer&&) = delete; void flattenAllocSizeHint(SkWriteBuffer& buffer) const; static int AllocSizeHintFromBuffer(SkReadBuffer& buffer); void flattenRuns(SkWriteBuffer& buffer) const; static SubRunContainerOwner MakeFromBufferInAlloc(SkReadBuffer& buffer, const SkStrikeClient* client, SubRunAllocator* alloc); enum SubRunCreationBehavior {kAddSubRuns, kStrikeCalculationsOnly}; // The returned SubRunContainerOwner will never be null. If subRunCreation == // kStrikeCalculationsOnly, then the returned container will be empty. [[nodiscard]] static SubRunContainerOwner MakeInAlloc(const GlyphRunList& glyphRunList, const SkMatrix& positionMatrix, const SkPaint& runPaint, SkStrikeDeviceInfo strikeDeviceInfo, StrikeForGPUCacheInterface* strikeCache, sktext::gpu::SubRunAllocator* alloc, SubRunCreationBehavior creationBehavior, const char* tag); static size_t EstimateAllocSize(const GlyphRunList& glyphRunList); void draw(SkCanvas*, SkPoint drawOrigin, const SkPaint&, const SkRefCnt* subRunStorage, const AtlasDrawDelegate&) const; const SkMatrix& initialPosition() const { return fInitialPositionMatrix; } bool isEmpty() const { return fSubRuns.isEmpty(); } bool canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const; private: friend class TextBlobTools; const SkMatrix fInitialPositionMatrix; SubRunList fSubRuns; }; // Returns the empty span if there is a problem reading the positions. SkSpan MakePointsFromBuffer(SkReadBuffer&, SubRunAllocator*); } // namespace sktext::gpu #endif // sktext_gpu_SubRunContainer_DEFINED