Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
PathAtlas.h
Go to the documentation of this file.
1/*
2 * Copyright 2023 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 skgpu_graphite_PathAtlas_DEFINED
9#define skgpu_graphite_PathAtlas_DEFINED
10
13#include "src/core/SkTHash.h"
14#include "src/gpu/AtlasTypes.h"
15#include "src/gpu/ResourceKey.h"
18
19namespace skgpu::graphite {
20
21class Caps;
22class DrawContext;
23class Recorder;
24class Rect;
25class Renderer;
26class Shape;
27class TextureProxy;
28class Transform;
29
30/**
31 * PathAtlas manages one or more atlas textures that store coverage masks for path rendering.
32 *
33 * The contents of a PathAtlas are intended to be transient: atlas regions are considered valid only
34 * for the scope of the render passes that sample them. Unlike DrawAtlas, PathAtlas does not
35 * necessarily support partial eviction and reuse of subregions. In most subclasses, once an atlas
36 * texture is filled up all of its sub-allocations must be invalidated before it can be reused.
37 *
38 * PathAtlas does not prescribe how atlas contents get uploaded to the GPU. The specific task
39 * mechanism is defined by subclasses.
40 */
41class PathAtlas {
42public:
43 /**
44 * The PathAtlas will use textures of the requested size or the system's maximum texture size,
45 * whichever is smaller.
46 */
47 PathAtlas(Recorder* recorder, uint32_t requestedWidth, uint32_t requestedHeight);
48 virtual ~PathAtlas();
49
50 using MaskAndOrigin = std::pair<CoverageMaskShape, SkIPoint>;
51
52 /**
53 * Searches the atlas for a slot that can fit a coverage mask for a clipped shape with the given
54 * bounds in device coordinates and submits the mask to be drawn into the found atlas region.
55 * For atlases that cache coverage masks, will first search the cache before adding.
56 *
57 * Returns an empty result if a the shape cannot fit in the atlas. Otherwise, returns the
58 * CoverageMaskShape (including the texture proxy) for sampling the eventually-rendered coverage
59 * mask and the device-space origin the mask should be drawn at (e.g. its recorded draw should
60 * be an integer translation matrix), and the Renderer that should be used to draw that shape.
61 * The Renderer should have single-channel coverage, require AA bounds outsetting, and have a
62 * single renderStep.
63 *
64 * The bounds of the atlas entry is laid out with a 1 pixel outset from the given dimensions.
65 * The returned shape's UV origin accounts for the padding, and its mask size does not include
66 * the padding. This allows the mask to be sampled safely with linear filtering without worrying
67 * about HW filtering accessing pixels from other entries.
68 *
69 * `shape` will be drawn after applying the linear components (scale, rotation, skew) of the
70 * provided `localToDevice` transform. This is done by translating the shape by the inverse of
71 * the rounded out `transformedShapeBounds` offset. For an unclipped shape this amounts to
72 * translating it back to its origin while preserving any sub-pixel translation. For a clipped
73 * shape, this ensures that the visible portions of the mask are centered in the atlas slot
74 * while invisible portions that would lie outside the atlas slot get clipped out.
75 *
76 * `addShape()` schedules the shape to be drawn but when and how the rendering happens is
77 * specified by the subclass implementation.
78 *
79 * The stroke-and-fill style is drawn as a single combined coverage mask containing the stroke
80 * and the fill.
81 */
82 std::pair<const Renderer*, std::optional<MaskAndOrigin>> addShape(
83 const Rect& transformedShapeBounds,
84 const Shape& shape,
85 const Transform& localToDevice,
86 const SkStrokeRec& style);
87
88 /**
89 * Returns true if a path coverage mask with the given device-space bounds is sufficiently
90 * small to benefit from atlasing without causing too many atlas renders.
91 */
92 virtual bool isSuitableForAtlasing(const Rect& transformedShapeBounds) const { return true; }
93
94 uint32_t width() const { return fWidth; }
95 uint32_t height() const { return fHeight; }
96
97protected:
98 // Subclasses should ensure that the recorded masks have this much padding around each entry.
99 // PathAtlas passes in un-padded sizes to onAddShape and assumes that padding has been included
100 // in the outPos value.
101 static constexpr int kEntryPadding = 1;
102
103 // The 'transform' has been adjusted to draw the Shape into a logical image from (0,0) to
104 // 'maskSize'. The actual rendering into the returned TextureProxy will need to be further
105 // translated by the value written to 'outPos', which is the responsibility of subclasses.
106 virtual const TextureProxy* onAddShape(const Shape&,
107 const Transform& transform,
108 const SkStrokeRec&,
109 skvx::half2 maskSize,
110 skvx::half2* outPos) = 0;
111
112 // Wrapper class to manage DrawAtlas and associated caching operations
114 public:
115 const TextureProxy* findOrCreateEntry(Recorder* recorder,
116 const Shape& shape,
117 const Transform& transform,
118 const SkStrokeRec& strokeRec,
119 skvx::half2 maskSize,
120 skvx::half2* outPos);
121 // Adds to DrawAtlas but not the cache
122 const TextureProxy* addToAtlas(Recorder* recorder,
123 const Shape& shape,
124 const Transform& transform,
125 const SkStrokeRec& strokeRec,
126 skvx::half2 maskSize,
127 skvx::half2* outPos,
128 AtlasLocator* locator);
130 void evict(PlotLocator) override;
131 void postFlush(Recorder*);
132
133 protected:
134 DrawAtlasMgr(size_t width, size_t height,
135 size_t plotWidth, size_t plotHeight,
136 std::string_view label, const Caps*);
137
138 bool virtual onAddToAtlas(const Shape&,
139 const Transform& transform,
140 const SkStrokeRec&,
141 SkIRect shapeBounds,
142 const AtlasLocator&) = 0;
143
144 std::unique_ptr<DrawAtlas> fDrawAtlas;
145
146 private:
147 // Tracks whether a shape is already in the DrawAtlas, and its location in the atlas
148 struct UniqueKeyHash {
149 uint32_t operator()(const skgpu::UniqueKey& key) const { return key.hash(); }
150 };
152 ShapeCache fShapeCache;
153
154 // List of stored keys per Plot, used to invalidate cache entries.
155 // When a Plot is invalidated via evict(), we'll get its index and Page index from the
156 // PlotLocator, index into the fKeyLists array to get the ShapeKeyList for that Plot,
157 // then iterate through the list and remove entries matching those keys from the ShapeCache.
158 struct ShapeKeyEntry {
159 skgpu::UniqueKey fKey;
161 };
162 using ShapeKeyList = SkTInternalLList<ShapeKeyEntry>;
163 SkTDArray<ShapeKeyList> fKeyLists;
164 };
165
166 // The Recorder that created and owns this Atlas.
168
169 uint32_t fWidth = 0;
170 uint32_t fHeight = 0;
171};
172
173} // namespace skgpu::graphite
174
175#endif // skgpu_graphite_PathAtlas_DEFINED
#define SK_DECLARE_INTERNAL_LLIST_INTERFACE(ClassName)
Shape
bool recordUploads(DrawContext *, Recorder *)
void evict(PlotLocator) override
const TextureProxy * addToAtlas(Recorder *recorder, const Shape &shape, const Transform &transform, const SkStrokeRec &strokeRec, skvx::half2 maskSize, skvx::half2 *outPos, AtlasLocator *locator)
virtual bool onAddToAtlas(const Shape &, const Transform &transform, const SkStrokeRec &, SkIRect shapeBounds, const AtlasLocator &)=0
std::unique_ptr< DrawAtlas > fDrawAtlas
Definition PathAtlas.h:144
const TextureProxy * findOrCreateEntry(Recorder *recorder, const Shape &shape, const Transform &transform, const SkStrokeRec &strokeRec, skvx::half2 maskSize, skvx::half2 *outPos)
virtual const TextureProxy * onAddShape(const Shape &, const Transform &transform, const SkStrokeRec &, skvx::half2 maskSize, skvx::half2 *outPos)=0
std::pair< CoverageMaskShape, SkIPoint > MaskAndOrigin
Definition PathAtlas.h:50
uint32_t height() const
Definition PathAtlas.h:95
static constexpr int kEntryPadding
Definition PathAtlas.h:101
std::pair< const Renderer *, std::optional< MaskAndOrigin > > addShape(const Rect &transformedShapeBounds, const Shape &shape, const Transform &localToDevice, const SkStrokeRec &style)
Definition PathAtlas.cpp:38
virtual bool isSuitableForAtlasing(const Rect &transformedShapeBounds) const
Definition PathAtlas.h:92
uint32_t width() const
Definition PathAtlas.h:94
TRect< Scalar > Rect
Definition rect.h:746
skgpu::graphite::Transform Transform
static SkColor4f transform(SkColor4f c, SkColorSpace *src, SkColorSpace *dst)
Definition p3.cpp:47