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_DrawPass_DEFINED 9 #define skgpu_DrawPass_DEFINED 10 11 #include "experimental/graphite/src/DrawTypes.h" 12 #include "experimental/graphite/src/GraphicsPipelineDesc.h" 13 #include "experimental/graphite/src/ResourceTypes.h" 14 #include "include/core/SkColor.h" 15 #include "include/core/SkRect.h" 16 #include "include/core/SkRefCnt.h" 17 #include "src/core/SkTBlockList.h" 18 19 #include <memory> 20 21 namespace skgpu { 22 23 class BoundsManager; 24 class CommandBuffer; 25 class DrawList; 26 class Recorder; 27 struct RenderPassDesc; 28 class ResourceProvider; 29 class TextureProxy; 30 enum class UniformSlot; 31 32 /** 33 * DrawPass is analogous to a subpass, storing the drawing operations in the order they are stored 34 * in the eventual command buffer, as well as the surface proxy the operations are intended for. 35 * DrawPasses are grouped into a RenderPassTask for execution within a single render pass if the 36 * subpasses are compatible with each other. 37 * 38 * Unlike DrawList, DrawPasses are immutable and represent as closely as possible what will be 39 * stored in the command buffer while being flexible as to how the pass is incorporated. Depending 40 * on the backend, it may even be able to write accumulated vertex and uniform data directly to 41 * mapped GPU memory, although that is the extent of the CPU->GPU work they perform before they are 42 * executed by a RenderPassTask. 43 */ 44 class DrawPass { 45 public: 46 ~DrawPass(); 47 48 // TODO: Replace SDC with the SDC's surface proxy view 49 static std::unique_ptr<DrawPass> Make(Recorder*, 50 std::unique_ptr<DrawList>, 51 sk_sp<TextureProxy>, 52 std::pair<LoadOp, StoreOp>, 53 std::array<float, 4> clearColor, 54 const BoundsManager* occlusionCuller); 55 56 // Defined relative to the top-left corner of the surface the DrawPass renders to, and is 57 // contained within its dimensions. bounds()58 const SkIRect& bounds() const { return fBounds; } target()59 TextureProxy* target() const { return fTarget.get(); } ops()60 std::pair<LoadOp, StoreOp> ops() const { return fOps; } clearColor()61 std::array<float, 4> clearColor() const { return fClearColor; } 62 requiresDstTexture()63 bool requiresDstTexture() const { return false; } requiresMSAA()64 bool requiresMSAA() const { return fRequiresMSAA; } 65 depthStencilFlags()66 Mask<DepthStencilFlags> depthStencilFlags() const { return fDepthStencilFlags; } 67 vertexBufferSize()68 size_t vertexBufferSize() const { return 0; } uniformBufferSize()69 size_t uniformBufferSize() const { return 0; } 70 71 // TODO: Real return types, but it seems useful for DrawPass to report these as sets so that 72 // task execution can compile necessary programs and track resources within a render pass. 73 // Maybe these won't need to be exposed and RenderPassTask can do it per command as needed when 74 // it iterates over the DrawPass contents. samplers()75 void samplers() const {} programs()76 void programs() const {} 77 78 // Transform this DrawPass into commands issued to the CommandBuffer. Assumes that the buffer 79 // has already begun a correctly configured render pass matching this pass's target. 80 void addCommands(ResourceProvider*, CommandBuffer*, const RenderPassDesc&) const; 81 82 private: 83 class SortKey; 84 class Drawer; 85 86 struct BindGraphicsPipeline { 87 // Points to a GraphicsPipelineDesc in DrawPass's fPipelineDescs array. It will also 88 // index into a parallel array of full GraphicsPipelines when commands are added to the CB. 89 uint32_t fPipelineIndex; 90 }; 91 struct BindUniformBuffer { 92 BindBufferInfo fInfo; 93 UniformSlot fSlot; 94 }; 95 struct BindDrawBuffers { 96 BindBufferInfo fVertices; 97 BindBufferInfo fInstances; 98 BindBufferInfo fIndices; 99 }; 100 struct Draw { 101 PrimitiveType fType; 102 uint32_t fBaseVertex; 103 uint32_t fVertexCount; 104 }; 105 struct DrawIndexed { 106 PrimitiveType fType; 107 uint32_t fBaseIndex; 108 uint32_t fIndexCount; 109 uint32_t fBaseVertex; 110 }; 111 struct DrawInstanced { 112 PrimitiveType fType; 113 uint32_t fBaseVertex; 114 uint32_t fVertexCount; 115 uint32_t fBaseInstance; 116 uint32_t fInstanceCount; 117 }; 118 struct DrawIndexedInstanced { 119 PrimitiveType fType; 120 uint32_t fBaseIndex; 121 uint32_t fIndexCount; 122 uint32_t fBaseVertex; 123 uint32_t fBaseInstance; 124 uint32_t fInstanceCount; 125 }; 126 struct SetScissor { 127 SkIRect fScissor; 128 }; 129 130 // TODO: BindSampler 131 132 enum class CommandType { 133 kBindGraphicsPipeline, 134 kBindUniformBuffer, 135 kBindDrawBuffers, 136 kDraw, 137 kDrawIndexed, 138 kDrawInstanced, 139 kDrawIndexedInstanced, 140 kSetScissor, 141 // kBindSampler 142 }; 143 // TODO: The goal is keep all command data in line, vs. type + void* to another data array, but 144 // the current union is memory inefficient. It would be better to have a byte buffer with per 145 // type advances, but then we need to work out alignment etc. so that will be easier to add 146 // once we have something up and running. 147 struct Command { 148 CommandType fType; 149 union { 150 BindGraphicsPipeline fBindGraphicsPipeline; 151 BindUniformBuffer fBindUniformBuffer; 152 BindDrawBuffers fBindDrawBuffers; 153 Draw fDraw; 154 DrawIndexed fDrawIndexed; 155 DrawInstanced fDrawInstanced; 156 DrawIndexedInstanced fDrawIndexedInstanced; 157 SetScissor fSetScissor; 158 }; 159 CommandCommand160 explicit Command(BindGraphicsPipeline d) 161 : fType(CommandType::kBindGraphicsPipeline), fBindGraphicsPipeline(d) {} CommandCommand162 explicit Command(BindUniformBuffer d) 163 : fType(CommandType::kBindUniformBuffer), fBindUniformBuffer(d) {} CommandCommand164 explicit Command(BindDrawBuffers d) 165 : fType(CommandType::kBindDrawBuffers), fBindDrawBuffers(d) {} CommandCommand166 explicit Command(Draw d) 167 : fType(CommandType::kDraw), fDraw(d) {} CommandCommand168 explicit Command(DrawIndexed d) 169 : fType(CommandType::kDrawIndexed), fDrawIndexed(d) {} CommandCommand170 explicit Command(DrawInstanced d) 171 : fType(CommandType::kDrawInstanced), fDrawInstanced(d) {} CommandCommand172 explicit Command(DrawIndexedInstanced d) 173 : fType(CommandType::kDrawIndexedInstanced), fDrawIndexedInstanced(d) {} CommandCommand174 explicit Command(SetScissor d) 175 : fType(CommandType::kSetScissor), fSetScissor(d) {} 176 }; 177 // Not strictly necessary, but keeping Command trivially destructible means the command list 178 // can be cleaned up efficiently once it's converted to a command buffer. 179 static_assert(std::is_trivially_destructible<Command>::value); 180 181 DrawPass(sk_sp<TextureProxy> target, 182 std::pair<LoadOp, StoreOp> ops, 183 std::array<float, 4> clearColor, 184 int renderStepCount); 185 186 SkTBlockList<Command, 32> fCommands; 187 // The pipelines are referenced by index in BindGraphicsPipeline, but that will index into a 188 // an array of actual GraphicsPipelines. fPipelineDescs only needs to accumulate encountered 189 // GraphicsPipelineDescs and provide stable pointers, hence SkTBlockList. 190 SkTBlockList<GraphicsPipelineDesc, 32> fPipelineDescs; 191 192 sk_sp<TextureProxy> fTarget; 193 SkIRect fBounds; 194 195 std::pair<LoadOp, StoreOp> fOps; 196 std::array<float, 4> fClearColor; 197 198 Mask<DepthStencilFlags> fDepthStencilFlags = DepthStencilFlags::kNone; 199 bool fRequiresMSAA = false; 200 }; 201 202 } // namespace skgpu 203 204 #endif // skgpu_DrawPass_DEFINED 205