• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "dawn_native/CommandEncoder.h"
16 
17 #include "common/BitSetIterator.h"
18 #include "common/Math.h"
19 #include "dawn_native/BindGroup.h"
20 #include "dawn_native/Buffer.h"
21 #include "dawn_native/CommandBuffer.h"
22 #include "dawn_native/CommandBufferStateTracker.h"
23 #include "dawn_native/CommandValidation.h"
24 #include "dawn_native/Commands.h"
25 #include "dawn_native/ComputePassEncoder.h"
26 #include "dawn_native/Device.h"
27 #include "dawn_native/ErrorData.h"
28 #include "dawn_native/ObjectType_autogen.h"
29 #include "dawn_native/QueryHelper.h"
30 #include "dawn_native/QuerySet.h"
31 #include "dawn_native/Queue.h"
32 #include "dawn_native/RenderPassEncoder.h"
33 #include "dawn_native/RenderPipeline.h"
34 #include "dawn_native/ValidationUtils_autogen.h"
35 #include "dawn_platform/DawnPlatform.h"
36 #include "dawn_platform/tracing/TraceEvent.h"
37 
38 #include <cmath>
39 #include <map>
40 
41 namespace dawn_native {
42 
43     namespace {
44 
ValidateB2BCopyAlignment(uint64_t dataSize,uint64_t srcOffset,uint64_t dstOffset)45         MaybeError ValidateB2BCopyAlignment(uint64_t dataSize,
46                                             uint64_t srcOffset,
47                                             uint64_t dstOffset) {
48             // Copy size must be a multiple of 4 bytes on macOS.
49             DAWN_INVALID_IF(dataSize % 4 != 0, "Copy size (%u) is not a multiple of 4.", dataSize);
50 
51             // SourceOffset and destinationOffset must be multiples of 4 bytes on macOS.
52             DAWN_INVALID_IF(
53                 srcOffset % 4 != 0 || dstOffset % 4 != 0,
54                 "Source offset (%u) or destination offset (%u) is not a multiple of 4 bytes,",
55                 srcOffset, dstOffset);
56 
57             return {};
58         }
59 
ValidateTextureSampleCountInBufferCopyCommands(const TextureBase * texture)60         MaybeError ValidateTextureSampleCountInBufferCopyCommands(const TextureBase* texture) {
61             DAWN_INVALID_IF(texture->GetSampleCount() > 1,
62                             "%s sample count (%u) is not 1 when copying to or from a buffer.",
63                             texture, texture->GetSampleCount());
64 
65             return {};
66         }
67 
ValidateLinearTextureCopyOffset(const TextureDataLayout & layout,const TexelBlockInfo & blockInfo,const bool hasDepthOrStencil)68         MaybeError ValidateLinearTextureCopyOffset(const TextureDataLayout& layout,
69                                                    const TexelBlockInfo& blockInfo,
70                                                    const bool hasDepthOrStencil) {
71             if (hasDepthOrStencil) {
72                 // For depth-stencil texture, buffer offset must be a multiple of 4.
73                 DAWN_INVALID_IF(layout.offset % 4 != 0,
74                                 "Offset (%u) is not a multiple of 4 for depth/stencil texture.",
75                                 layout.offset);
76             } else {
77                 DAWN_INVALID_IF(layout.offset % blockInfo.byteSize != 0,
78                                 "Offset (%u) is not a multiple of the texel block byte size (%u).",
79                                 layout.offset, blockInfo.byteSize);
80             }
81             return {};
82         }
83 
ValidateTextureDepthStencilToBufferCopyRestrictions(const ImageCopyTexture & src)84         MaybeError ValidateTextureDepthStencilToBufferCopyRestrictions(
85             const ImageCopyTexture& src) {
86             Aspect aspectUsed;
87             DAWN_TRY_ASSIGN(aspectUsed, SingleAspectUsedByImageCopyTexture(src));
88             if (aspectUsed == Aspect::Depth) {
89                 switch (src.texture->GetFormat().format) {
90                     case wgpu::TextureFormat::Depth24Plus:
91                     case wgpu::TextureFormat::Depth24PlusStencil8:
92                     case wgpu::TextureFormat::Depth24UnormStencil8:
93                         return DAWN_FORMAT_VALIDATION_ERROR(
94                             "The depth aspect of %s format %s cannot be selected in a texture to "
95                             "buffer copy.",
96                             src.texture, src.texture->GetFormat().format);
97                     case wgpu::TextureFormat::Depth32Float:
98                     case wgpu::TextureFormat::Depth16Unorm:
99                     case wgpu::TextureFormat::Depth32FloatStencil8:
100                         break;
101 
102                     default:
103                         UNREACHABLE();
104                 }
105             }
106 
107             return {};
108         }
109 
ValidateAttachmentArrayLayersAndLevelCount(const TextureViewBase * attachment)110         MaybeError ValidateAttachmentArrayLayersAndLevelCount(const TextureViewBase* attachment) {
111             // Currently we do not support layered rendering.
112             DAWN_INVALID_IF(attachment->GetLayerCount() > 1,
113                             "The layer count (%u) of %s used as attachment is greater than 1.",
114                             attachment->GetLayerCount(), attachment);
115 
116             DAWN_INVALID_IF(attachment->GetLevelCount() > 1,
117                             "The mip level count (%u) of %s used as attachment is greater than 1.",
118                             attachment->GetLevelCount(), attachment);
119 
120             return {};
121         }
122 
ValidateOrSetAttachmentSize(const TextureViewBase * attachment,uint32_t * width,uint32_t * height)123         MaybeError ValidateOrSetAttachmentSize(const TextureViewBase* attachment,
124                                                uint32_t* width,
125                                                uint32_t* height) {
126             const Extent3D& attachmentSize =
127                 attachment->GetTexture()->GetMipLevelVirtualSize(attachment->GetBaseMipLevel());
128 
129             if (*width == 0) {
130                 DAWN_ASSERT(*height == 0);
131                 *width = attachmentSize.width;
132                 *height = attachmentSize.height;
133                 DAWN_ASSERT(*width != 0 && *height != 0);
134             } else {
135                 DAWN_INVALID_IF(
136                     *width != attachmentSize.width || *height != attachmentSize.height,
137                     "Attachment %s size (width: %u, height: %u) does not match the size of the "
138                     "other attachments (width: %u, height: %u).",
139                     attachment, attachmentSize.width, attachmentSize.height, *width, *height);
140             }
141 
142             return {};
143         }
144 
ValidateOrSetColorAttachmentSampleCount(const TextureViewBase * colorAttachment,uint32_t * sampleCount)145         MaybeError ValidateOrSetColorAttachmentSampleCount(const TextureViewBase* colorAttachment,
146                                                            uint32_t* sampleCount) {
147             if (*sampleCount == 0) {
148                 *sampleCount = colorAttachment->GetTexture()->GetSampleCount();
149                 DAWN_ASSERT(*sampleCount != 0);
150             } else {
151                 DAWN_INVALID_IF(
152                     *sampleCount != colorAttachment->GetTexture()->GetSampleCount(),
153                     "Color attachment %s sample count (%u) does not match the sample count of the "
154                     "other attachments (%u).",
155                     colorAttachment, colorAttachment->GetTexture()->GetSampleCount(), *sampleCount);
156             }
157 
158             return {};
159         }
160 
ValidateResolveTarget(const DeviceBase * device,const RenderPassColorAttachment & colorAttachment)161         MaybeError ValidateResolveTarget(const DeviceBase* device,
162                                          const RenderPassColorAttachment& colorAttachment) {
163             if (colorAttachment.resolveTarget == nullptr) {
164                 return {};
165             }
166 
167             const TextureViewBase* resolveTarget = colorAttachment.resolveTarget;
168             const TextureViewBase* attachment = colorAttachment.view;
169             DAWN_TRY(device->ValidateObject(colorAttachment.resolveTarget));
170             DAWN_TRY(ValidateCanUseAs(colorAttachment.resolveTarget->GetTexture(),
171                                       wgpu::TextureUsage::RenderAttachment));
172 
173             DAWN_INVALID_IF(
174                 !attachment->GetTexture()->IsMultisampledTexture(),
175                 "Cannot set %s as a resolve target when the color attachment %s has a sample "
176                 "count of 1.",
177                 resolveTarget, attachment);
178 
179             DAWN_INVALID_IF(resolveTarget->GetTexture()->IsMultisampledTexture(),
180                             "Cannot use %s as resolve target. Sample count (%u) is greater than 1.",
181                             resolveTarget, resolveTarget->GetTexture()->GetSampleCount());
182 
183             DAWN_INVALID_IF(resolveTarget->GetLayerCount() > 1,
184                             "The resolve target %s array layer count (%u) is not 1.", resolveTarget,
185                             resolveTarget->GetLayerCount());
186 
187             DAWN_INVALID_IF(resolveTarget->GetLevelCount() > 1,
188                             "The resolve target %s mip level count (%u) is not 1.", resolveTarget,
189                             resolveTarget->GetLevelCount());
190 
191             const Extent3D& colorTextureSize =
192                 attachment->GetTexture()->GetMipLevelVirtualSize(attachment->GetBaseMipLevel());
193             const Extent3D& resolveTextureSize =
194                 resolveTarget->GetTexture()->GetMipLevelVirtualSize(
195                     resolveTarget->GetBaseMipLevel());
196             DAWN_INVALID_IF(
197                 colorTextureSize.width != resolveTextureSize.width ||
198                     colorTextureSize.height != resolveTextureSize.height,
199                 "The Resolve target %s size (width: %u, height: %u) does not match the color "
200                 "attachment %s size (width: %u, height: %u).",
201                 resolveTarget, resolveTextureSize.width, resolveTextureSize.height, attachment,
202                 colorTextureSize.width, colorTextureSize.height);
203 
204             wgpu::TextureFormat resolveTargetFormat = resolveTarget->GetFormat().format;
205             DAWN_INVALID_IF(
206                 resolveTargetFormat != attachment->GetFormat().format,
207                 "The resolve target %s format (%s) does not match the color attachment %s format "
208                 "(%s).",
209                 resolveTarget, resolveTargetFormat, attachment, attachment->GetFormat().format);
210 
211             return {};
212         }
213 
ValidateRenderPassColorAttachment(DeviceBase * device,const RenderPassColorAttachment & colorAttachment,uint32_t * width,uint32_t * height,uint32_t * sampleCount)214         MaybeError ValidateRenderPassColorAttachment(
215             DeviceBase* device,
216             const RenderPassColorAttachment& colorAttachment,
217             uint32_t* width,
218             uint32_t* height,
219             uint32_t* sampleCount) {
220             TextureViewBase* attachment = colorAttachment.view;
221             DAWN_TRY(device->ValidateObject(attachment));
222             DAWN_TRY(
223                 ValidateCanUseAs(attachment->GetTexture(), wgpu::TextureUsage::RenderAttachment));
224 
225             DAWN_INVALID_IF(!(attachment->GetAspects() & Aspect::Color) ||
226                                 !attachment->GetFormat().isRenderable,
227                             "The color attachment %s format (%s) is not color renderable.",
228                             attachment, attachment->GetFormat().format);
229 
230             DAWN_TRY(ValidateLoadOp(colorAttachment.loadOp));
231             DAWN_TRY(ValidateStoreOp(colorAttachment.storeOp));
232 
233             if (colorAttachment.loadOp == wgpu::LoadOp::Clear) {
234                 DAWN_INVALID_IF(std::isnan(colorAttachment.clearColor.r) ||
235                                     std::isnan(colorAttachment.clearColor.g) ||
236                                     std::isnan(colorAttachment.clearColor.b) ||
237                                     std::isnan(colorAttachment.clearColor.a),
238                                 "Color clear value (%s) contain a NaN.",
239                                 &colorAttachment.clearColor);
240             }
241 
242             DAWN_TRY(ValidateOrSetColorAttachmentSampleCount(attachment, sampleCount));
243 
244             DAWN_TRY(ValidateResolveTarget(device, colorAttachment));
245 
246             DAWN_TRY(ValidateAttachmentArrayLayersAndLevelCount(attachment));
247             DAWN_TRY(ValidateOrSetAttachmentSize(attachment, width, height));
248 
249             return {};
250         }
251 
ValidateRenderPassDepthStencilAttachment(DeviceBase * device,const RenderPassDepthStencilAttachment * depthStencilAttachment,uint32_t * width,uint32_t * height,uint32_t * sampleCount)252         MaybeError ValidateRenderPassDepthStencilAttachment(
253             DeviceBase* device,
254             const RenderPassDepthStencilAttachment* depthStencilAttachment,
255             uint32_t* width,
256             uint32_t* height,
257             uint32_t* sampleCount) {
258             DAWN_ASSERT(depthStencilAttachment != nullptr);
259 
260             TextureViewBase* attachment = depthStencilAttachment->view;
261             DAWN_TRY(device->ValidateObject(attachment));
262             DAWN_TRY(
263                 ValidateCanUseAs(attachment->GetTexture(), wgpu::TextureUsage::RenderAttachment));
264 
265             const Format& format = attachment->GetFormat();
266             DAWN_INVALID_IF(
267                 !format.HasDepthOrStencil(),
268                 "The depth stencil attachment %s format (%s) is not a depth stencil format.",
269                 attachment, format.format);
270 
271             DAWN_INVALID_IF(!format.isRenderable,
272                             "The depth stencil attachment %s format (%s) is not renderable.",
273                             attachment, format.format);
274 
275             DAWN_INVALID_IF(attachment->GetAspects() != format.aspects,
276                             "The depth stencil attachment %s must encompass all aspects.",
277                             attachment);
278 
279             DAWN_TRY(ValidateLoadOp(depthStencilAttachment->depthLoadOp));
280             DAWN_TRY(ValidateLoadOp(depthStencilAttachment->stencilLoadOp));
281             DAWN_TRY(ValidateStoreOp(depthStencilAttachment->depthStoreOp));
282             DAWN_TRY(ValidateStoreOp(depthStencilAttachment->stencilStoreOp));
283 
284             DAWN_INVALID_IF(
285                 attachment->GetAspects() == (Aspect::Depth | Aspect::Stencil) &&
286                     depthStencilAttachment->depthReadOnly !=
287                         depthStencilAttachment->stencilReadOnly,
288                 "depthReadOnly (%u) and stencilReadOnly (%u) must be the same when texture aspect "
289                 "is 'all'.",
290                 depthStencilAttachment->depthReadOnly, depthStencilAttachment->stencilReadOnly);
291 
292             DAWN_INVALID_IF(
293                 depthStencilAttachment->depthReadOnly &&
294                     (depthStencilAttachment->depthLoadOp != wgpu::LoadOp::Load ||
295                      depthStencilAttachment->depthStoreOp != wgpu::StoreOp::Store),
296                 "depthLoadOp (%s) is not %s or depthStoreOp (%s) is not %s when depthReadOnly "
297                 "is true.",
298                 depthStencilAttachment->depthLoadOp, wgpu::LoadOp::Load,
299                 depthStencilAttachment->depthStoreOp, wgpu::StoreOp::Store);
300 
301             DAWN_INVALID_IF(depthStencilAttachment->stencilReadOnly &&
302                                 (depthStencilAttachment->stencilLoadOp != wgpu::LoadOp::Load ||
303                                  depthStencilAttachment->stencilStoreOp != wgpu::StoreOp::Store),
304                             "stencilLoadOp (%s) is not %s or stencilStoreOp (%s) is not %s when "
305                             "stencilReadOnly is true.",
306                             depthStencilAttachment->stencilLoadOp, wgpu::LoadOp::Load,
307                             depthStencilAttachment->stencilStoreOp, wgpu::StoreOp::Store);
308 
309             DAWN_INVALID_IF(depthStencilAttachment->depthLoadOp == wgpu::LoadOp::Clear &&
310                                 std::isnan(depthStencilAttachment->clearDepth),
311                             "Depth clear value is NaN.");
312 
313             // *sampleCount == 0 must only happen when there is no color attachment. In that case we
314             // do not need to validate the sample count of the depth stencil attachment.
315             const uint32_t depthStencilSampleCount = attachment->GetTexture()->GetSampleCount();
316             if (*sampleCount != 0) {
317                 DAWN_INVALID_IF(
318                     depthStencilSampleCount != *sampleCount,
319                     "The depth stencil attachment %s sample count (%u) does not match the sample "
320                     "count of the other attachments (%u).",
321                     attachment, depthStencilSampleCount, *sampleCount);
322             } else {
323                 *sampleCount = depthStencilSampleCount;
324             }
325 
326             DAWN_TRY(ValidateAttachmentArrayLayersAndLevelCount(attachment));
327             DAWN_TRY(ValidateOrSetAttachmentSize(attachment, width, height));
328 
329             return {};
330         }
331 
ValidateRenderPassDescriptor(DeviceBase * device,const RenderPassDescriptor * descriptor,uint32_t * width,uint32_t * height,uint32_t * sampleCount)332         MaybeError ValidateRenderPassDescriptor(DeviceBase* device,
333                                                 const RenderPassDescriptor* descriptor,
334                                                 uint32_t* width,
335                                                 uint32_t* height,
336                                                 uint32_t* sampleCount) {
337             DAWN_INVALID_IF(
338                 descriptor->colorAttachmentCount > kMaxColorAttachments,
339                 "Color attachment count (%u) exceeds the maximum number of color attachments (%u).",
340                 descriptor->colorAttachmentCount, kMaxColorAttachments);
341 
342             for (uint32_t i = 0; i < descriptor->colorAttachmentCount; ++i) {
343                 DAWN_TRY_CONTEXT(
344                     ValidateRenderPassColorAttachment(device, descriptor->colorAttachments[i],
345                                                       width, height, sampleCount),
346                     "validating colorAttachments[%u].", i);
347             }
348 
349             if (descriptor->depthStencilAttachment != nullptr) {
350                 DAWN_TRY_CONTEXT(
351                     ValidateRenderPassDepthStencilAttachment(
352                         device, descriptor->depthStencilAttachment, width, height, sampleCount),
353                     "validating depthStencilAttachment.");
354             }
355 
356             if (descriptor->occlusionQuerySet != nullptr) {
357                 DAWN_TRY(device->ValidateObject(descriptor->occlusionQuerySet));
358 
359                 DAWN_INVALID_IF(
360                     descriptor->occlusionQuerySet->GetQueryType() != wgpu::QueryType::Occlusion,
361                     "The occlusionQuerySet %s type (%s) is not %s.", descriptor->occlusionQuerySet,
362                     descriptor->occlusionQuerySet->GetQueryType(), wgpu::QueryType::Occlusion);
363             }
364 
365             DAWN_INVALID_IF(descriptor->colorAttachmentCount == 0 &&
366                                 descriptor->depthStencilAttachment == nullptr,
367                             "Render pass has no attachments.");
368 
369             return {};
370         }
371 
ValidateComputePassDescriptor(const DeviceBase * device,const ComputePassDescriptor * descriptor)372         MaybeError ValidateComputePassDescriptor(const DeviceBase* device,
373                                                  const ComputePassDescriptor* descriptor) {
374             return {};
375         }
376 
ValidateQuerySetResolve(const QuerySetBase * querySet,uint32_t firstQuery,uint32_t queryCount,const BufferBase * destination,uint64_t destinationOffset)377         MaybeError ValidateQuerySetResolve(const QuerySetBase* querySet,
378                                            uint32_t firstQuery,
379                                            uint32_t queryCount,
380                                            const BufferBase* destination,
381                                            uint64_t destinationOffset) {
382             DAWN_INVALID_IF(firstQuery >= querySet->GetQueryCount(),
383                             "First query (%u) exceeds the number of queries (%u) in %s.",
384                             firstQuery, querySet->GetQueryCount(), querySet);
385 
386             DAWN_INVALID_IF(
387                 queryCount > querySet->GetQueryCount() - firstQuery,
388                 "The query range (firstQuery: %u, queryCount: %u) exceeds the number of queries "
389                 "(%u) in %s.",
390                 firstQuery, queryCount, querySet->GetQueryCount(), querySet);
391 
392             DAWN_INVALID_IF(destinationOffset % 256 != 0,
393                             "The destination buffer %s offset (%u) is not a multiple of 256.",
394                             destination, destinationOffset);
395 
396             uint64_t bufferSize = destination->GetSize();
397             // The destination buffer must have enough storage, from destination offset, to contain
398             // the result of resolved queries
399             bool fitsInBuffer = destinationOffset <= bufferSize &&
400                                 (static_cast<uint64_t>(queryCount) * sizeof(uint64_t) <=
401                                  (bufferSize - destinationOffset));
402             DAWN_INVALID_IF(
403                 !fitsInBuffer,
404                 "The resolved %s data size (%u) would not fit in %s with size %u at the offset %u.",
405                 querySet, static_cast<uint64_t>(queryCount) * sizeof(uint64_t), destination,
406                 bufferSize, destinationOffset);
407 
408             return {};
409         }
410 
EncodeTimestampsToNanosecondsConversion(CommandEncoder * encoder,QuerySetBase * querySet,uint32_t firstQuery,uint32_t queryCount,BufferBase * destination,uint64_t destinationOffset)411         MaybeError EncodeTimestampsToNanosecondsConversion(CommandEncoder* encoder,
412                                                            QuerySetBase* querySet,
413                                                            uint32_t firstQuery,
414                                                            uint32_t queryCount,
415                                                            BufferBase* destination,
416                                                            uint64_t destinationOffset) {
417             DeviceBase* device = encoder->GetDevice();
418 
419             // The availability got from query set is a reference to vector<bool>, need to covert
420             // bool to uint32_t due to a user input in pipeline must not contain a bool type in
421             // WGSL.
422             std::vector<uint32_t> availability{querySet->GetQueryAvailability().begin(),
423                                                querySet->GetQueryAvailability().end()};
424 
425             // Timestamp availability storage buffer
426             BufferDescriptor availabilityDesc = {};
427             availabilityDesc.usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopyDst;
428             availabilityDesc.size = querySet->GetQueryCount() * sizeof(uint32_t);
429             Ref<BufferBase> availabilityBuffer;
430             DAWN_TRY_ASSIGN(availabilityBuffer, device->CreateBuffer(&availabilityDesc));
431 
432             DAWN_TRY(device->GetQueue()->WriteBuffer(availabilityBuffer.Get(), 0,
433                                                      availability.data(),
434                                                      availability.size() * sizeof(uint32_t)));
435 
436             // Timestamp params uniform buffer
437             TimestampParams params = {firstQuery, queryCount,
438                                       static_cast<uint32_t>(destinationOffset),
439                                       device->GetTimestampPeriodInNS()};
440 
441             BufferDescriptor parmsDesc = {};
442             parmsDesc.usage = wgpu::BufferUsage::Uniform | wgpu::BufferUsage::CopyDst;
443             parmsDesc.size = sizeof(params);
444             Ref<BufferBase> paramsBuffer;
445             DAWN_TRY_ASSIGN(paramsBuffer, device->CreateBuffer(&parmsDesc));
446 
447             DAWN_TRY(
448                 device->GetQueue()->WriteBuffer(paramsBuffer.Get(), 0, &params, sizeof(params)));
449 
450             return EncodeConvertTimestampsToNanoseconds(
451                 encoder, destination, availabilityBuffer.Get(), paramsBuffer.Get());
452         }
453 
IsReadOnlyDepthStencilAttachment(const RenderPassDepthStencilAttachment * depthStencilAttachment)454         bool IsReadOnlyDepthStencilAttachment(
455             const RenderPassDepthStencilAttachment* depthStencilAttachment) {
456             DAWN_ASSERT(depthStencilAttachment != nullptr);
457             Aspect aspects = depthStencilAttachment->view->GetAspects();
458             DAWN_ASSERT(IsSubset(aspects, Aspect::Depth | Aspect::Stencil));
459 
460             if ((aspects & Aspect::Depth) && !depthStencilAttachment->depthReadOnly) {
461                 return false;
462             }
463             if (aspects & Aspect::Stencil && !depthStencilAttachment->stencilReadOnly) {
464                 return false;
465             }
466             return true;
467         }
468 
469     }  // namespace
470 
CommandEncoder(DeviceBase * device,const CommandEncoderDescriptor * descriptor)471     CommandEncoder::CommandEncoder(DeviceBase* device, const CommandEncoderDescriptor* descriptor)
472         : ApiObjectBase(device, descriptor->label), mEncodingContext(device, this) {
473         TrackInDevice();
474     }
475 
GetType() const476     ObjectType CommandEncoder::GetType() const {
477         return ObjectType::CommandEncoder;
478     }
479 
DestroyImpl()480     void CommandEncoder::DestroyImpl() {
481         mEncodingContext.Destroy();
482     }
483 
AcquireResourceUsages()484     CommandBufferResourceUsage CommandEncoder::AcquireResourceUsages() {
485         return CommandBufferResourceUsage{
486             mEncodingContext.AcquireRenderPassUsages(), mEncodingContext.AcquireComputePassUsages(),
487             std::move(mTopLevelBuffers), std::move(mTopLevelTextures), std::move(mUsedQuerySets)};
488     }
489 
AcquireCommands()490     CommandIterator CommandEncoder::AcquireCommands() {
491         return mEncodingContext.AcquireCommands();
492     }
493 
TrackUsedQuerySet(QuerySetBase * querySet)494     void CommandEncoder::TrackUsedQuerySet(QuerySetBase* querySet) {
495         mUsedQuerySets.insert(querySet);
496     }
497 
TrackQueryAvailability(QuerySetBase * querySet,uint32_t queryIndex)498     void CommandEncoder::TrackQueryAvailability(QuerySetBase* querySet, uint32_t queryIndex) {
499         DAWN_ASSERT(querySet != nullptr);
500 
501         if (GetDevice()->IsValidationEnabled()) {
502             TrackUsedQuerySet(querySet);
503         }
504 
505         // Set the query at queryIndex to available for resolving in query set.
506         querySet->SetQueryAvailability(queryIndex, true);
507     }
508 
509     // Implementation of the API's command recording methods
510 
APIBeginComputePass(const ComputePassDescriptor * descriptor)511     ComputePassEncoder* CommandEncoder::APIBeginComputePass(
512         const ComputePassDescriptor* descriptor) {
513         DeviceBase* device = GetDevice();
514 
515         bool success = mEncodingContext.TryEncode(
516             this,
517             [&](CommandAllocator* allocator) -> MaybeError {
518                 DAWN_TRY(ValidateComputePassDescriptor(device, descriptor));
519 
520                 allocator->Allocate<BeginComputePassCmd>(Command::BeginComputePass);
521 
522                 return {};
523             },
524             "encoding %s.BeginComputePass(%s).", this, descriptor);
525 
526         if (success) {
527             const ComputePassDescriptor defaultDescriptor = {};
528             if (descriptor == nullptr) {
529                 descriptor = &defaultDescriptor;
530             }
531 
532             ComputePassEncoder* passEncoder =
533                 new ComputePassEncoder(device, descriptor, this, &mEncodingContext);
534             mEncodingContext.EnterPass(passEncoder);
535             return passEncoder;
536         }
537 
538         return ComputePassEncoder::MakeError(device, this, &mEncodingContext);
539     }
540 
APIBeginRenderPass(const RenderPassDescriptor * descriptor)541     RenderPassEncoder* CommandEncoder::APIBeginRenderPass(const RenderPassDescriptor* descriptor) {
542         DeviceBase* device = GetDevice();
543 
544         RenderPassResourceUsageTracker usageTracker;
545 
546         uint32_t width = 0;
547         uint32_t height = 0;
548         bool depthReadOnly = false;
549         bool stencilReadOnly = false;
550         Ref<AttachmentState> attachmentState;
551         bool success = mEncodingContext.TryEncode(
552             this,
553             [&](CommandAllocator* allocator) -> MaybeError {
554                 uint32_t sampleCount = 0;
555 
556                 DAWN_TRY(ValidateRenderPassDescriptor(device, descriptor, &width, &height,
557                                                       &sampleCount));
558 
559                 ASSERT(width > 0 && height > 0 && sampleCount > 0);
560 
561                 mEncodingContext.WillBeginRenderPass();
562                 BeginRenderPassCmd* cmd =
563                     allocator->Allocate<BeginRenderPassCmd>(Command::BeginRenderPass);
564 
565                 cmd->attachmentState = device->GetOrCreateAttachmentState(descriptor);
566                 attachmentState = cmd->attachmentState;
567 
568                 for (ColorAttachmentIndex index :
569                      IterateBitSet(cmd->attachmentState->GetColorAttachmentsMask())) {
570                     uint8_t i = static_cast<uint8_t>(index);
571                     TextureViewBase* view = descriptor->colorAttachments[i].view;
572                     TextureViewBase* resolveTarget = descriptor->colorAttachments[i].resolveTarget;
573 
574                     cmd->colorAttachments[index].view = view;
575                     cmd->colorAttachments[index].resolveTarget = resolveTarget;
576                     cmd->colorAttachments[index].loadOp = descriptor->colorAttachments[i].loadOp;
577                     cmd->colorAttachments[index].storeOp = descriptor->colorAttachments[i].storeOp;
578                     cmd->colorAttachments[index].clearColor =
579                         descriptor->colorAttachments[i].clearColor;
580 
581                     usageTracker.TextureViewUsedAs(view, wgpu::TextureUsage::RenderAttachment);
582 
583                     if (resolveTarget != nullptr) {
584                         usageTracker.TextureViewUsedAs(resolveTarget,
585                                                        wgpu::TextureUsage::RenderAttachment);
586                     }
587                 }
588 
589                 if (cmd->attachmentState->HasDepthStencilAttachment()) {
590                     TextureViewBase* view = descriptor->depthStencilAttachment->view;
591 
592                     cmd->depthStencilAttachment.view = view;
593                     cmd->depthStencilAttachment.clearDepth =
594                         descriptor->depthStencilAttachment->clearDepth;
595                     cmd->depthStencilAttachment.clearStencil =
596                         descriptor->depthStencilAttachment->clearStencil;
597                     cmd->depthStencilAttachment.depthLoadOp =
598                         descriptor->depthStencilAttachment->depthLoadOp;
599                     cmd->depthStencilAttachment.depthStoreOp =
600                         descriptor->depthStencilAttachment->depthStoreOp;
601                     cmd->depthStencilAttachment.stencilLoadOp =
602                         descriptor->depthStencilAttachment->stencilLoadOp;
603                     cmd->depthStencilAttachment.stencilStoreOp =
604                         descriptor->depthStencilAttachment->stencilStoreOp;
605                     cmd->depthStencilAttachment.depthReadOnly =
606                         descriptor->depthStencilAttachment->depthReadOnly;
607                     cmd->depthStencilAttachment.stencilReadOnly =
608                         descriptor->depthStencilAttachment->stencilReadOnly;
609 
610                     if (IsReadOnlyDepthStencilAttachment(descriptor->depthStencilAttachment)) {
611                         // TODO(dawn:485): Readonly depth/stencil attachment is not fully
612                         // implemented. Disallow it as unsafe until the implementaion is completed.
613                         DAWN_INVALID_IF(
614                             device->IsToggleEnabled(Toggle::DisallowUnsafeAPIs),
615                             "Readonly depth/stencil attachment is disallowed because it's not "
616                             "fully implemented");
617 
618                         usageTracker.TextureViewUsedAs(view, kReadOnlyRenderAttachment);
619                     } else {
620                         usageTracker.TextureViewUsedAs(view, wgpu::TextureUsage::RenderAttachment);
621                     }
622 
623                     depthReadOnly = descriptor->depthStencilAttachment->depthReadOnly;
624                     stencilReadOnly = descriptor->depthStencilAttachment->stencilReadOnly;
625                 }
626 
627                 cmd->width = width;
628                 cmd->height = height;
629 
630                 cmd->occlusionQuerySet = descriptor->occlusionQuerySet;
631 
632                 return {};
633             },
634             "encoding %s.BeginRenderPass(%s).", this, descriptor);
635 
636         if (success) {
637             RenderPassEncoder* passEncoder = new RenderPassEncoder(
638                 device, descriptor, this, &mEncodingContext, std::move(usageTracker),
639                 std::move(attachmentState), descriptor->occlusionQuerySet, width, height,
640                 depthReadOnly, stencilReadOnly);
641             mEncodingContext.EnterPass(passEncoder);
642             return passEncoder;
643         }
644 
645         return RenderPassEncoder::MakeError(device, this, &mEncodingContext);
646     }
647 
APICopyBufferToBuffer(BufferBase * source,uint64_t sourceOffset,BufferBase * destination,uint64_t destinationOffset,uint64_t size)648     void CommandEncoder::APICopyBufferToBuffer(BufferBase* source,
649                                                uint64_t sourceOffset,
650                                                BufferBase* destination,
651                                                uint64_t destinationOffset,
652                                                uint64_t size) {
653         mEncodingContext.TryEncode(
654             this,
655             [&](CommandAllocator* allocator) -> MaybeError {
656                 if (GetDevice()->IsValidationEnabled()) {
657                     DAWN_TRY(GetDevice()->ValidateObject(source));
658                     DAWN_TRY(GetDevice()->ValidateObject(destination));
659 
660                     DAWN_INVALID_IF(source == destination,
661                                     "Source and destination are the same buffer (%s).", source);
662 
663                     DAWN_TRY_CONTEXT(ValidateCopySizeFitsInBuffer(source, sourceOffset, size),
664                                      "validating source %s copy size.", source);
665                     DAWN_TRY_CONTEXT(
666                         ValidateCopySizeFitsInBuffer(destination, destinationOffset, size),
667                         "validating destination %s copy size.", destination);
668                     DAWN_TRY(ValidateB2BCopyAlignment(size, sourceOffset, destinationOffset));
669 
670                     DAWN_TRY_CONTEXT(ValidateCanUseAs(source, wgpu::BufferUsage::CopySrc),
671                                      "validating source %s usage.", source);
672                     DAWN_TRY_CONTEXT(ValidateCanUseAs(destination, wgpu::BufferUsage::CopyDst),
673                                      "validating destination %s usage.", destination);
674 
675                     mTopLevelBuffers.insert(source);
676                     mTopLevelBuffers.insert(destination);
677                 }
678 
679                 CopyBufferToBufferCmd* copy =
680                     allocator->Allocate<CopyBufferToBufferCmd>(Command::CopyBufferToBuffer);
681                 copy->source = source;
682                 copy->sourceOffset = sourceOffset;
683                 copy->destination = destination;
684                 copy->destinationOffset = destinationOffset;
685                 copy->size = size;
686 
687                 return {};
688             },
689             "encoding %s.CopyBufferToBuffer(%s, %u, %s, %u, %u).", this, source, sourceOffset,
690             destination, destinationOffset, size);
691     }
692 
APICopyBufferToTexture(const ImageCopyBuffer * source,const ImageCopyTexture * destination,const Extent3D * copySize)693     void CommandEncoder::APICopyBufferToTexture(const ImageCopyBuffer* source,
694                                                 const ImageCopyTexture* destination,
695                                                 const Extent3D* copySize) {
696         mEncodingContext.TryEncode(
697             this,
698             [&](CommandAllocator* allocator) -> MaybeError {
699                 if (GetDevice()->IsValidationEnabled()) {
700                     DAWN_TRY(ValidateImageCopyBuffer(GetDevice(), *source));
701                     DAWN_TRY_CONTEXT(ValidateCanUseAs(source->buffer, wgpu::BufferUsage::CopySrc),
702                                      "validating source %s usage.", source->buffer);
703 
704                     DAWN_TRY(ValidateImageCopyTexture(GetDevice(), *destination, *copySize));
705                     DAWN_TRY_CONTEXT(
706                         ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst),
707                         "validating destination %s usage.", destination->texture);
708                     DAWN_TRY(ValidateTextureSampleCountInBufferCopyCommands(destination->texture));
709 
710                     DAWN_TRY(ValidateLinearToDepthStencilCopyRestrictions(*destination));
711                     // We validate texture copy range before validating linear texture data,
712                     // because in the latter we divide copyExtent.width by blockWidth and
713                     // copyExtent.height by blockHeight while the divisibility conditions are
714                     // checked in validating texture copy range.
715                     DAWN_TRY(ValidateTextureCopyRange(GetDevice(), *destination, *copySize));
716                 }
717                 const TexelBlockInfo& blockInfo =
718                     destination->texture->GetFormat().GetAspectInfo(destination->aspect).block;
719                 if (GetDevice()->IsValidationEnabled()) {
720                     DAWN_TRY(ValidateLinearTextureCopyOffset(
721                         source->layout, blockInfo,
722                         destination->texture->GetFormat().HasDepthOrStencil()));
723                     DAWN_TRY(ValidateLinearTextureData(source->layout, source->buffer->GetSize(),
724                                                        blockInfo, *copySize));
725 
726                     mTopLevelBuffers.insert(source->buffer);
727                     mTopLevelTextures.insert(destination->texture);
728                 }
729 
730                 TextureDataLayout srcLayout = source->layout;
731                 ApplyDefaultTextureDataLayoutOptions(&srcLayout, blockInfo, *copySize);
732 
733                 CopyBufferToTextureCmd* copy =
734                     allocator->Allocate<CopyBufferToTextureCmd>(Command::CopyBufferToTexture);
735                 copy->source.buffer = source->buffer;
736                 copy->source.offset = srcLayout.offset;
737                 copy->source.bytesPerRow = srcLayout.bytesPerRow;
738                 copy->source.rowsPerImage = srcLayout.rowsPerImage;
739                 copy->destination.texture = destination->texture;
740                 copy->destination.origin = destination->origin;
741                 copy->destination.mipLevel = destination->mipLevel;
742                 copy->destination.aspect =
743                     ConvertAspect(destination->texture->GetFormat(), destination->aspect);
744                 copy->copySize = *copySize;
745 
746                 return {};
747             },
748             "encoding %s.CopyBufferToTexture(%s, %s, %s).", this, source->buffer,
749             destination->texture, copySize);
750     }
751 
APICopyTextureToBuffer(const ImageCopyTexture * source,const ImageCopyBuffer * destination,const Extent3D * copySize)752     void CommandEncoder::APICopyTextureToBuffer(const ImageCopyTexture* source,
753                                                 const ImageCopyBuffer* destination,
754                                                 const Extent3D* copySize) {
755         mEncodingContext.TryEncode(
756             this,
757             [&](CommandAllocator* allocator) -> MaybeError {
758                 if (GetDevice()->IsValidationEnabled()) {
759                     DAWN_TRY(ValidateImageCopyTexture(GetDevice(), *source, *copySize));
760                     DAWN_TRY_CONTEXT(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc),
761                                      "validating source %s usage.", source->texture);
762                     DAWN_TRY(ValidateTextureSampleCountInBufferCopyCommands(source->texture));
763                     DAWN_TRY(ValidateTextureDepthStencilToBufferCopyRestrictions(*source));
764 
765                     DAWN_TRY(ValidateImageCopyBuffer(GetDevice(), *destination));
766                     DAWN_TRY_CONTEXT(
767                         ValidateCanUseAs(destination->buffer, wgpu::BufferUsage::CopyDst),
768                         "validating destination %s usage.", destination->buffer);
769 
770                     // We validate texture copy range before validating linear texture data,
771                     // because in the latter we divide copyExtent.width by blockWidth and
772                     // copyExtent.height by blockHeight while the divisibility conditions are
773                     // checked in validating texture copy range.
774                     DAWN_TRY(ValidateTextureCopyRange(GetDevice(), *source, *copySize));
775                 }
776                 const TexelBlockInfo& blockInfo =
777                     source->texture->GetFormat().GetAspectInfo(source->aspect).block;
778                 if (GetDevice()->IsValidationEnabled()) {
779                     DAWN_TRY(ValidateLinearTextureCopyOffset(
780                         destination->layout, blockInfo,
781                         source->texture->GetFormat().HasDepthOrStencil()));
782                     DAWN_TRY(ValidateLinearTextureData(
783                         destination->layout, destination->buffer->GetSize(), blockInfo, *copySize));
784 
785                     mTopLevelTextures.insert(source->texture);
786                     mTopLevelBuffers.insert(destination->buffer);
787                 }
788 
789                 TextureDataLayout dstLayout = destination->layout;
790                 ApplyDefaultTextureDataLayoutOptions(&dstLayout, blockInfo, *copySize);
791 
792                 CopyTextureToBufferCmd* copy =
793                     allocator->Allocate<CopyTextureToBufferCmd>(Command::CopyTextureToBuffer);
794                 copy->source.texture = source->texture;
795                 copy->source.origin = source->origin;
796                 copy->source.mipLevel = source->mipLevel;
797                 copy->source.aspect = ConvertAspect(source->texture->GetFormat(), source->aspect);
798                 copy->destination.buffer = destination->buffer;
799                 copy->destination.offset = dstLayout.offset;
800                 copy->destination.bytesPerRow = dstLayout.bytesPerRow;
801                 copy->destination.rowsPerImage = dstLayout.rowsPerImage;
802                 copy->copySize = *copySize;
803 
804                 return {};
805             },
806             "encoding %s.CopyTextureToBuffer(%s, %s, %s).", this, source->texture,
807             destination->buffer, copySize);
808     }
809 
APICopyTextureToTexture(const ImageCopyTexture * source,const ImageCopyTexture * destination,const Extent3D * copySize)810     void CommandEncoder::APICopyTextureToTexture(const ImageCopyTexture* source,
811                                                  const ImageCopyTexture* destination,
812                                                  const Extent3D* copySize) {
813         APICopyTextureToTextureHelper<false>(source, destination, copySize);
814     }
815 
APICopyTextureToTextureInternal(const ImageCopyTexture * source,const ImageCopyTexture * destination,const Extent3D * copySize)816     void CommandEncoder::APICopyTextureToTextureInternal(const ImageCopyTexture* source,
817                                                          const ImageCopyTexture* destination,
818                                                          const Extent3D* copySize) {
819         APICopyTextureToTextureHelper<true>(source, destination, copySize);
820     }
821 
822     template <bool Internal>
APICopyTextureToTextureHelper(const ImageCopyTexture * source,const ImageCopyTexture * destination,const Extent3D * copySize)823     void CommandEncoder::APICopyTextureToTextureHelper(const ImageCopyTexture* source,
824                                                        const ImageCopyTexture* destination,
825                                                        const Extent3D* copySize) {
826         mEncodingContext.TryEncode(
827             this,
828             [&](CommandAllocator* allocator) -> MaybeError {
829                 if (GetDevice()->IsValidationEnabled()) {
830                     DAWN_TRY(GetDevice()->ValidateObject(source->texture));
831                     DAWN_TRY(GetDevice()->ValidateObject(destination->texture));
832 
833                     DAWN_TRY_CONTEXT(ValidateImageCopyTexture(GetDevice(), *source, *copySize),
834                                      "validating source %s.", source->texture);
835                     DAWN_TRY_CONTEXT(ValidateImageCopyTexture(GetDevice(), *destination, *copySize),
836                                      "validating destination %s.", destination->texture);
837 
838                     DAWN_TRY(
839                         ValidateTextureToTextureCopyRestrictions(*source, *destination, *copySize));
840 
841                     DAWN_TRY_CONTEXT(ValidateTextureCopyRange(GetDevice(), *source, *copySize),
842                                      "validating source %s copy range.", source->texture);
843                     DAWN_TRY_CONTEXT(ValidateTextureCopyRange(GetDevice(), *destination, *copySize),
844                                      "validating source %s copy range.", destination->texture);
845 
846                     // For internal usages (CopyToCopyInternal) we don't care if the user has added
847                     // CopySrc as a usage for this texture, but we will always add it internally.
848                     if (Internal) {
849                         DAWN_TRY(
850                             ValidateInternalCanUseAs(source->texture, wgpu::TextureUsage::CopySrc));
851                         DAWN_TRY(ValidateInternalCanUseAs(destination->texture,
852                                                           wgpu::TextureUsage::CopyDst));
853                     } else {
854                         DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc));
855                         DAWN_TRY(
856                             ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst));
857                     }
858 
859                     mTopLevelTextures.insert(source->texture);
860                     mTopLevelTextures.insert(destination->texture);
861                 }
862 
863                 CopyTextureToTextureCmd* copy =
864                     allocator->Allocate<CopyTextureToTextureCmd>(Command::CopyTextureToTexture);
865                 copy->source.texture = source->texture;
866                 copy->source.origin = source->origin;
867                 copy->source.mipLevel = source->mipLevel;
868                 copy->source.aspect = ConvertAspect(source->texture->GetFormat(), source->aspect);
869                 copy->destination.texture = destination->texture;
870                 copy->destination.origin = destination->origin;
871                 copy->destination.mipLevel = destination->mipLevel;
872                 copy->destination.aspect =
873                     ConvertAspect(destination->texture->GetFormat(), destination->aspect);
874                 copy->copySize = *copySize;
875 
876                 return {};
877             },
878             "encoding %s.CopyTextureToTexture(%s, %s, %s).", this, source->texture,
879             destination->texture, copySize);
880     }
881 
APIClearBuffer(BufferBase * buffer,uint64_t offset,uint64_t size)882     void CommandEncoder::APIClearBuffer(BufferBase* buffer, uint64_t offset, uint64_t size) {
883         mEncodingContext.TryEncode(
884             this,
885             [&](CommandAllocator* allocator) -> MaybeError {
886                 if (GetDevice()->IsValidationEnabled()) {
887                     DAWN_TRY(GetDevice()->ValidateObject(buffer));
888 
889                     uint64_t bufferSize = buffer->GetSize();
890                     DAWN_INVALID_IF(offset > bufferSize,
891                                     "Buffer offset (%u) is larger than the size (%u) of %s.",
892                                     offset, bufferSize, buffer);
893 
894                     uint64_t remainingSize = bufferSize - offset;
895                     if (size == wgpu::kWholeSize) {
896                         size = remainingSize;
897                     } else {
898                         DAWN_INVALID_IF(size > remainingSize,
899                                         "Buffer range (offset: %u, size: %u) doesn't fit in "
900                                         "the size (%u) of %s.",
901                                         offset, size, bufferSize, buffer);
902                     }
903 
904                     DAWN_TRY_CONTEXT(ValidateCanUseAs(buffer, wgpu::BufferUsage::CopyDst),
905                                      "validating buffer %s usage.", buffer);
906 
907                     // Size must be a multiple of 4 bytes on macOS.
908                     DAWN_INVALID_IF(size % 4 != 0, "Fill size (%u) is not a multiple of 4 bytes.",
909                                     size);
910 
911                     // Offset must be multiples of 4 bytes on macOS.
912                     DAWN_INVALID_IF(offset % 4 != 0, "Offset (%u) is not a multiple of 4 bytes,",
913                                     offset);
914 
915                     mTopLevelBuffers.insert(buffer);
916                 } else {
917                     if (size == wgpu::kWholeSize) {
918                         DAWN_ASSERT(buffer->GetSize() >= offset);
919                         size = buffer->GetSize() - offset;
920                     }
921                 }
922 
923                 ClearBufferCmd* cmd = allocator->Allocate<ClearBufferCmd>(Command::ClearBuffer);
924                 cmd->buffer = buffer;
925                 cmd->offset = offset;
926                 cmd->size = size;
927 
928                 return {};
929             },
930             "encoding %s.ClearBuffer(%s, %u, %u).", this, buffer, offset, size);
931     }
932 
APIInjectValidationError(const char * message)933     void CommandEncoder::APIInjectValidationError(const char* message) {
934         if (mEncodingContext.CheckCurrentEncoder(this)) {
935             mEncodingContext.HandleError(DAWN_VALIDATION_ERROR(message));
936         }
937     }
938 
APIInsertDebugMarker(const char * groupLabel)939     void CommandEncoder::APIInsertDebugMarker(const char* groupLabel) {
940         mEncodingContext.TryEncode(
941             this,
942             [&](CommandAllocator* allocator) -> MaybeError {
943                 InsertDebugMarkerCmd* cmd =
944                     allocator->Allocate<InsertDebugMarkerCmd>(Command::InsertDebugMarker);
945                 cmd->length = strlen(groupLabel);
946 
947                 char* label = allocator->AllocateData<char>(cmd->length + 1);
948                 memcpy(label, groupLabel, cmd->length + 1);
949 
950                 return {};
951             },
952             "encoding %s.InsertDebugMarker(\"%s\").", this, groupLabel);
953     }
954 
APIPopDebugGroup()955     void CommandEncoder::APIPopDebugGroup() {
956         mEncodingContext.TryEncode(
957             this,
958             [&](CommandAllocator* allocator) -> MaybeError {
959                 if (GetDevice()->IsValidationEnabled()) {
960                     DAWN_INVALID_IF(
961                         mDebugGroupStackSize == 0,
962                         "PopDebugGroup called when no debug groups are currently pushed.");
963                 }
964                 allocator->Allocate<PopDebugGroupCmd>(Command::PopDebugGroup);
965                 mDebugGroupStackSize--;
966                 mEncodingContext.PopDebugGroupLabel();
967 
968                 return {};
969             },
970             "encoding %s.PopDebugGroup().", this);
971     }
972 
APIPushDebugGroup(const char * groupLabel)973     void CommandEncoder::APIPushDebugGroup(const char* groupLabel) {
974         mEncodingContext.TryEncode(
975             this,
976             [&](CommandAllocator* allocator) -> MaybeError {
977                 PushDebugGroupCmd* cmd =
978                     allocator->Allocate<PushDebugGroupCmd>(Command::PushDebugGroup);
979                 cmd->length = strlen(groupLabel);
980 
981                 char* label = allocator->AllocateData<char>(cmd->length + 1);
982                 memcpy(label, groupLabel, cmd->length + 1);
983 
984                 mDebugGroupStackSize++;
985                 mEncodingContext.PushDebugGroupLabel(groupLabel);
986 
987                 return {};
988             },
989             "encoding %s.PushDebugGroup(\"%s\").", this, groupLabel);
990     }
991 
APIResolveQuerySet(QuerySetBase * querySet,uint32_t firstQuery,uint32_t queryCount,BufferBase * destination,uint64_t destinationOffset)992     void CommandEncoder::APIResolveQuerySet(QuerySetBase* querySet,
993                                             uint32_t firstQuery,
994                                             uint32_t queryCount,
995                                             BufferBase* destination,
996                                             uint64_t destinationOffset) {
997         mEncodingContext.TryEncode(
998             this,
999             [&](CommandAllocator* allocator) -> MaybeError {
1000                 if (GetDevice()->IsValidationEnabled()) {
1001                     DAWN_TRY(GetDevice()->ValidateObject(querySet));
1002                     DAWN_TRY(GetDevice()->ValidateObject(destination));
1003 
1004                     DAWN_TRY(ValidateQuerySetResolve(querySet, firstQuery, queryCount, destination,
1005                                                      destinationOffset));
1006 
1007                     DAWN_TRY(ValidateCanUseAs(destination, wgpu::BufferUsage::QueryResolve));
1008 
1009                     TrackUsedQuerySet(querySet);
1010                     mTopLevelBuffers.insert(destination);
1011                 }
1012 
1013                 ResolveQuerySetCmd* cmd =
1014                     allocator->Allocate<ResolveQuerySetCmd>(Command::ResolveQuerySet);
1015                 cmd->querySet = querySet;
1016                 cmd->firstQuery = firstQuery;
1017                 cmd->queryCount = queryCount;
1018                 cmd->destination = destination;
1019                 cmd->destinationOffset = destinationOffset;
1020 
1021                 // Encode internal compute pipeline for timestamp query
1022                 if (querySet->GetQueryType() == wgpu::QueryType::Timestamp) {
1023                     DAWN_TRY(EncodeTimestampsToNanosecondsConversion(
1024                         this, querySet, firstQuery, queryCount, destination, destinationOffset));
1025                 }
1026 
1027                 return {};
1028             },
1029             "encoding %s.ResolveQuerySet(%s, %u, %u, %s, %u).", this, querySet, firstQuery,
1030             queryCount, destination, destinationOffset);
1031     }
1032 
APIWriteBuffer(BufferBase * buffer,uint64_t bufferOffset,const uint8_t * data,uint64_t size)1033     void CommandEncoder::APIWriteBuffer(BufferBase* buffer,
1034                                         uint64_t bufferOffset,
1035                                         const uint8_t* data,
1036                                         uint64_t size) {
1037         mEncodingContext.TryEncode(
1038             this,
1039             [&](CommandAllocator* allocator) -> MaybeError {
1040                 if (GetDevice()->IsValidationEnabled()) {
1041                     DAWN_TRY(ValidateWriteBuffer(GetDevice(), buffer, bufferOffset, size));
1042                 }
1043 
1044                 WriteBufferCmd* cmd = allocator->Allocate<WriteBufferCmd>(Command::WriteBuffer);
1045                 cmd->buffer = buffer;
1046                 cmd->offset = bufferOffset;
1047                 cmd->size = size;
1048 
1049                 uint8_t* inlinedData = allocator->AllocateData<uint8_t>(size);
1050                 memcpy(inlinedData, data, size);
1051 
1052                 mTopLevelBuffers.insert(buffer);
1053 
1054                 return {};
1055             },
1056             "encoding %s.WriteBuffer(%s, %u, ..., %u).", this, buffer, bufferOffset, size);
1057     }
1058 
APIWriteTimestamp(QuerySetBase * querySet,uint32_t queryIndex)1059     void CommandEncoder::APIWriteTimestamp(QuerySetBase* querySet, uint32_t queryIndex) {
1060         mEncodingContext.TryEncode(
1061             this,
1062             [&](CommandAllocator* allocator) -> MaybeError {
1063                 if (GetDevice()->IsValidationEnabled()) {
1064                     DAWN_TRY(GetDevice()->ValidateObject(querySet));
1065                     DAWN_TRY(ValidateTimestampQuery(querySet, queryIndex));
1066                 }
1067 
1068                 TrackQueryAvailability(querySet, queryIndex);
1069 
1070                 WriteTimestampCmd* cmd =
1071                     allocator->Allocate<WriteTimestampCmd>(Command::WriteTimestamp);
1072                 cmd->querySet = querySet;
1073                 cmd->queryIndex = queryIndex;
1074 
1075                 return {};
1076             },
1077             "encoding %s.WriteTimestamp(%s, %u).", this, querySet, queryIndex);
1078     }
1079 
APIFinish(const CommandBufferDescriptor * descriptor)1080     CommandBufferBase* CommandEncoder::APIFinish(const CommandBufferDescriptor* descriptor) {
1081         Ref<CommandBufferBase> commandBuffer;
1082         if (GetDevice()->ConsumedError(FinishInternal(descriptor), &commandBuffer)) {
1083             return CommandBufferBase::MakeError(GetDevice());
1084         }
1085         ASSERT(!IsError());
1086         return commandBuffer.Detach();
1087     }
1088 
FinishInternal(const CommandBufferDescriptor * descriptor)1089     ResultOrError<Ref<CommandBufferBase>> CommandEncoder::FinishInternal(
1090         const CommandBufferDescriptor* descriptor) {
1091         DeviceBase* device = GetDevice();
1092 
1093         // Even if mEncodingContext.Finish() validation fails, calling it will mutate the internal
1094         // state of the encoding context. The internal state is set to finished, and subsequent
1095         // calls to encode commands will generate errors.
1096         DAWN_TRY(mEncodingContext.Finish());
1097         DAWN_TRY(device->ValidateIsAlive());
1098 
1099         if (device->IsValidationEnabled()) {
1100             DAWN_TRY(ValidateFinish());
1101         }
1102 
1103         const CommandBufferDescriptor defaultDescriptor = {};
1104         if (descriptor == nullptr) {
1105             descriptor = &defaultDescriptor;
1106         }
1107 
1108         return device->CreateCommandBuffer(this, descriptor);
1109     }
1110 
1111     // Implementation of the command buffer validation that can be precomputed before submit
ValidateFinish() const1112     MaybeError CommandEncoder::ValidateFinish() const {
1113         TRACE_EVENT0(GetDevice()->GetPlatform(), Validation, "CommandEncoder::ValidateFinish");
1114         DAWN_TRY(GetDevice()->ValidateObject(this));
1115 
1116         for (const RenderPassResourceUsage& passUsage : mEncodingContext.GetRenderPassUsages()) {
1117             DAWN_TRY_CONTEXT(ValidateSyncScopeResourceUsage(passUsage),
1118                              "validating render pass usage.");
1119         }
1120 
1121         for (const ComputePassResourceUsage& passUsage : mEncodingContext.GetComputePassUsages()) {
1122             for (const SyncScopeResourceUsage& scope : passUsage.dispatchUsages) {
1123                 DAWN_TRY_CONTEXT(ValidateSyncScopeResourceUsage(scope),
1124                                  "validating compute pass usage.");
1125             }
1126         }
1127 
1128         DAWN_INVALID_IF(
1129             mDebugGroupStackSize != 0,
1130             "PushDebugGroup called %u time(s) without a corresponding PopDebugGroup prior to "
1131             "calling Finish.",
1132             mDebugGroupStackSize);
1133 
1134         return {};
1135     }
1136 
1137 }  // namespace dawn_native
1138