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, ¶ms, 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