1 // 2 // Copyright 2024 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 #ifndef LIBANGLE_RENDERER_WGPU_WGPU_COMMAND_BUFFER_H_ 8 #define LIBANGLE_RENDERER_WGPU_WGPU_COMMAND_BUFFER_H_ 9 10 #include "common/debug.h" 11 #include "libANGLE/renderer/wgpu/wgpu_utils.h" 12 13 #include <dawn/webgpu_cpp.h> 14 #include <unordered_set> 15 16 namespace rx 17 { 18 namespace webgpu 19 { 20 21 #define ANGLE_WGPU_COMMANDS_X(PROC) \ 22 PROC(BeginOcclusionQuery) \ 23 PROC(Draw) \ 24 PROC(DrawIndexed) \ 25 PROC(DrawIndexedIndirect) \ 26 PROC(DrawIndirect) \ 27 PROC(End) \ 28 PROC(EndOcclusionQuery) \ 29 PROC(ExecuteBundles) \ 30 PROC(InsertDebugMarker) \ 31 PROC(PixelLocalStorageBarrier) \ 32 PROC(PopDebugGroup) \ 33 PROC(PushDebugGroup) \ 34 PROC(SetBindGroup) \ 35 PROC(SetBlendConstant) \ 36 PROC(SetIndexBuffer) \ 37 PROC(SetLabel) \ 38 PROC(SetPipeline) \ 39 PROC(SetScissorRect) \ 40 PROC(SetStencilReference) \ 41 PROC(SetVertexBuffer) \ 42 PROC(SetViewport) \ 43 PROC(WriteTimestamp) 44 45 #define WGPU_DECLARE_COMMAND_ID(CMD) CMD, 46 47 enum class CommandID : uint8_t 48 { 49 Invalid = 0, 50 ANGLE_WGPU_COMMANDS_X(WGPU_DECLARE_COMMAND_ID) 51 }; 52 53 ANGLE_ENABLE_STRUCT_PADDING_WARNINGS 54 55 struct BeginOcclusionQueryCommand 56 { 57 uint64_t pad; 58 }; 59 60 struct DrawCommand 61 { 62 uint32_t vertexCount; 63 uint32_t instanceCount; 64 uint32_t firstVertex; 65 uint32_t firstInstance; 66 }; 67 68 struct DrawIndexedCommand 69 { 70 uint32_t indexCount; 71 uint32_t instanceCount; 72 uint32_t firstIndex; 73 uint32_t baseVertex; 74 uint32_t firstInstance; 75 uint32_t pad; 76 }; 77 78 struct DrawIndexedIndirectCommand 79 { 80 uint64_t pad; 81 }; 82 83 struct DrawIndirectCommand 84 { 85 uint64_t pad; 86 }; 87 88 struct EndCommand 89 { 90 uint64_t pad; 91 }; 92 93 struct EndOcclusionQueryCommand 94 { 95 uint64_t pad; 96 }; 97 98 struct ExecuteBundlesCommand 99 { 100 uint64_t pad; 101 }; 102 103 struct InsertDebugMarkerCommand 104 { 105 uint64_t pad; 106 }; 107 108 struct PixelLocalStorageBarrierCommand 109 { 110 uint64_t pad; 111 }; 112 113 struct PopDebugGroupCommand 114 { 115 uint64_t pad; 116 }; 117 118 struct PushDebugGroupCommand 119 { 120 uint64_t pad; 121 }; 122 123 struct SetBindGroupCommand 124 { 125 uint32_t groupIndex; 126 uint32_t pad0; 127 union 128 { 129 const wgpu::BindGroup *bindGroup; 130 uint64_t pad1; // Pad to 64 bits on 32-bit systems 131 }; 132 }; 133 134 struct SetBlendConstantCommand 135 { 136 float r; 137 float g; 138 float b; 139 float a; 140 }; 141 142 struct SetIndexBufferCommand 143 { 144 union 145 { 146 const wgpu::Buffer *buffer; 147 uint64_t pad0; // Pad to 64 bits on 32-bit systems 148 }; 149 wgpu::IndexFormat format; 150 uint32_t pad1; 151 uint64_t offset; 152 uint64_t size; 153 }; 154 155 struct SetLabelCommand 156 { 157 uint64_t pad; 158 }; 159 160 struct SetPipelineCommand 161 { 162 union 163 { 164 const wgpu::RenderPipeline *pipeline; 165 uint64_t padding; // Pad to 64 bits on 32-bit systems 166 }; 167 }; 168 169 struct SetScissorRectCommand 170 { 171 uint32_t x; 172 uint32_t y; 173 uint32_t width; 174 uint32_t height; 175 }; 176 177 struct SetStencilReferenceCommand 178 { 179 uint64_t pad; 180 }; 181 182 struct SetVertexBufferCommand 183 { 184 uint32_t slot; 185 uint32_t pad0; 186 union 187 { 188 const wgpu::Buffer *buffer; 189 uint64_t pad1; // Pad to 64 bits on 32-bit systems 190 }; 191 uint64_t offset; 192 uint64_t size; 193 }; 194 195 struct SetViewportCommand 196 { 197 float x; 198 float y; 199 float width; 200 float height; 201 float minDepth; 202 float maxDepth; 203 }; 204 205 struct WriteTimestampCommand 206 { 207 uint64_t pad; 208 }; 209 210 ANGLE_DISABLE_STRUCT_PADDING_WARNINGS 211 212 #define VERIFY_COMMAND_8_BYTE_ALIGNMENT(CMD) \ 213 static_assert((sizeof(CMD##Command) % 8) == 0, "Check " #CMD "Command alignment"); 214 ANGLE_WGPU_COMMANDS_X(VERIFY_COMMAND_8_BYTE_ALIGNMENT) 215 #undef VERIFY_COMMAND_8_BYTE_ALIGNMENT 216 217 template <CommandID> 218 struct CommandTypeHelper; 219 220 #define ANGLE_WGPU_COMMAND_TYPE_HELPER(CMD) \ 221 template <> \ 222 struct CommandTypeHelper<CommandID::CMD> \ 223 { \ 224 using CommandType = CMD##Command; \ 225 }; 226 ANGLE_WGPU_COMMANDS_X(ANGLE_WGPU_COMMAND_TYPE_HELPER) 227 #undef ANGLE_WGPU_COMMAND_TYPE_HELPER 228 229 static constexpr size_t kCommandBlockSize = 1 << 14; // 16kB 230 231 class CommandBuffer 232 { 233 public: 234 CommandBuffer(); 235 236 void draw(uint32_t vertexCount, 237 uint32_t instanceCount, 238 uint32_t firstVertex, 239 uint32_t firstInstance); 240 void drawIndexed(uint32_t indexCount, 241 uint32_t instanceCount, 242 uint32_t firstIndex, 243 int32_t baseVertex, 244 uint32_t firstInstance); 245 void setBindGroup(uint32_t groupIndex, wgpu::BindGroup bindGroup); 246 void setBlendConstant(float r, float g, float b, float a); 247 void setPipeline(wgpu::RenderPipeline pipeline); 248 void setScissorRect(uint32_t x, uint32_t y, uint32_t width, uint32_t height); 249 void setViewport(float x, float y, float width, float height, float minDepth, float maxDepth); 250 void setIndexBuffer(wgpu::Buffer buffer, 251 wgpu::IndexFormat format, 252 uint64_t offset, 253 uint64_t size); 254 void setVertexBuffer(uint32_t slot, wgpu::Buffer buffer, uint64_t offset, uint64_t size); 255 256 void clear(); 257 hasCommands()258 bool hasCommands() const { return mCommandCount > 0; } hasSetScissorCommand()259 bool hasSetScissorCommand() const { return mHasSetScissorCommand; } hasSetViewportCommand()260 bool hasSetViewportCommand() const { return mHasSetViewportCommand; } hasSetBlendConstantCommand()261 bool hasSetBlendConstantCommand() const { return mHasSetBlendConstantCommand; } 262 263 void recordCommands(wgpu::RenderPassEncoder encoder); 264 265 private: 266 struct CommandBlock 267 { 268 static constexpr size_t kCommandBlockDataSize = kCommandBlockSize - (sizeof(size_t) * 2); 269 uint8_t mData[kCommandBlockDataSize] = {0}; 270 271 size_t mCurrentPosition = 0; 272 273 static constexpr size_t kCommandIDSize = sizeof(CommandID); 274 static constexpr size_t kCommandBlockInitialRemainingSize = 275 kCommandBlockDataSize - kCommandIDSize; // Leave room for one command ID at the end to 276 // signify the end of the list 277 size_t mRemainingSize = kCommandBlockInitialRemainingSize; 278 279 void clear(); 280 void finalize(); 281 282 template <typename T> getDataAtCurrentPositionAndReserveSpaceCommandBlock283 T *getDataAtCurrentPositionAndReserveSpace(size_t space) 284 { 285 T *data = reinterpret_cast<T *>(&mData[mCurrentPosition]); 286 287 ASSERT(mRemainingSize >= space); 288 mCurrentPosition += space; 289 mRemainingSize -= space; 290 291 return data; 292 } 293 }; 294 static constexpr size_t kCommandBlockStructSize = sizeof(CommandBlock); 295 static_assert(kCommandBlockStructSize == kCommandBlockSize, "Size mismatch"); 296 297 std::vector<std::unique_ptr<CommandBlock>> mCommandBlocks; 298 size_t mCurrentCommandBlock = 0; 299 300 size_t mCommandCount = 0; 301 bool mHasSetScissorCommand = false; 302 bool mHasSetViewportCommand = false; 303 bool mHasSetBlendConstantCommand = false; 304 305 // std::unordered_set required because it does not move elements and stored command reference 306 // addresses in the set 307 std::unordered_set<wgpu::RenderPipeline> mReferencedRenderPipelines; 308 std::unordered_set<wgpu::Buffer> mReferencedBuffers; 309 std::unordered_set<wgpu::BindGroup> mReferencedBindGroups; 310 311 void nextCommandBlock(); 312 ensureCommandSpace(size_t space)313 void ensureCommandSpace(size_t space) 314 { 315 if (mCommandBlocks.empty() || mCommandBlocks[mCurrentCommandBlock]->mRemainingSize < space) 316 { 317 nextCommandBlock(); 318 } 319 } 320 321 template <CommandID Command, typename CommandType = CommandTypeHelper<Command>::CommandType> initCommand()322 CommandType *initCommand() 323 { 324 constexpr size_t allocationSize = sizeof(CommandID) + sizeof(CommandType); 325 ensureCommandSpace(allocationSize); 326 CommandBlock *commandBlock = mCommandBlocks[mCurrentCommandBlock].get(); 327 328 uint8_t *idAndCommandStorage = 329 commandBlock->getDataAtCurrentPositionAndReserveSpace<uint8_t>(allocationSize); 330 331 CommandID *id = reinterpret_cast<CommandID *>(idAndCommandStorage); 332 *id = Command; 333 334 CommandType *commandStruct = 335 reinterpret_cast<CommandType *>(idAndCommandStorage + sizeof(CommandID)); 336 337 mCommandCount++; 338 339 return commandStruct; 340 } 341 }; 342 343 } // namespace webgpu 344 } // namespace rx 345 346 #endif // LIBANGLE_RENDERER_WGPU_WGPU_COMMAND_BUFFER_H_ 347