• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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