• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 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_DrawList_DEFINED
9 #define skgpu_graphite_DrawList_DEFINED
10 
11 #include "include/core/SkPaint.h"
12 #include "src/base/SkTBlockList.h"
13 
14 #include "src/gpu/graphite/DrawOrder.h"
15 #include "src/gpu/graphite/DrawParams.h"
16 #include "src/gpu/graphite/PaintParams.h"
17 #include "src/gpu/graphite/geom/Geometry.h"
18 #include "src/gpu/graphite/geom/Rect.h"
19 #include "src/gpu/graphite/geom/Transform.h"
20 
21 #include <limits>
22 #include <optional>
23 
24 namespace skgpu::graphite {
25 
26 class Renderer;
27 
28 /**
29  * A DrawList represents a collection of drawing commands (and related clip/shading state) in
30  * a form that closely mirrors what can be rendered efficiently and directly by the GPU backend
31  * (while balancing how much pre-processing to do for draws that might get eliminated later due to
32  * occlusion culling).
33  *
34  * A draw command combines:
35  *   - a shape
36  *   - a transform
37  *   - a primitive clip (not affected by the transform)
38  *   - optional shading description (shader, color filter, blend mode, etc)
39  *   - a draw ordering (compressed painters index, stencil set, and write/test depth)
40  *
41  * Commands are accumulated in an arbitrary order and then sorted by increasing sort z when the list
42  * is prepared into an actual command buffer. The result of a draw command is the rasterization of
43  * the transformed shape, restricted by its primitive clip (e.g. a scissor rect) and a depth test
44  * of "GREATER" vs. its write/test z. (A test of GREATER, as opposed to GEQUAL, avoids double hits
45  * for draws that may have overlapping geometry, e.g. stroking.) If the command has a shading
46  * description, the color buffer will be modified; if not, it will be a depth-only draw.
47  *
48  * In addition to sorting the collected commands, the command list can be optimized during
49  * preparation. Commands that are fully occluded by later operations can be skipped entirely without
50  * affecting the final results. Adjacent commands (post sort) that would use equivalent GPU
51  * pipelines are merged to produce fewer (but larger) operations on the GPU.
52  *
53  * Other than flush-time optimizations (sort, cull, and merge), the command list does what you tell
54  * it to. Draw-specific simplification, style application, and advanced clipping should be handled
55  * at a higher layer.
56  */
57 class DrawList {
58 public:
59     // The maximum number of render steps that can be recorded into a DrawList before it must be
60     // converted to a DrawPass. The true fundamental limit is imposed by the limits of the depth
61     // attachment and precision of CompressedPaintersOrder and PaintDepth. These values can be
62     // shared by multiple draw calls so it's more difficult to reason about how much room is left
63     // in a DrawList. Limiting it to this keeps tracking simple and ensures that the sequences in
64     // DrawOrder cannot overflow since they are always less than or equal to the number of draws.
65     // TODO(b/322840221): The theoretic max for this value is 16-bit, but we see markedly better
66     // performance with smaller values. This should be understood and fixed directly rather than as
67     // a magic side-effect, but for now, let it go fast.
68     static constexpr int kMaxRenderSteps = 4096;
69     static_assert(kMaxRenderSteps <= std::numeric_limits<uint16_t>::max());
70 
71     // Add a construtor to prevent default zero initialization of SkTBlockList members' storage.
DrawList()72     DrawList() {}
73 
74     // DrawList requires that all Transforms be valid and asserts as much; invalid transforms should
75     // be detected at the Device level or similar. The provided Renderer must be compatible with the
76     // 'shape' and 'stroke' parameters. If the renderer uses coverage AA, 'ordering' must have a
77     // compressed painters order that reflects that. If the renderer uses stencil, the 'ordering'
78     // must have a valid stencil index as well.
79     void recordDraw(const Renderer* renderer,
80                     const Transform& localToDevice,
81                     const Geometry& geometry,
82                     const Clip& clip,
83                     DrawOrder ordering,
84                     const PaintParams* paint,
85                     const StrokeStyle* stroke);
86 
renderStepCount()87     int renderStepCount() const { return fRenderStepCount; }
88 
89     // Bounds for a dst read required by this DrawList.
dstReadBounds()90     const Rect& dstReadBounds() const { return fDstReadBounds; }
91 
92     SkDEBUGCODE(bool hasCoverageMaskDraws() const { return fCoverageMaskShapeDrawCount > 0; })
93 
94 private:
95     friend class DrawPass;
96 
97     struct Draw {
98         const Renderer* fRenderer; // Owned by SharedContext of Recorder that recorded the draw
99         DrawParams fDrawParams; // The DrawParam's transform is owned by fTransforms of the DrawList
100         std::optional<PaintParams> fPaintParams; // Not present implies depth-only draw
101 
DrawDraw102         Draw(const Renderer* renderer, const Transform& transform, const Geometry& geometry,
103              const Clip& clip, DrawOrder order, const PaintParams* paint,
104              const StrokeStyle* stroke)
105                 : fRenderer(renderer)
106                 , fDrawParams(transform, geometry, clip, order, stroke)
107                 , fPaintParams(paint ? std::optional<PaintParams>(*paint) : std::nullopt) {}
108 
readsFromDstDraw109         bool readsFromDst() const {
110             return fPaintParams.has_value() ? fPaintParams.value().dstReadRequired() : false;
111         }
112     };
113 
114     // The returned Transform reference remains valid for the lifetime of the DrawList.
115     const Transform& deduplicateTransform(const Transform&);
116 
117     SkTBlockList<Transform, 16> fTransforms{SkBlockAllocator::GrowthPolicy::kFibonacci};
118     SkTBlockList<Draw, 16>      fDraws{SkBlockAllocator::GrowthPolicy::kFibonacci};
119 
120     // Running total of RenderSteps for all draws, assuming nothing is culled
121     int fRenderStepCount = 0;
122 
123 #if defined(SK_DEBUG)
124     // The number of CoverageMask draws that have been recorded. Used in debugging.
125     int fCoverageMaskShapeDrawCount = 0;
126 #endif
127 
128     // Tracked for all paints that read from the dst. If it is later determined that the
129     // DstReadStrategy is not kTextureCopy, this value can simply be ignored.
130     Rect fDstReadBounds = Rect::InfiniteInverted();
131 };
132 
133 } // namespace skgpu::graphite
134 
135 #endif // skgpu_graphite_DrawList_DEFINED
136