1 /* 2 * Copyright 2022 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_DrawPassCommands_DEFINED 9 #define skgpu_graphite_DrawPassCommands_DEFINED 10 11 #include "include/core/SkRect.h" 12 #include "src/base/SkArenaAlloc.h" 13 #include "src/base/SkTBlockList.h" 14 #include "src/gpu/graphite/DrawTypes.h" 15 16 namespace skgpu::graphite { 17 18 namespace DrawPassCommands { 19 20 // A list of all the commands types used by a DrawPass. 21 // Each of these is reified into a struct below. 22 // 23 // The design of this systems is based on SkRecords. 24 25 // (We're using the macro-of-macro trick here to do several different things with the same list.) 26 // 27 // We leave this SKGPU_DRAW_COMMAND_TYPES macro defined for use by code that wants to operate on 28 // DrawPassCommands types polymorphically. 29 #define SKGPU_DRAW_PASS_COMMAND_TYPES(M) \ 30 M(BindGraphicsPipeline) \ 31 M(SetBlendConstants) \ 32 M(BindUniformBuffer) \ 33 M(BindDrawBuffers) \ 34 M(BindTexturesAndSamplers) \ 35 M(SetScissor) \ 36 M(Draw) \ 37 M(DrawIndexed) \ 38 M(DrawInstanced) \ 39 M(DrawIndexedInstanced) \ 40 M(DrawIndirect) \ 41 M(DrawIndexedIndirect) 42 43 // Defines DrawPassCommands::Type, an enum of all draw command types. 44 #define ENUM(T) k##T, 45 enum class Type { SKGPU_DRAW_PASS_COMMAND_TYPES(ENUM) }; 46 #undef ENUM 47 48 #define ACT_AS_PTR(ptr) \ 49 operator T*() const { return ptr; } \ 50 T* operator->() const { return ptr; } 51 52 // PODArray doesn't own the pointer's memory, and we assume the data is POD. 53 template <typename T> 54 class PODArray { 55 public: PODArray()56 PODArray() {} PODArray(T * ptr)57 PODArray(T* ptr) : fPtr(ptr) {} 58 // Default copy and assign. 59 60 ACT_AS_PTR(fPtr) 61 private: 62 T* fPtr; 63 }; 64 65 #undef ACT_AS_PTR 66 67 // A macro to make it a little easier to define a struct that can be stored in DrawPass. 68 #define COMMAND(T, ...) \ 69 struct T { \ 70 static constexpr Type kType = Type::k##T; \ 71 __VA_ARGS__; \ 72 }; 73 74 COMMAND(BindGraphicsPipeline, 75 uint32_t fPipelineIndex); 76 COMMAND(SetBlendConstants, 77 PODArray<float> fBlendConstants); 78 COMMAND(BindUniformBuffer, 79 BindUniformBufferInfo fInfo; 80 UniformSlot fSlot); 81 COMMAND(BindDrawBuffers, 82 BindBufferInfo fVertices; 83 BindBufferInfo fInstances; 84 BindBufferInfo fIndices; 85 BindBufferInfo fIndirect); 86 COMMAND(BindTexturesAndSamplers, 87 int fNumTexSamplers; 88 PODArray<int> fTextureIndices; 89 PODArray<int> fSamplerIndices); 90 COMMAND(SetScissor, 91 SkIRect fScissor); 92 COMMAND(Draw, 93 PrimitiveType fType; 94 uint32_t fBaseVertex; 95 uint32_t fVertexCount); 96 COMMAND(DrawIndexed, 97 PrimitiveType fType; 98 uint32_t fBaseIndex; 99 uint32_t fIndexCount; 100 uint32_t fBaseVertex); 101 COMMAND(DrawInstanced, 102 PrimitiveType fType; 103 uint32_t fBaseVertex; 104 uint32_t fVertexCount; 105 uint32_t fBaseInstance; 106 uint32_t fInstanceCount); 107 COMMAND(DrawIndexedInstanced, 108 PrimitiveType fType; 109 uint32_t fBaseIndex; 110 uint32_t fIndexCount; 111 uint32_t fBaseVertex; 112 uint32_t fBaseInstance; 113 uint32_t fInstanceCount); 114 COMMAND(DrawIndirect, 115 PrimitiveType fType); 116 COMMAND(DrawIndexedIndirect, 117 PrimitiveType fType); 118 119 #undef COMMAND 120 121 #define ASSERT_TRIV_DES(T) static_assert(std::is_trivially_destructible<T>::value); 122 SKGPU_DRAW_PASS_COMMAND_TYPES(ASSERT_TRIV_DES) 123 #undef ASSERT_TRIV_DES 124 #define ASSERT_TRIV_CPY(T) static_assert(std::is_trivially_copyable<T>::value); 125 SKGPU_DRAW_PASS_COMMAND_TYPES(ASSERT_TRIV_CPY) 126 #undef ASSERT_TRIV_CPY 127 128 class List { 129 public: 130 List() = default; 131 ~List() = default; 132 133 int count() const { return fCommands.count(); } 134 135 void bindGraphicsPipeline(uint32_t pipelineIndex) { 136 this->add<BindGraphicsPipeline>(pipelineIndex); 137 } 138 139 void setBlendConstants(std::array<float, 4> blendConstants) { 140 this->add<SetBlendConstants>(this->copy(blendConstants.data(), 4)); 141 } 142 143 void bindUniformBuffer(BindUniformBufferInfo info, UniformSlot slot) { 144 this->add<BindUniformBuffer>(info, slot); 145 } 146 147 // Caller must write 'numTexSamplers' texture and sampler indices into the two returned arrays. 148 std::pair<int*, int*> 149 bindDeferredTexturesAndSamplers(int numTexSamplers) { 150 int* textureIndices = fAlloc.makeArrayDefault<int>(numTexSamplers); 151 int* samplerIndices = fAlloc.makeArrayDefault<int>(numTexSamplers); 152 this->add<BindTexturesAndSamplers>(numTexSamplers, textureIndices, samplerIndices); 153 return {textureIndices, samplerIndices}; 154 } 155 156 void setScissor(SkIRect scissor) { 157 this->add<SetScissor>(scissor); 158 } 159 160 void bindDrawBuffers(BindBufferInfo vertexAttribs, 161 BindBufferInfo instanceAttribs, 162 BindBufferInfo indices, 163 BindBufferInfo indirect) { 164 this->add<BindDrawBuffers>(vertexAttribs, instanceAttribs, indices, indirect); 165 } 166 167 void draw(PrimitiveType type, unsigned int baseVertex, unsigned int vertexCount) { 168 this->add<Draw>(type, baseVertex, vertexCount); 169 } 170 171 void drawIndexed(PrimitiveType type, unsigned int baseIndex, 172 unsigned int indexCount, unsigned int baseVertex) { 173 this->add<DrawIndexed>(type, baseIndex, indexCount, baseVertex); 174 } 175 176 void drawInstanced(PrimitiveType type, 177 unsigned int baseVertex, unsigned int vertexCount, 178 unsigned int baseInstance, unsigned int instanceCount) { 179 this->add<DrawInstanced>(type, baseVertex, vertexCount, baseInstance, instanceCount); 180 } 181 182 void drawIndexedInstanced(PrimitiveType type, 183 unsigned int baseIndex, unsigned int indexCount, 184 unsigned int baseVertex, unsigned int baseInstance, 185 unsigned int instanceCount) { 186 this->add<DrawIndexedInstanced>(type, 187 baseIndex, 188 indexCount, 189 baseVertex, 190 baseInstance, 191 instanceCount); 192 } 193 194 void drawIndirect(PrimitiveType type) { 195 this->add<DrawIndirect>(type); 196 } 197 198 void drawIndexedIndirect(PrimitiveType type) { 199 this->add<DrawIndexedIndirect>(type); 200 } 201 202 using Command = std::pair<Type, void*>; 203 using Iter = SkTBlockList<Command, 16>::CIter; 204 Iter commands() const { return fCommands.items(); } 205 206 private: 207 template <typename T, typename... Args> 208 void add(Args&&... args) { 209 T* cmd = fAlloc.make<T>(T{std::forward<Args>(args)...}); 210 fCommands.push_back(std::make_pair(T::kType, cmd)); 211 } 212 213 // This copy() is for arrays. 214 // It will work with POD only arrays. 215 template <typename T> 216 T* copy(const T src[], size_t count) { 217 static_assert(std::is_trivially_copyable<T>::value); 218 T* dst = fAlloc.makeArrayDefault<T>(count); 219 memcpy(dst, src, count*sizeof(T)); 220 return dst; 221 } 222 223 SkTBlockList<Command, 16> fCommands{SkBlockAllocator::GrowthPolicy::kFibonacci}; 224 225 // fAlloc needs to be a data structure which can append variable length data in contiguous 226 // chunks, returning a stable handle to that data for later retrieval. 227 SkArenaAlloc fAlloc{256}; 228 }; 229 230 } // namespace DrawPassCommands 231 232 } // namespace skgpu::graphite 233 234 #endif // skgpu_graphite_DrawPassCommands_DEFINED 235