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