• 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 #include "libANGLE/renderer/wgpu/wgpu_command_buffer.h"
8 
9 namespace rx
10 {
11 namespace webgpu
12 {
13 namespace
14 {
15 template <typename T>
GetReferencedObject(std::unordered_set<T> & referenceList,const T & item)16 const T *GetReferencedObject(std::unordered_set<T> &referenceList, const T &item)
17 {
18     auto iter = referenceList.insert(item).first;
19     return &(*iter);
20 }
21 
22 // Get the packed command ID from the current command data
CurrentCommandID(const uint8_t * commandData)23 CommandID CurrentCommandID(const uint8_t *commandData)
24 {
25     return *reinterpret_cast<const CommandID *>(commandData);
26 }
27 
28 // Get the command struct from the current command data and increment the command data to the next
29 // command
30 template <CommandID Command, typename CommandType = CommandTypeHelper<Command>::CommandType>
GetCommandAndIterate(const uint8_t ** commandData)31 const CommandType &GetCommandAndIterate(const uint8_t **commandData)
32 {
33     constexpr size_t commandAndIdSize = sizeof(CommandID) + sizeof(CommandType);
34     const CommandType *command =
35         reinterpret_cast<const CommandType *>(*commandData + sizeof(CommandID));
36     *commandData += commandAndIdSize;
37     return *command;
38 }
39 }  // namespace
40 
CommandBuffer()41 CommandBuffer::CommandBuffer() {}
42 
draw(uint32_t vertexCount,uint32_t instanceCount,uint32_t firstVertex,uint32_t firstInstance)43 void CommandBuffer::draw(uint32_t vertexCount,
44                          uint32_t instanceCount,
45                          uint32_t firstVertex,
46                          uint32_t firstInstance)
47 {
48     DrawCommand *drawCommand   = initCommand<CommandID::Draw>();
49     drawCommand->vertexCount   = vertexCount;
50     drawCommand->instanceCount = instanceCount;
51     drawCommand->firstVertex   = firstVertex;
52     drawCommand->firstInstance = firstInstance;
53 }
54 
drawIndexed(uint32_t indexCount,uint32_t instanceCount,uint32_t firstIndex,int32_t baseVertex,uint32_t firstInstance)55 void CommandBuffer::drawIndexed(uint32_t indexCount,
56                                 uint32_t instanceCount,
57                                 uint32_t firstIndex,
58                                 int32_t baseVertex,
59                                 uint32_t firstInstance)
60 {
61     DrawIndexedCommand *drawIndexedCommand = initCommand<CommandID::DrawIndexed>();
62     drawIndexedCommand->indexCount         = indexCount;
63     drawIndexedCommand->instanceCount      = instanceCount;
64     drawIndexedCommand->firstIndex         = firstIndex;
65     drawIndexedCommand->baseVertex         = baseVertex;
66     drawIndexedCommand->firstInstance      = firstInstance;
67 }
68 
setBindGroup(uint32_t groupIndex,wgpu::BindGroup bindGroup)69 void CommandBuffer::setBindGroup(uint32_t groupIndex, wgpu::BindGroup bindGroup)
70 {
71     SetBindGroupCommand *setBindGroupCommand = initCommand<CommandID::SetBindGroup>();
72     setBindGroupCommand->groupIndex          = groupIndex;
73     setBindGroupCommand->bindGroup = GetReferencedObject(mReferencedBindGroups, bindGroup);
74 }
75 
setBlendConstant(float r,float g,float b,float a)76 void CommandBuffer::setBlendConstant(float r, float g, float b, float a)
77 {
78     SetBlendConstantCommand *setBlendConstantCommand = initCommand<CommandID::SetBlendConstant>();
79     setBlendConstantCommand->r                       = r;
80     setBlendConstantCommand->g                       = g;
81     setBlendConstantCommand->b                       = b;
82     setBlendConstantCommand->a                       = a;
83 
84     mHasSetBlendConstantCommand = true;
85 }
86 
setPipeline(wgpu::RenderPipeline pipeline)87 void CommandBuffer::setPipeline(wgpu::RenderPipeline pipeline)
88 {
89     SetPipelineCommand *setPiplelineCommand = initCommand<CommandID::SetPipeline>();
90     setPiplelineCommand->pipeline = GetReferencedObject(mReferencedRenderPipelines, pipeline);
91 }
92 
setScissorRect(uint32_t x,uint32_t y,uint32_t width,uint32_t height)93 void CommandBuffer::setScissorRect(uint32_t x, uint32_t y, uint32_t width, uint32_t height)
94 {
95     SetScissorRectCommand *setScissorRectCommand = initCommand<CommandID::SetScissorRect>();
96     setScissorRectCommand->x                     = x;
97     setScissorRectCommand->y                     = y;
98     setScissorRectCommand->width                 = width;
99     setScissorRectCommand->height                = height;
100 
101     mHasSetScissorCommand = true;
102 }
103 
setViewport(float x,float y,float width,float height,float minDepth,float maxDepth)104 void CommandBuffer::setViewport(float x,
105                                 float y,
106                                 float width,
107                                 float height,
108                                 float minDepth,
109                                 float maxDepth)
110 {
111     SetViewportCommand *setViewportCommand = initCommand<CommandID::SetViewport>();
112     setViewportCommand->x                  = x;
113     setViewportCommand->y                  = y;
114     setViewportCommand->width              = width;
115     setViewportCommand->height             = height;
116     setViewportCommand->minDepth           = minDepth;
117     setViewportCommand->maxDepth           = maxDepth;
118 
119     mHasSetViewportCommand = true;
120 }
121 
setIndexBuffer(wgpu::Buffer buffer,wgpu::IndexFormat format,uint64_t offset,uint64_t size)122 void CommandBuffer::setIndexBuffer(wgpu::Buffer buffer,
123                                    wgpu::IndexFormat format,
124                                    uint64_t offset,
125                                    uint64_t size)
126 {
127     SetIndexBufferCommand *setIndexBufferCommand = initCommand<CommandID::SetIndexBuffer>();
128     setIndexBufferCommand->buffer                = GetReferencedObject(mReferencedBuffers, buffer);
129     setIndexBufferCommand->format                = format;
130     setIndexBufferCommand->offset                = offset;
131     setIndexBufferCommand->size                  = size;
132 }
133 
setVertexBuffer(uint32_t slot,wgpu::Buffer buffer,uint64_t offset,uint64_t size)134 void CommandBuffer::setVertexBuffer(uint32_t slot,
135                                     wgpu::Buffer buffer,
136                                     uint64_t offset,
137                                     uint64_t size)
138 {
139     SetVertexBufferCommand *setVertexBufferCommand = initCommand<CommandID::SetVertexBuffer>();
140     setVertexBufferCommand->slot                   = slot;
141     setVertexBufferCommand->buffer = GetReferencedObject(mReferencedBuffers, buffer);
142     setVertexBufferCommand->offset                 = offset;
143     setVertexBufferCommand->size                   = size;
144 }
145 
clear()146 void CommandBuffer::clear()
147 {
148     mCommandCount = 0;
149 
150     mHasSetScissorCommand  = false;
151     mHasSetViewportCommand = false;
152     mHasSetBlendConstantCommand = false;
153 
154     if (!mCommandBlocks.empty())
155     {
156         // Only clear the command blocks that have been used
157         for (size_t cmdBlockIdx = 0; cmdBlockIdx <= mCurrentCommandBlock; cmdBlockIdx++)
158         {
159             mCommandBlocks[cmdBlockIdx]->clear();
160         }
161     }
162     mCurrentCommandBlock = 0;
163 
164     mReferencedRenderPipelines.clear();
165     mReferencedBuffers.clear();
166 }
167 
recordCommands(wgpu::RenderPassEncoder encoder)168 void CommandBuffer::recordCommands(wgpu::RenderPassEncoder encoder)
169 {
170     ASSERT(hasCommands());
171     ASSERT(!mCommandBlocks.empty());
172 
173     // Make sure the last block is finalized
174     mCommandBlocks[mCurrentCommandBlock]->finalize();
175 
176     for (size_t cmdBlockIdx = 0; cmdBlockIdx <= mCurrentCommandBlock; cmdBlockIdx++)
177     {
178         const CommandBlock *commandBlock = mCommandBlocks[cmdBlockIdx].get();
179 
180         const uint8_t *currentCommand = commandBlock->mData;
181         while (CurrentCommandID(currentCommand) != CommandID::Invalid)
182         {
183             switch (CurrentCommandID(currentCommand))
184             {
185                 case CommandID::Invalid:
186                     UNREACHABLE();
187                     return;
188 
189                 case CommandID::Draw:
190                 {
191                     const DrawCommand &drawCommand =
192                         GetCommandAndIterate<CommandID::Draw>(&currentCommand);
193                     encoder.Draw(drawCommand.vertexCount, drawCommand.instanceCount,
194                                  drawCommand.firstVertex, drawCommand.firstInstance);
195                     break;
196                 }
197 
198                 case CommandID::DrawIndexed:
199                 {
200                     const DrawIndexedCommand &drawIndexedCommand =
201                         GetCommandAndIterate<CommandID::DrawIndexed>(&currentCommand);
202                     encoder.DrawIndexed(
203                         drawIndexedCommand.indexCount, drawIndexedCommand.instanceCount,
204                         drawIndexedCommand.firstIndex, drawIndexedCommand.baseVertex,
205                         drawIndexedCommand.firstInstance);
206                     break;
207                 }
208 
209                 case CommandID::SetBindGroup:
210                 {
211                     const SetBindGroupCommand &setBindGroupCommand =
212                         GetCommandAndIterate<CommandID::SetBindGroup>(&currentCommand);
213                     encoder.SetBindGroup(setBindGroupCommand.groupIndex,
214                                          *setBindGroupCommand.bindGroup);
215                     break;
216                 }
217 
218                 case CommandID::SetBlendConstant:
219                 {
220                     const SetBlendConstantCommand &setBlendConstantCommand =
221                         GetCommandAndIterate<CommandID::SetBlendConstant>(&currentCommand);
222                     wgpu::Color color{setBlendConstantCommand.r, setBlendConstantCommand.g,
223                                       setBlendConstantCommand.b, setBlendConstantCommand.a};
224                     encoder.SetBlendConstant(&color);
225                     break;
226                 }
227 
228                 case CommandID::SetIndexBuffer:
229                 {
230                     const SetIndexBufferCommand &setIndexBufferCommand =
231                         GetCommandAndIterate<CommandID::SetIndexBuffer>(&currentCommand);
232                     encoder.SetIndexBuffer(
233                         *setIndexBufferCommand.buffer, setIndexBufferCommand.format,
234                         setIndexBufferCommand.offset, setIndexBufferCommand.size);
235                     break;
236                 }
237 
238                 case CommandID::SetPipeline:
239                 {
240                     const SetPipelineCommand &setPiplelineCommand =
241                         GetCommandAndIterate<CommandID::SetPipeline>(&currentCommand);
242                     encoder.SetPipeline(*setPiplelineCommand.pipeline);
243                     break;
244                 }
245 
246                 case CommandID::SetScissorRect:
247                 {
248                     const SetScissorRectCommand &setScissorRectCommand =
249                         GetCommandAndIterate<CommandID::SetScissorRect>(&currentCommand);
250                     encoder.SetScissorRect(setScissorRectCommand.x, setScissorRectCommand.y,
251                                            setScissorRectCommand.width,
252                                            setScissorRectCommand.height);
253                     break;
254                 }
255 
256                 case CommandID::SetViewport:
257                 {
258                     const SetViewportCommand &setViewportCommand =
259                         GetCommandAndIterate<CommandID::SetViewport>(&currentCommand);
260                     encoder.SetViewport(setViewportCommand.x, setViewportCommand.y,
261                                         setViewportCommand.width, setViewportCommand.height,
262                                         setViewportCommand.minDepth, setViewportCommand.maxDepth);
263                     break;
264                 }
265 
266                 case CommandID::SetVertexBuffer:
267                 {
268                     const SetVertexBufferCommand &setVertexBufferCommand =
269                         GetCommandAndIterate<CommandID::SetVertexBuffer>(&currentCommand);
270                     encoder.SetVertexBuffer(
271                         setVertexBufferCommand.slot, *setVertexBufferCommand.buffer,
272                         setVertexBufferCommand.offset, setVertexBufferCommand.size);
273                     break;
274                 }
275 
276                 default:
277                     UNREACHABLE();
278                     return;
279             }
280         }
281     }
282 }
283 
nextCommandBlock()284 void CommandBuffer::nextCommandBlock()
285 {
286     if (mCurrentCommandBlock + 1 < mCommandBlocks.size())
287     {
288         // There is already a command block allocated. Make sure it's been cleared and use it.
289         mCurrentCommandBlock++;
290         ASSERT(mCommandBlocks[mCurrentCommandBlock]->mCurrentPosition == 0);
291         ASSERT(mCommandBlocks[mCurrentCommandBlock]->mRemainingSize > 0);
292     }
293     else
294     {
295         std::unique_ptr<CommandBlock> newBlock = std::make_unique<CommandBlock>();
296         mCommandBlocks.push_back(std::move(newBlock));
297         mCurrentCommandBlock = mCommandBlocks.size() - 1;
298     }
299 }
300 
clear()301 void CommandBuffer::CommandBlock::clear()
302 {
303     mCurrentPosition = 0;
304     mRemainingSize   = kCommandBlockInitialRemainingSize;
305 }
306 
finalize()307 void CommandBuffer::CommandBlock::finalize()
308 {
309     // Don't move the current position to allow finalize to be called multiple times if needed
310     CommandID *nextCommandID = getDataAtCurrentPositionAndReserveSpace<CommandID>(0);
311     *nextCommandID           = CommandID::Invalid;
312     mRemainingSize           = 0;
313 }
314 
315 }  // namespace webgpu
316 }  // namespace rx
317