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/QuerySet.h"
29 #include "dawn_native/RenderPassEncoder.h"
30 #include "dawn_native/RenderPipeline.h"
31 #include "dawn_native/ValidationUtils_autogen.h"
32 #include "dawn_platform/DawnPlatform.h"
33 #include "dawn_platform/tracing/TraceEvent.h"
34 
35 #include <cmath>
36 #include <map>
37 
38 namespace dawn_native {
39 
40     namespace {
41 
ValidateB2BCopyAlignment(uint64_t dataSize,uint64_t srcOffset,uint64_t dstOffset)42         MaybeError ValidateB2BCopyAlignment(uint64_t dataSize,
43                                             uint64_t srcOffset,
44                                             uint64_t dstOffset) {
45             // Copy size must be a multiple of 4 bytes on macOS.
46             if (dataSize % 4 != 0) {
47                 return DAWN_VALIDATION_ERROR("Copy size must be a multiple of 4 bytes");
48             }
49 
50             // SourceOffset and destinationOffset must be multiples of 4 bytes on macOS.
51             if (srcOffset % 4 != 0 || dstOffset % 4 != 0) {
52                 return DAWN_VALIDATION_ERROR(
53                     "Source offset and destination offset must be multiples of 4 bytes");
54             }
55 
56             return {};
57         }
58 
ValidateTextureSampleCountInBufferCopyCommands(const TextureBase * texture)59         MaybeError ValidateTextureSampleCountInBufferCopyCommands(const TextureBase* texture) {
60             if (texture->GetSampleCount() > 1) {
61                 return DAWN_VALIDATION_ERROR(
62                     "The sample count of textures must be 1 when copying between buffers and "
63                     "textures");
64             }
65 
66             return {};
67         }
68 
ValidateLinearTextureCopyOffset(const TextureDataLayout & layout,const TexelBlockInfo & blockInfo)69         MaybeError ValidateLinearTextureCopyOffset(const TextureDataLayout& layout,
70                                                    const TexelBlockInfo& blockInfo) {
71             if (layout.offset % blockInfo.byteSize != 0) {
72                 return DAWN_VALIDATION_ERROR(
73                     "offset must be a multiple of the texel block byte size.");
74             }
75             return {};
76         }
77 
ValidateTextureDepthStencilToBufferCopyRestrictions(const TextureCopyView & src)78         MaybeError ValidateTextureDepthStencilToBufferCopyRestrictions(const TextureCopyView& src) {
79             Aspect aspectUsed;
80             DAWN_TRY_ASSIGN(aspectUsed, SingleAspectUsedByTextureCopyView(src));
81             if (aspectUsed == Aspect::Depth) {
82                 switch (src.texture->GetFormat().format) {
83                     case wgpu::TextureFormat::Depth24Plus:
84                     case wgpu::TextureFormat::Depth24PlusStencil8:
85                         return DAWN_VALIDATION_ERROR(
86                             "The depth aspect of depth24plus texture cannot be selected in a "
87                             "texture to buffer copy");
88                         break;
89                     case wgpu::TextureFormat::Depth32Float:
90                         break;
91 
92                     default:
93                         UNREACHABLE();
94                 }
95             }
96 
97             return {};
98         }
99 
ValidateAttachmentArrayLayersAndLevelCount(const TextureViewBase * attachment)100         MaybeError ValidateAttachmentArrayLayersAndLevelCount(const TextureViewBase* attachment) {
101             // Currently we do not support layered rendering.
102             if (attachment->GetLayerCount() > 1) {
103                 return DAWN_VALIDATION_ERROR(
104                     "The layer count of the texture view used as attachment cannot be greater than "
105                     "1");
106             }
107 
108             if (attachment->GetLevelCount() > 1) {
109                 return DAWN_VALIDATION_ERROR(
110                     "The mipmap level count of the texture view used as attachment cannot be "
111                     "greater than 1");
112             }
113 
114             return {};
115         }
116 
ValidateOrSetAttachmentSize(const TextureViewBase * attachment,uint32_t * width,uint32_t * height)117         MaybeError ValidateOrSetAttachmentSize(const TextureViewBase* attachment,
118                                                uint32_t* width,
119                                                uint32_t* height) {
120             const Extent3D& attachmentSize =
121                 attachment->GetTexture()->GetMipLevelVirtualSize(attachment->GetBaseMipLevel());
122 
123             if (*width == 0) {
124                 DAWN_ASSERT(*height == 0);
125                 *width = attachmentSize.width;
126                 *height = attachmentSize.height;
127                 DAWN_ASSERT(*width != 0 && *height != 0);
128             } else if (*width != attachmentSize.width || *height != attachmentSize.height) {
129                 return DAWN_VALIDATION_ERROR("Attachment size mismatch");
130             }
131 
132             return {};
133         }
134 
ValidateOrSetColorAttachmentSampleCount(const TextureViewBase * colorAttachment,uint32_t * sampleCount)135         MaybeError ValidateOrSetColorAttachmentSampleCount(const TextureViewBase* colorAttachment,
136                                                            uint32_t* sampleCount) {
137             if (*sampleCount == 0) {
138                 *sampleCount = colorAttachment->GetTexture()->GetSampleCount();
139                 DAWN_ASSERT(*sampleCount != 0);
140             } else if (*sampleCount != colorAttachment->GetTexture()->GetSampleCount()) {
141                 return DAWN_VALIDATION_ERROR("Color attachment sample counts mismatch");
142             }
143 
144             return {};
145         }
146 
ValidateResolveTarget(const DeviceBase * device,const RenderPassColorAttachmentDescriptor & colorAttachment)147         MaybeError ValidateResolveTarget(
148             const DeviceBase* device,
149             const RenderPassColorAttachmentDescriptor& colorAttachment) {
150             if (colorAttachment.resolveTarget == nullptr) {
151                 return {};
152             }
153 
154             const TextureViewBase* resolveTarget = colorAttachment.resolveTarget;
155             const TextureViewBase* attachment = colorAttachment.attachment;
156             DAWN_TRY(device->ValidateObject(colorAttachment.resolveTarget));
157 
158             if (!attachment->GetTexture()->IsMultisampledTexture()) {
159                 return DAWN_VALIDATION_ERROR(
160                     "Cannot set resolve target when the sample count of the color attachment is 1");
161             }
162 
163             if (resolveTarget->GetTexture()->IsMultisampledTexture()) {
164                 return DAWN_VALIDATION_ERROR("Cannot use multisampled texture as resolve target");
165             }
166 
167             if (resolveTarget->GetLayerCount() > 1) {
168                 return DAWN_VALIDATION_ERROR(
169                     "The array layer count of the resolve target must be 1");
170             }
171 
172             if (resolveTarget->GetLevelCount() > 1) {
173                 return DAWN_VALIDATION_ERROR("The mip level count of the resolve target must be 1");
174             }
175 
176             uint32_t colorAttachmentBaseMipLevel = attachment->GetBaseMipLevel();
177             const Extent3D& colorTextureSize = attachment->GetTexture()->GetSize();
178             uint32_t colorAttachmentWidth = colorTextureSize.width >> colorAttachmentBaseMipLevel;
179             uint32_t colorAttachmentHeight = colorTextureSize.height >> colorAttachmentBaseMipLevel;
180 
181             uint32_t resolveTargetBaseMipLevel = resolveTarget->GetBaseMipLevel();
182             const Extent3D& resolveTextureSize = resolveTarget->GetTexture()->GetSize();
183             uint32_t resolveTargetWidth = resolveTextureSize.width >> resolveTargetBaseMipLevel;
184             uint32_t resolveTargetHeight = resolveTextureSize.height >> resolveTargetBaseMipLevel;
185             if (colorAttachmentWidth != resolveTargetWidth ||
186                 colorAttachmentHeight != resolveTargetHeight) {
187                 return DAWN_VALIDATION_ERROR(
188                     "The size of the resolve target must be the same as the color attachment");
189             }
190 
191             wgpu::TextureFormat resolveTargetFormat = resolveTarget->GetFormat().format;
192             if (resolveTargetFormat != attachment->GetFormat().format) {
193                 return DAWN_VALIDATION_ERROR(
194                     "The format of the resolve target must be the same as the color attachment");
195             }
196 
197             return {};
198         }
199 
ValidateRenderPassColorAttachment(const DeviceBase * device,const RenderPassColorAttachmentDescriptor & colorAttachment,uint32_t * width,uint32_t * height,uint32_t * sampleCount)200         MaybeError ValidateRenderPassColorAttachment(
201             const DeviceBase* device,
202             const RenderPassColorAttachmentDescriptor& colorAttachment,
203             uint32_t* width,
204             uint32_t* height,
205             uint32_t* sampleCount) {
206             DAWN_TRY(device->ValidateObject(colorAttachment.attachment));
207 
208             const TextureViewBase* attachment = colorAttachment.attachment;
209             if (!(attachment->GetAspects() & Aspect::Color) ||
210                 !attachment->GetFormat().isRenderable) {
211                 return DAWN_VALIDATION_ERROR(
212                     "The format of the texture view used as color attachment is not color "
213                     "renderable");
214             }
215 
216             DAWN_TRY(ValidateLoadOp(colorAttachment.loadOp));
217             DAWN_TRY(ValidateStoreOp(colorAttachment.storeOp));
218 
219             if (colorAttachment.loadOp == wgpu::LoadOp::Clear) {
220                 if (std::isnan(colorAttachment.clearColor.r) ||
221                     std::isnan(colorAttachment.clearColor.g) ||
222                     std::isnan(colorAttachment.clearColor.b) ||
223                     std::isnan(colorAttachment.clearColor.a)) {
224                     return DAWN_VALIDATION_ERROR("Color clear value cannot contain NaN");
225                 }
226             }
227 
228             DAWN_TRY(ValidateOrSetColorAttachmentSampleCount(attachment, sampleCount));
229 
230             DAWN_TRY(ValidateResolveTarget(device, colorAttachment));
231 
232             DAWN_TRY(ValidateAttachmentArrayLayersAndLevelCount(attachment));
233             DAWN_TRY(ValidateOrSetAttachmentSize(attachment, width, height));
234 
235             return {};
236         }
237 
ValidateRenderPassDepthStencilAttachment(const DeviceBase * device,const RenderPassDepthStencilAttachmentDescriptor * depthStencilAttachment,uint32_t * width,uint32_t * height,uint32_t * sampleCount)238         MaybeError ValidateRenderPassDepthStencilAttachment(
239             const DeviceBase* device,
240             const RenderPassDepthStencilAttachmentDescriptor* depthStencilAttachment,
241             uint32_t* width,
242             uint32_t* height,
243             uint32_t* sampleCount) {
244             DAWN_ASSERT(depthStencilAttachment != nullptr);
245 
246             DAWN_TRY(device->ValidateObject(depthStencilAttachment->attachment));
247 
248             const TextureViewBase* attachment = depthStencilAttachment->attachment;
249             if ((attachment->GetAspects() & (Aspect::Depth | Aspect::Stencil)) == Aspect::None ||
250                 !attachment->GetFormat().isRenderable) {
251                 return DAWN_VALIDATION_ERROR(
252                     "The format of the texture view used as depth stencil attachment is not a "
253                     "depth stencil format");
254             }
255 
256             DAWN_TRY(ValidateLoadOp(depthStencilAttachment->depthLoadOp));
257             DAWN_TRY(ValidateLoadOp(depthStencilAttachment->stencilLoadOp));
258             DAWN_TRY(ValidateStoreOp(depthStencilAttachment->depthStoreOp));
259             DAWN_TRY(ValidateStoreOp(depthStencilAttachment->stencilStoreOp));
260 
261             if (attachment->GetAspects() == (Aspect::Depth | Aspect::Stencil) &&
262                 depthStencilAttachment->depthReadOnly != depthStencilAttachment->stencilReadOnly) {
263                 return DAWN_VALIDATION_ERROR(
264                     "depthReadOnly and stencilReadOnly must be the same when texture aspect is "
265                     "'all'");
266             }
267 
268             if (depthStencilAttachment->depthReadOnly &&
269                 (depthStencilAttachment->depthLoadOp != wgpu::LoadOp::Load ||
270                  depthStencilAttachment->depthStoreOp != wgpu::StoreOp::Store)) {
271                 return DAWN_VALIDATION_ERROR(
272                     "depthLoadOp must be load and depthStoreOp must be store when depthReadOnly "
273                     "is true.");
274             }
275 
276             if (depthStencilAttachment->stencilReadOnly &&
277                 (depthStencilAttachment->stencilLoadOp != wgpu::LoadOp::Load ||
278                  depthStencilAttachment->stencilStoreOp != wgpu::StoreOp::Store)) {
279                 return DAWN_VALIDATION_ERROR(
280                     "stencilLoadOp must be load and stencilStoreOp must be store when "
281                     "stencilReadOnly "
282                     "is true.");
283             }
284 
285             if (depthStencilAttachment->depthLoadOp == wgpu::LoadOp::Clear &&
286                 std::isnan(depthStencilAttachment->clearDepth)) {
287                 return DAWN_VALIDATION_ERROR("Depth clear value cannot be NaN");
288             }
289 
290             // *sampleCount == 0 must only happen when there is no color attachment. In that case we
291             // do not need to validate the sample count of the depth stencil attachment.
292             const uint32_t depthStencilSampleCount = attachment->GetTexture()->GetSampleCount();
293             if (*sampleCount != 0) {
294                 if (depthStencilSampleCount != *sampleCount) {
295                     return DAWN_VALIDATION_ERROR("Depth stencil attachment sample counts mismatch");
296                 }
297             } else {
298                 *sampleCount = depthStencilSampleCount;
299             }
300 
301             DAWN_TRY(ValidateAttachmentArrayLayersAndLevelCount(attachment));
302             DAWN_TRY(ValidateOrSetAttachmentSize(attachment, width, height));
303 
304             return {};
305         }
306 
ValidateRenderPassDescriptor(const DeviceBase * device,const RenderPassDescriptor * descriptor,uint32_t * width,uint32_t * height,uint32_t * sampleCount)307         MaybeError ValidateRenderPassDescriptor(const DeviceBase* device,
308                                                 const RenderPassDescriptor* descriptor,
309                                                 uint32_t* width,
310                                                 uint32_t* height,
311                                                 uint32_t* sampleCount) {
312             if (descriptor->colorAttachmentCount > kMaxColorAttachments) {
313                 return DAWN_VALIDATION_ERROR("Setting color attachments out of bounds");
314             }
315 
316             for (uint32_t i = 0; i < descriptor->colorAttachmentCount; ++i) {
317                 DAWN_TRY(ValidateRenderPassColorAttachment(device, descriptor->colorAttachments[i],
318                                                            width, height, sampleCount));
319             }
320 
321             if (descriptor->depthStencilAttachment != nullptr) {
322                 DAWN_TRY(ValidateRenderPassDepthStencilAttachment(
323                     device, descriptor->depthStencilAttachment, width, height, sampleCount));
324             }
325 
326             if (descriptor->occlusionQuerySet != nullptr) {
327                 return DAWN_VALIDATION_ERROR("occlusionQuerySet not implemented");
328             }
329 
330             if (descriptor->colorAttachmentCount == 0 &&
331                 descriptor->depthStencilAttachment == nullptr) {
332                 return DAWN_VALIDATION_ERROR("Cannot use render pass with no attachments.");
333             }
334 
335             return {};
336         }
337 
ValidateComputePassDescriptor(const DeviceBase * device,const ComputePassDescriptor * descriptor)338         MaybeError ValidateComputePassDescriptor(const DeviceBase* device,
339                                                  const ComputePassDescriptor* descriptor) {
340             return {};
341         }
342 
ValidateQuerySetResolve(const QuerySetBase * querySet,uint32_t firstQuery,uint32_t queryCount,const BufferBase * destination,uint64_t destinationOffset)343         MaybeError ValidateQuerySetResolve(const QuerySetBase* querySet,
344                                            uint32_t firstQuery,
345                                            uint32_t queryCount,
346                                            const BufferBase* destination,
347                                            uint64_t destinationOffset) {
348             if (firstQuery >= querySet->GetQueryCount()) {
349                 return DAWN_VALIDATION_ERROR("Query index out of bounds");
350             }
351 
352             if (queryCount > querySet->GetQueryCount() - firstQuery) {
353                 return DAWN_VALIDATION_ERROR(
354                     "The sum of firstQuery and queryCount exceeds the number of queries in query "
355                     "set");
356             }
357 
358             // TODO(hao.x.li@intel.com): Validate that the queries between [firstQuery, firstQuery +
359             // queryCount - 1] must be available(written by query operations).
360 
361             // The destinationOffset must be a multiple of 8 bytes on D3D12 and Vulkan
362             if (destinationOffset % 8 != 0) {
363                 return DAWN_VALIDATION_ERROR(
364                     "The alignment offset into the destination buffer must be a multiple of 8 "
365                     "bytes");
366             }
367 
368             uint64_t bufferSize = destination->GetSize();
369             // The destination buffer must have enough storage, from destination offset, to contain
370             // the result of resolved queries
371             bool fitsInBuffer = destinationOffset <= bufferSize &&
372                                 (static_cast<uint64_t>(queryCount) * sizeof(uint64_t) <=
373                                  (bufferSize - destinationOffset));
374             if (!fitsInBuffer) {
375                 return DAWN_VALIDATION_ERROR("The resolved query data would overflow the buffer");
376             }
377 
378             return {};
379         }
380 
381     }  // namespace
382 
CommandEncoder(DeviceBase * device,const CommandEncoderDescriptor *)383     CommandEncoder::CommandEncoder(DeviceBase* device, const CommandEncoderDescriptor*)
384         : ObjectBase(device), mEncodingContext(device, this) {
385     }
386 
AcquireResourceUsages()387     CommandBufferResourceUsage CommandEncoder::AcquireResourceUsages() {
388         return CommandBufferResourceUsage{mEncodingContext.AcquirePassUsages(),
389                                           std::move(mTopLevelBuffers), std::move(mTopLevelTextures),
390                                           std::move(mUsedQuerySets)};
391     }
392 
AcquireCommands()393     CommandIterator CommandEncoder::AcquireCommands() {
394         return mEncodingContext.AcquireCommands();
395     }
396 
TrackUsedQuerySet(QuerySetBase * querySet)397     void CommandEncoder::TrackUsedQuerySet(QuerySetBase* querySet) {
398         mUsedQuerySets.insert(querySet);
399     }
400 
TrackUsedQueryIndex(QuerySetBase * querySet,uint32_t queryIndex)401     void CommandEncoder::TrackUsedQueryIndex(QuerySetBase* querySet, uint32_t queryIndex) {
402         UsedQueryMap::iterator it = mUsedQueryIndices.find(querySet);
403         if (it != mUsedQueryIndices.end()) {
404             // Record index on existing query set
405             std::vector<bool>& queryIndices = it->second;
406             queryIndices[queryIndex] = 1;
407         } else {
408             // Record index on new query set
409             std::vector<bool> queryIndices(querySet->GetQueryCount(), 0);
410             queryIndices[queryIndex] = 1;
411             mUsedQueryIndices.insert({querySet, std::move(queryIndices)});
412         }
413     }
414 
GetUsedQueryIndices() const415     const UsedQueryMap& CommandEncoder::GetUsedQueryIndices() const {
416         return mUsedQueryIndices;
417     }
418 
419     // Implementation of the API's command recording methods
420 
BeginComputePass(const ComputePassDescriptor * descriptor)421     ComputePassEncoder* CommandEncoder::BeginComputePass(const ComputePassDescriptor* descriptor) {
422         DeviceBase* device = GetDevice();
423 
424         bool success =
425             mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
426                 DAWN_TRY(ValidateComputePassDescriptor(device, descriptor));
427 
428                 allocator->Allocate<BeginComputePassCmd>(Command::BeginComputePass);
429 
430                 return {};
431             });
432 
433         if (success) {
434             ComputePassEncoder* passEncoder =
435                 new ComputePassEncoder(device, this, &mEncodingContext);
436             mEncodingContext.EnterPass(passEncoder);
437             return passEncoder;
438         }
439 
440         return ComputePassEncoder::MakeError(device, this, &mEncodingContext);
441     }
442 
BeginRenderPass(const RenderPassDescriptor * descriptor)443     RenderPassEncoder* CommandEncoder::BeginRenderPass(const RenderPassDescriptor* descriptor) {
444         DeviceBase* device = GetDevice();
445 
446         PassResourceUsageTracker usageTracker(PassType::Render);
447 
448         uint32_t width = 0;
449         uint32_t height = 0;
450         bool success =
451             mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
452                 uint32_t sampleCount = 0;
453 
454                 DAWN_TRY(ValidateRenderPassDescriptor(device, descriptor, &width, &height,
455                                                       &sampleCount));
456 
457                 ASSERT(width > 0 && height > 0 && sampleCount > 0);
458 
459                 BeginRenderPassCmd* cmd =
460                     allocator->Allocate<BeginRenderPassCmd>(Command::BeginRenderPass);
461 
462                 cmd->attachmentState = device->GetOrCreateAttachmentState(descriptor);
463 
464                 for (ColorAttachmentIndex index :
465                      IterateBitSet(cmd->attachmentState->GetColorAttachmentsMask())) {
466                     uint8_t i = static_cast<uint8_t>(index);
467                     TextureViewBase* view = descriptor->colorAttachments[i].attachment;
468                     TextureViewBase* resolveTarget = descriptor->colorAttachments[i].resolveTarget;
469 
470                     cmd->colorAttachments[index].view = view;
471                     cmd->colorAttachments[index].resolveTarget = resolveTarget;
472                     cmd->colorAttachments[index].loadOp = descriptor->colorAttachments[i].loadOp;
473                     cmd->colorAttachments[index].storeOp = descriptor->colorAttachments[i].storeOp;
474                     cmd->colorAttachments[index].clearColor =
475                         descriptor->colorAttachments[i].clearColor;
476 
477                     usageTracker.TextureViewUsedAs(view, wgpu::TextureUsage::RenderAttachment);
478 
479                     if (resolveTarget != nullptr) {
480                         usageTracker.TextureViewUsedAs(resolveTarget,
481                                                        wgpu::TextureUsage::RenderAttachment);
482                     }
483                 }
484 
485                 if (cmd->attachmentState->HasDepthStencilAttachment()) {
486                     TextureViewBase* view = descriptor->depthStencilAttachment->attachment;
487 
488                     cmd->depthStencilAttachment.view = view;
489                     cmd->depthStencilAttachment.clearDepth =
490                         descriptor->depthStencilAttachment->clearDepth;
491                     cmd->depthStencilAttachment.clearStencil =
492                         descriptor->depthStencilAttachment->clearStencil;
493                     cmd->depthStencilAttachment.depthLoadOp =
494                         descriptor->depthStencilAttachment->depthLoadOp;
495                     cmd->depthStencilAttachment.depthStoreOp =
496                         descriptor->depthStencilAttachment->depthStoreOp;
497                     cmd->depthStencilAttachment.stencilLoadOp =
498                         descriptor->depthStencilAttachment->stencilLoadOp;
499                     cmd->depthStencilAttachment.stencilStoreOp =
500                         descriptor->depthStencilAttachment->stencilStoreOp;
501 
502                     usageTracker.TextureViewUsedAs(view, wgpu::TextureUsage::RenderAttachment);
503                 }
504 
505                 cmd->width = width;
506                 cmd->height = height;
507 
508                 return {};
509             });
510 
511         if (success) {
512             RenderPassEncoder* passEncoder = new RenderPassEncoder(
513                 device, this, &mEncodingContext, std::move(usageTracker), width, height);
514             mEncodingContext.EnterPass(passEncoder);
515             return passEncoder;
516         }
517 
518         return RenderPassEncoder::MakeError(device, this, &mEncodingContext);
519     }
520 
CopyBufferToBuffer(BufferBase * source,uint64_t sourceOffset,BufferBase * destination,uint64_t destinationOffset,uint64_t size)521     void CommandEncoder::CopyBufferToBuffer(BufferBase* source,
522                                             uint64_t sourceOffset,
523                                             BufferBase* destination,
524                                             uint64_t destinationOffset,
525                                             uint64_t size) {
526         mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
527             if (GetDevice()->IsValidationEnabled()) {
528                 DAWN_TRY(GetDevice()->ValidateObject(source));
529                 DAWN_TRY(GetDevice()->ValidateObject(destination));
530 
531                 if (source == destination) {
532                     return DAWN_VALIDATION_ERROR(
533                         "Source and destination cannot be the same buffer.");
534                 }
535 
536                 DAWN_TRY(ValidateCopySizeFitsInBuffer(source, sourceOffset, size));
537                 DAWN_TRY(ValidateCopySizeFitsInBuffer(destination, destinationOffset, size));
538                 DAWN_TRY(ValidateB2BCopyAlignment(size, sourceOffset, destinationOffset));
539 
540                 DAWN_TRY(ValidateCanUseAs(source, wgpu::BufferUsage::CopySrc));
541                 DAWN_TRY(ValidateCanUseAs(destination, wgpu::BufferUsage::CopyDst));
542 
543                 mTopLevelBuffers.insert(source);
544                 mTopLevelBuffers.insert(destination);
545             }
546 
547             // Skip noop copies. Some backends validation rules disallow them.
548             if (size != 0) {
549                 CopyBufferToBufferCmd* copy =
550                     allocator->Allocate<CopyBufferToBufferCmd>(Command::CopyBufferToBuffer);
551                 copy->source = source;
552                 copy->sourceOffset = sourceOffset;
553                 copy->destination = destination;
554                 copy->destinationOffset = destinationOffset;
555                 copy->size = size;
556             }
557 
558             return {};
559         });
560     }
561 
CopyBufferToTexture(const BufferCopyView * source,const TextureCopyView * destination,const Extent3D * copySize)562     void CommandEncoder::CopyBufferToTexture(const BufferCopyView* source,
563                                              const TextureCopyView* destination,
564                                              const Extent3D* copySize) {
565         mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
566             if (GetDevice()->IsValidationEnabled()) {
567                 DAWN_TRY(ValidateBufferCopyView(GetDevice(), *source));
568                 DAWN_TRY(ValidateCanUseAs(source->buffer, wgpu::BufferUsage::CopySrc));
569 
570                 DAWN_TRY(ValidateTextureCopyView(GetDevice(), *destination, *copySize));
571                 DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst));
572                 DAWN_TRY(ValidateTextureSampleCountInBufferCopyCommands(destination->texture));
573 
574                 DAWN_TRY(ValidateLinearToDepthStencilCopyRestrictions(*destination));
575                 // We validate texture copy range before validating linear texture data,
576                 // because in the latter we divide copyExtent.width by blockWidth and
577                 // copyExtent.height by blockHeight while the divisibility conditions are
578                 // checked in validating texture copy range.
579                 DAWN_TRY(ValidateTextureCopyRange(*destination, *copySize));
580             }
581             const TexelBlockInfo& blockInfo =
582                 destination->texture->GetFormat().GetAspectInfo(destination->aspect).block;
583             TextureDataLayout srcLayout = FixUpDeprecatedTextureDataLayoutOptions(
584                 GetDevice(), source->layout, blockInfo, *copySize);
585             if (GetDevice()->IsValidationEnabled()) {
586                 DAWN_TRY(ValidateLinearTextureCopyOffset(srcLayout, blockInfo));
587                 DAWN_TRY(ValidateLinearTextureData(srcLayout, source->buffer->GetSize(), blockInfo,
588                                                    *copySize));
589 
590                 mTopLevelBuffers.insert(source->buffer);
591                 mTopLevelTextures.insert(destination->texture);
592             }
593 
594             ApplyDefaultTextureDataLayoutOptions(&srcLayout, blockInfo, *copySize);
595 
596             // Skip noop copies.
597             if (copySize->width != 0 && copySize->height != 0 && copySize->depth != 0) {
598                 // Record the copy command.
599                 CopyBufferToTextureCmd* copy =
600                     allocator->Allocate<CopyBufferToTextureCmd>(Command::CopyBufferToTexture);
601                 copy->source.buffer = source->buffer;
602                 copy->source.offset = srcLayout.offset;
603                 copy->source.bytesPerRow = srcLayout.bytesPerRow;
604                 copy->source.rowsPerImage = srcLayout.rowsPerImage;
605                 copy->destination.texture = destination->texture;
606                 copy->destination.origin = destination->origin;
607                 copy->destination.mipLevel = destination->mipLevel;
608                 copy->destination.aspect =
609                     ConvertAspect(destination->texture->GetFormat(), destination->aspect);
610                 copy->copySize = *copySize;
611             }
612 
613             return {};
614         });
615     }
616 
CopyTextureToBuffer(const TextureCopyView * source,const BufferCopyView * destination,const Extent3D * copySize)617     void CommandEncoder::CopyTextureToBuffer(const TextureCopyView* source,
618                                              const BufferCopyView* destination,
619                                              const Extent3D* copySize) {
620         mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
621             if (GetDevice()->IsValidationEnabled()) {
622                 DAWN_TRY(ValidateTextureCopyView(GetDevice(), *source, *copySize));
623                 DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc));
624                 DAWN_TRY(ValidateTextureSampleCountInBufferCopyCommands(source->texture));
625                 DAWN_TRY(ValidateTextureDepthStencilToBufferCopyRestrictions(*source));
626 
627                 DAWN_TRY(ValidateBufferCopyView(GetDevice(), *destination));
628                 DAWN_TRY(ValidateCanUseAs(destination->buffer, wgpu::BufferUsage::CopyDst));
629 
630                 // We validate texture copy range before validating linear texture data,
631                 // because in the latter we divide copyExtent.width by blockWidth and
632                 // copyExtent.height by blockHeight while the divisibility conditions are
633                 // checked in validating texture copy range.
634                 DAWN_TRY(ValidateTextureCopyRange(*source, *copySize));
635             }
636             const TexelBlockInfo& blockInfo =
637                 source->texture->GetFormat().GetAspectInfo(source->aspect).block;
638             TextureDataLayout dstLayout = FixUpDeprecatedTextureDataLayoutOptions(
639                 GetDevice(), destination->layout, blockInfo, *copySize);
640             if (GetDevice()->IsValidationEnabled()) {
641                 DAWN_TRY(ValidateLinearTextureCopyOffset(dstLayout, blockInfo));
642                 DAWN_TRY(ValidateLinearTextureData(dstLayout, destination->buffer->GetSize(),
643                                                    blockInfo, *copySize));
644 
645                 mTopLevelTextures.insert(source->texture);
646                 mTopLevelBuffers.insert(destination->buffer);
647             }
648 
649             ApplyDefaultTextureDataLayoutOptions(&dstLayout, blockInfo, *copySize);
650 
651             // Skip noop copies.
652             if (copySize->width != 0 && copySize->height != 0 && copySize->depth != 0) {
653                 // Record the copy command.
654                 CopyTextureToBufferCmd* copy =
655                     allocator->Allocate<CopyTextureToBufferCmd>(Command::CopyTextureToBuffer);
656                 copy->source.texture = source->texture;
657                 copy->source.origin = source->origin;
658                 copy->source.mipLevel = source->mipLevel;
659                 copy->source.aspect = ConvertAspect(source->texture->GetFormat(), source->aspect);
660                 copy->destination.buffer = destination->buffer;
661                 copy->destination.offset = dstLayout.offset;
662                 copy->destination.bytesPerRow = dstLayout.bytesPerRow;
663                 copy->destination.rowsPerImage = dstLayout.rowsPerImage;
664                 copy->copySize = *copySize;
665             }
666 
667             return {};
668         });
669     }
670 
CopyTextureToTexture(const TextureCopyView * source,const TextureCopyView * destination,const Extent3D * copySize)671     void CommandEncoder::CopyTextureToTexture(const TextureCopyView* source,
672                                               const TextureCopyView* destination,
673                                               const Extent3D* copySize) {
674         mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
675             if (GetDevice()->IsValidationEnabled()) {
676                 DAWN_TRY(GetDevice()->ValidateObject(source->texture));
677                 DAWN_TRY(GetDevice()->ValidateObject(destination->texture));
678 
679                 DAWN_TRY(ValidateTextureCopyView(GetDevice(), *source, *copySize));
680                 DAWN_TRY(ValidateTextureCopyView(GetDevice(), *destination, *copySize));
681 
682                 DAWN_TRY(
683                     ValidateTextureToTextureCopyRestrictions(*source, *destination, *copySize));
684 
685                 DAWN_TRY(ValidateTextureCopyRange(*source, *copySize));
686                 DAWN_TRY(ValidateTextureCopyRange(*destination, *copySize));
687 
688                 DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc));
689                 DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst));
690 
691                 mTopLevelTextures.insert(source->texture);
692                 mTopLevelTextures.insert(destination->texture);
693             }
694 
695             // Skip noop copies.
696             if (copySize->width != 0 && copySize->height != 0 && copySize->depth != 0) {
697                 CopyTextureToTextureCmd* copy =
698                     allocator->Allocate<CopyTextureToTextureCmd>(Command::CopyTextureToTexture);
699                 copy->source.texture = source->texture;
700                 copy->source.origin = source->origin;
701                 copy->source.mipLevel = source->mipLevel;
702                 copy->source.aspect = ConvertAspect(source->texture->GetFormat(), source->aspect);
703                 copy->destination.texture = destination->texture;
704                 copy->destination.origin = destination->origin;
705                 copy->destination.mipLevel = destination->mipLevel;
706                 copy->destination.aspect =
707                     ConvertAspect(destination->texture->GetFormat(), destination->aspect);
708                 copy->copySize = *copySize;
709             }
710 
711             return {};
712         });
713     }
714 
InsertDebugMarker(const char * groupLabel)715     void CommandEncoder::InsertDebugMarker(const char* groupLabel) {
716         mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
717             InsertDebugMarkerCmd* cmd =
718                 allocator->Allocate<InsertDebugMarkerCmd>(Command::InsertDebugMarker);
719             cmd->length = strlen(groupLabel);
720 
721             char* label = allocator->AllocateData<char>(cmd->length + 1);
722             memcpy(label, groupLabel, cmd->length + 1);
723 
724             return {};
725         });
726     }
727 
PopDebugGroup()728     void CommandEncoder::PopDebugGroup() {
729         mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
730             allocator->Allocate<PopDebugGroupCmd>(Command::PopDebugGroup);
731 
732             return {};
733         });
734     }
735 
PushDebugGroup(const char * groupLabel)736     void CommandEncoder::PushDebugGroup(const char* groupLabel) {
737         mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
738             PushDebugGroupCmd* cmd =
739                 allocator->Allocate<PushDebugGroupCmd>(Command::PushDebugGroup);
740             cmd->length = strlen(groupLabel);
741 
742             char* label = allocator->AllocateData<char>(cmd->length + 1);
743             memcpy(label, groupLabel, cmd->length + 1);
744 
745             return {};
746         });
747     }
748 
ResolveQuerySet(QuerySetBase * querySet,uint32_t firstQuery,uint32_t queryCount,BufferBase * destination,uint64_t destinationOffset)749     void CommandEncoder::ResolveQuerySet(QuerySetBase* querySet,
750                                          uint32_t firstQuery,
751                                          uint32_t queryCount,
752                                          BufferBase* destination,
753                                          uint64_t destinationOffset) {
754         mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
755             if (GetDevice()->IsValidationEnabled()) {
756                 DAWN_TRY(GetDevice()->ValidateObject(querySet));
757                 DAWN_TRY(GetDevice()->ValidateObject(destination));
758 
759                 DAWN_TRY(ValidateQuerySetResolve(querySet, firstQuery, queryCount, destination,
760                                                  destinationOffset));
761 
762                 DAWN_TRY(ValidateCanUseAs(destination, wgpu::BufferUsage::QueryResolve));
763 
764                 TrackUsedQuerySet(querySet);
765                 mTopLevelBuffers.insert(destination);
766             }
767 
768             ResolveQuerySetCmd* cmd =
769                 allocator->Allocate<ResolveQuerySetCmd>(Command::ResolveQuerySet);
770             cmd->querySet = querySet;
771             cmd->firstQuery = firstQuery;
772             cmd->queryCount = queryCount;
773             cmd->destination = destination;
774             cmd->destinationOffset = destinationOffset;
775 
776             return {};
777         });
778     }
779 
WriteTimestamp(QuerySetBase * querySet,uint32_t queryIndex)780     void CommandEncoder::WriteTimestamp(QuerySetBase* querySet, uint32_t queryIndex) {
781         mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
782             if (GetDevice()->IsValidationEnabled()) {
783                 DAWN_TRY(GetDevice()->ValidateObject(querySet));
784                 DAWN_TRY(ValidateTimestampQuery(querySet, queryIndex, GetUsedQueryIndices()));
785                 TrackUsedQuerySet(querySet);
786             }
787 
788             TrackUsedQueryIndex(querySet, queryIndex);
789 
790             WriteTimestampCmd* cmd =
791                 allocator->Allocate<WriteTimestampCmd>(Command::WriteTimestamp);
792             cmd->querySet = querySet;
793             cmd->queryIndex = queryIndex;
794 
795             return {};
796         });
797     }
798 
Finish(const CommandBufferDescriptor * descriptor)799     CommandBufferBase* CommandEncoder::Finish(const CommandBufferDescriptor* descriptor) {
800         DeviceBase* device = GetDevice();
801         // Even if mEncodingContext.Finish() validation fails, calling it will mutate the internal
802         // state of the encoding context. The internal state is set to finished, and subsequent
803         // calls to encode commands will generate errors.
804         if (device->ConsumedError(mEncodingContext.Finish()) ||
805             device->ConsumedError(device->ValidateIsAlive()) ||
806             (device->IsValidationEnabled() &&
807              device->ConsumedError(ValidateFinish(mEncodingContext.GetIterator(),
808                                                   mEncodingContext.GetPassUsages())))) {
809             return CommandBufferBase::MakeError(device);
810         }
811         ASSERT(!IsError());
812         return device->CreateCommandBuffer(this, descriptor);
813     }
814 
815     // Implementation of the command buffer validation that can be precomputed before submit
ValidateFinish(CommandIterator * commands,const PerPassUsages & perPassUsages) const816     MaybeError CommandEncoder::ValidateFinish(CommandIterator* commands,
817                                               const PerPassUsages& perPassUsages) const {
818         TRACE_EVENT0(GetDevice()->GetPlatform(), Validation, "CommandEncoder::ValidateFinish");
819         DAWN_TRY(GetDevice()->ValidateObject(this));
820 
821         for (const PassResourceUsage& passUsage : perPassUsages) {
822             DAWN_TRY(ValidatePassResourceUsage(passUsage));
823         }
824 
825         uint64_t debugGroupStackSize = 0;
826 
827         commands->Reset();
828         Command type;
829         while (commands->NextCommandId(&type)) {
830             switch (type) {
831                 case Command::BeginComputePass: {
832                     commands->NextCommand<BeginComputePassCmd>();
833                     DAWN_TRY(ValidateComputePass(commands));
834                     break;
835                 }
836 
837                 case Command::BeginRenderPass: {
838                     const BeginRenderPassCmd* cmd = commands->NextCommand<BeginRenderPassCmd>();
839                     DAWN_TRY(ValidateRenderPass(commands, cmd));
840                     break;
841                 }
842 
843                 case Command::CopyBufferToBuffer: {
844                     commands->NextCommand<CopyBufferToBufferCmd>();
845                     break;
846                 }
847 
848                 case Command::CopyBufferToTexture: {
849                     commands->NextCommand<CopyBufferToTextureCmd>();
850                     break;
851                 }
852 
853                 case Command::CopyTextureToBuffer: {
854                     commands->NextCommand<CopyTextureToBufferCmd>();
855                     break;
856                 }
857 
858                 case Command::CopyTextureToTexture: {
859                     commands->NextCommand<CopyTextureToTextureCmd>();
860                     break;
861                 }
862 
863                 case Command::InsertDebugMarker: {
864                     const InsertDebugMarkerCmd* cmd = commands->NextCommand<InsertDebugMarkerCmd>();
865                     commands->NextData<char>(cmd->length + 1);
866                     break;
867                 }
868 
869                 case Command::PopDebugGroup: {
870                     commands->NextCommand<PopDebugGroupCmd>();
871                     DAWN_TRY(ValidateCanPopDebugGroup(debugGroupStackSize));
872                     debugGroupStackSize--;
873                     break;
874                 }
875 
876                 case Command::PushDebugGroup: {
877                     const PushDebugGroupCmd* cmd = commands->NextCommand<PushDebugGroupCmd>();
878                     commands->NextData<char>(cmd->length + 1);
879                     debugGroupStackSize++;
880                     break;
881                 }
882 
883                 case Command::ResolveQuerySet: {
884                     commands->NextCommand<ResolveQuerySetCmd>();
885                     break;
886                 }
887 
888                 case Command::WriteTimestamp: {
889                     commands->NextCommand<WriteTimestampCmd>();
890                     break;
891                 }
892                 default:
893                     return DAWN_VALIDATION_ERROR("Command disallowed outside of a pass");
894             }
895         }
896 
897         DAWN_TRY(ValidateFinalDebugGroupStackSize(debugGroupStackSize));
898 
899         return {};
900     }
901 
902 }  // namespace dawn_native
903