Skip validation during command recording when skip_validation is on
This patch factors resource usage tracking so it is separate from
command validation, allowing the bulk of command validation to be
completely skipped.
In DrawCallPerfRun/Vulkan_DynamicPipeline_DynamicBindGroup, disabling
validation cuts roughly 74 nanoseconds (20%) of CPU time, per draw.
In DrawCallPerfRun/Vulkan_DynamicBindGroup, disabling validation
cuts roughly 35 nanoseconds (17%) of CPU time, per draw.
In DrawCallPerfRun/Vulkan_MultipleBindGroups, disabling validation
cuts roughly 45 nanoseconds (14%) of CPU time, per draw.
Bug: dawn:271
Change-Id: I517b85840ba18c6a554b83f34a1d0aef1a8c56a6
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/13520
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn_native/CommandEncoder.cpp b/src/dawn_native/CommandEncoder.cpp
index 5af8ba0..e0de3a2 100644
--- a/src/dawn_native/CommandEncoder.cpp
+++ b/src/dawn_native/CommandEncoder.cpp
@@ -24,7 +24,6 @@
#include "dawn_native/ComputePassEncoder.h"
#include "dawn_native/Device.h"
#include "dawn_native/ErrorData.h"
-#include "dawn_native/PassResourceUsageTracker.h"
#include "dawn_native/RenderPassEncoder.h"
#include "dawn_native/RenderPipeline.h"
#include "dawn_platform/DawnPlatform.h"
@@ -243,7 +242,7 @@
return {};
}
- MaybeError ValidateCanUseAs(BufferBase* buffer, wgpu::BufferUsage usage) {
+ MaybeError ValidateCanUseAs(const BufferBase* buffer, wgpu::BufferUsage usage) {
ASSERT(wgpu::HasZeroOrOneBits(usage));
if (!(buffer->GetUsage() & usage)) {
return DAWN_VALIDATION_ERROR("buffer doesn't have the required usage.");
@@ -252,7 +251,7 @@
return {};
}
- MaybeError ValidateCanUseAs(TextureBase* texture, wgpu::TextureUsage usage) {
+ MaybeError ValidateCanUseAs(const TextureBase* texture, wgpu::TextureUsage usage) {
ASSERT(wgpu::HasZeroOrOneBits(usage));
if (!(texture->GetUsage() & usage)) {
return DAWN_VALIDATION_ERROR("texture doesn't have the required usage.");
@@ -467,9 +466,9 @@
}
CommandBufferResourceUsage CommandEncoder::AcquireResourceUsages() {
- ASSERT(!mWereResourceUsagesAcquired);
- mWereResourceUsagesAcquired = true;
- return std::move(mResourceUsages);
+ return CommandBufferResourceUsage{mEncodingContext.AcquirePassUsages(),
+ std::move(mTopLevelBuffers),
+ std::move(mTopLevelTextures)};
}
CommandIterator CommandEncoder::AcquireCommands() {
@@ -503,6 +502,7 @@
RenderPassEncoder* CommandEncoder::BeginRenderPass(const RenderPassDescriptor* descriptor) {
DeviceBase* device = GetDevice();
+ PassResourceUsageTracker usageTracker;
bool success =
mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
uint32_t width = 0;
@@ -520,18 +520,29 @@
cmd->attachmentState = device->GetOrCreateAttachmentState(descriptor);
for (uint32_t i : IterateBitSet(cmd->attachmentState->GetColorAttachmentsMask())) {
- cmd->colorAttachments[i].view = descriptor->colorAttachments[i].attachment;
- cmd->colorAttachments[i].resolveTarget =
- descriptor->colorAttachments[i].resolveTarget;
+ TextureViewBase* view = descriptor->colorAttachments[i].attachment;
+ TextureViewBase* resolveTarget = descriptor->colorAttachments[i].resolveTarget;
+
+ cmd->colorAttachments[i].view = view;
+ cmd->colorAttachments[i].resolveTarget = resolveTarget;
cmd->colorAttachments[i].loadOp = descriptor->colorAttachments[i].loadOp;
cmd->colorAttachments[i].storeOp = descriptor->colorAttachments[i].storeOp;
cmd->colorAttachments[i].clearColor =
descriptor->colorAttachments[i].clearColor;
+
+ usageTracker.TextureUsedAs(view->GetTexture(),
+ wgpu::TextureUsage::OutputAttachment);
+
+ if (resolveTarget != nullptr) {
+ usageTracker.TextureUsedAs(resolveTarget->GetTexture(),
+ wgpu::TextureUsage::OutputAttachment);
+ }
}
if (cmd->attachmentState->HasDepthStencilAttachment()) {
- cmd->depthStencilAttachment.view =
- descriptor->depthStencilAttachment->attachment;
+ TextureViewBase* view = descriptor->depthStencilAttachment->attachment;
+
+ cmd->depthStencilAttachment.view = view;
cmd->depthStencilAttachment.clearDepth =
descriptor->depthStencilAttachment->clearDepth;
cmd->depthStencilAttachment.clearStencil =
@@ -544,6 +555,9 @@
descriptor->depthStencilAttachment->stencilLoadOp;
cmd->depthStencilAttachment.stencilStoreOp =
descriptor->depthStencilAttachment->stencilStoreOp;
+
+ usageTracker.TextureUsedAs(view->GetTexture(),
+ wgpu::TextureUsage::OutputAttachment);
}
cmd->width = width;
@@ -553,7 +567,8 @@
});
if (success) {
- RenderPassEncoder* passEncoder = new RenderPassEncoder(device, this, &mEncodingContext);
+ RenderPassEncoder* passEncoder =
+ new RenderPassEncoder(device, this, &mEncodingContext, std::move(usageTracker));
mEncodingContext.EnterPass(passEncoder);
return passEncoder;
}
@@ -578,6 +593,10 @@
copy->destinationOffset = destinationOffset;
copy->size = size;
+ if (GetDevice()->IsValidationEnabled()) {
+ mTopLevelBuffers.insert(source);
+ mTopLevelBuffers.insert(destination);
+ }
return {};
});
}
@@ -610,6 +629,10 @@
copy->source.imageHeight = source->imageHeight;
}
+ if (GetDevice()->IsValidationEnabled()) {
+ mTopLevelBuffers.insert(source->buffer);
+ mTopLevelTextures.insert(destination->texture);
+ }
return {};
});
}
@@ -642,6 +665,10 @@
copy->destination.imageHeight = destination->imageHeight;
}
+ if (GetDevice()->IsValidationEnabled()) {
+ mTopLevelTextures.insert(source->texture);
+ mTopLevelBuffers.insert(destination->buffer);
+ }
return {};
});
}
@@ -665,6 +692,10 @@
copy->destination.arrayLayer = destination->arrayLayer;
copy->copySize = *copySize;
+ if (GetDevice()->IsValidationEnabled()) {
+ mTopLevelTextures.insert(source->texture);
+ mTopLevelTextures.insert(destination->texture);
+ }
return {};
});
}
@@ -704,46 +735,49 @@
}
CommandBufferBase* CommandEncoder::Finish(const CommandBufferDescriptor* descriptor) {
- if (GetDevice()->ConsumedError(ValidateFinish(descriptor))) {
- // Even if finish validation fails, it is now invalid to call any encoding commands on
- // this object, so we set its state to finished.
- return CommandBufferBase::MakeError(GetDevice());
+ DeviceBase* device = GetDevice();
+ // Even if mEncodingContext.Finish() validation fails, calling it will mutate the internal
+ // state of the encoding context. The internal state is set to finished, and subsequent
+ // calls to encode commands will generate errors.
+ if (device->ConsumedError(mEncodingContext.Finish()) ||
+ (device->IsValidationEnabled() &&
+ device->ConsumedError(ValidateFinish(mEncodingContext.GetIterator(),
+ mEncodingContext.GetPassUsages())))) {
+ return CommandBufferBase::MakeError(device);
}
ASSERT(!IsError());
-
- return GetDevice()->CreateCommandBuffer(this, descriptor);
+ return device->CreateCommandBuffer(this, descriptor);
}
// Implementation of the command buffer validation that can be precomputed before submit
-
- MaybeError CommandEncoder::ValidateFinish(const CommandBufferDescriptor*) {
+ MaybeError CommandEncoder::ValidateFinish(CommandIterator* commands,
+ const PerPassUsages& perPassUsages) const {
TRACE_EVENT0(GetDevice()->GetPlatform(), Validation, "CommandEncoder::ValidateFinish");
DAWN_TRY(GetDevice()->ValidateObject(this));
- // Even if Finish() validation fails, calling it will mutate the internal state of the
- // encoding context. Subsequent calls to encode commands will generate errors.
- DAWN_TRY(mEncodingContext.Finish());
+ for (const PassResourceUsage& passUsage : perPassUsages) {
+ DAWN_TRY(ValidatePassResourceUsage(passUsage));
+ }
uint64_t debugGroupStackSize = 0;
- CommandIterator* commands = mEncodingContext.GetIterator();
commands->Reset();
-
Command type;
while (commands->NextCommandId(&type)) {
switch (type) {
case Command::BeginComputePass: {
commands->NextCommand<BeginComputePassCmd>();
- DAWN_TRY(ValidateComputePass(commands, &mResourceUsages.perPass));
+ DAWN_TRY(ValidateComputePass(commands));
} break;
case Command::BeginRenderPass: {
- BeginRenderPassCmd* cmd = commands->NextCommand<BeginRenderPassCmd>();
- DAWN_TRY(ValidateRenderPass(commands, cmd, &mResourceUsages.perPass));
+ const BeginRenderPassCmd* cmd = commands->NextCommand<BeginRenderPassCmd>();
+ DAWN_TRY(ValidateRenderPass(commands, cmd));
} break;
case Command::CopyBufferToBuffer: {
- CopyBufferToBufferCmd* copy = commands->NextCommand<CopyBufferToBufferCmd>();
+ const CopyBufferToBufferCmd* copy =
+ commands->NextCommand<CopyBufferToBufferCmd>();
DAWN_TRY(
ValidateCopySizeFitsInBuffer(copy->source, copy->sourceOffset, copy->size));
@@ -754,13 +788,11 @@
DAWN_TRY(ValidateCanUseAs(copy->source.Get(), wgpu::BufferUsage::CopySrc));
DAWN_TRY(ValidateCanUseAs(copy->destination.Get(), wgpu::BufferUsage::CopyDst));
-
- mResourceUsages.topLevelBuffers.insert(copy->source.Get());
- mResourceUsages.topLevelBuffers.insert(copy->destination.Get());
} break;
case Command::CopyBufferToTexture: {
- CopyBufferToTextureCmd* copy = commands->NextCommand<CopyBufferToTextureCmd>();
+ const CopyBufferToTextureCmd* copy =
+ commands->NextCommand<CopyBufferToTextureCmd>();
DAWN_TRY(
ValidateTextureSampleCountInCopyCommands(copy->destination.texture.Get()));
@@ -789,13 +821,11 @@
ValidateCanUseAs(copy->source.buffer.Get(), wgpu::BufferUsage::CopySrc));
DAWN_TRY(ValidateCanUseAs(copy->destination.texture.Get(),
wgpu::TextureUsage::CopyDst));
-
- mResourceUsages.topLevelBuffers.insert(copy->source.buffer.Get());
- mResourceUsages.topLevelTextures.insert(copy->destination.texture.Get());
} break;
case Command::CopyTextureToBuffer: {
- CopyTextureToBufferCmd* copy = commands->NextCommand<CopyTextureToBufferCmd>();
+ const CopyTextureToBufferCmd* copy =
+ commands->NextCommand<CopyTextureToBufferCmd>();
DAWN_TRY(ValidateTextureSampleCountInCopyCommands(copy->source.texture.Get()));
@@ -824,13 +854,10 @@
ValidateCanUseAs(copy->source.texture.Get(), wgpu::TextureUsage::CopySrc));
DAWN_TRY(ValidateCanUseAs(copy->destination.buffer.Get(),
wgpu::BufferUsage::CopyDst));
-
- mResourceUsages.topLevelTextures.insert(copy->source.texture.Get());
- mResourceUsages.topLevelBuffers.insert(copy->destination.buffer.Get());
} break;
case Command::CopyTextureToTexture: {
- CopyTextureToTextureCmd* copy =
+ const CopyTextureToTextureCmd* copy =
commands->NextCommand<CopyTextureToTextureCmd>();
DAWN_TRY(ValidateTextureToTextureCopyRestrictions(
@@ -852,13 +879,10 @@
ValidateCanUseAs(copy->source.texture.Get(), wgpu::TextureUsage::CopySrc));
DAWN_TRY(ValidateCanUseAs(copy->destination.texture.Get(),
wgpu::TextureUsage::CopyDst));
-
- mResourceUsages.topLevelTextures.insert(copy->source.texture.Get());
- mResourceUsages.topLevelTextures.insert(copy->destination.texture.Get());
} break;
case Command::InsertDebugMarker: {
- InsertDebugMarkerCmd* cmd = commands->NextCommand<InsertDebugMarkerCmd>();
+ const InsertDebugMarkerCmd* cmd = commands->NextCommand<InsertDebugMarkerCmd>();
commands->NextData<char>(cmd->length + 1);
} break;
@@ -869,7 +893,7 @@
} break;
case Command::PushDebugGroup: {
- PushDebugGroupCmd* cmd = commands->NextCommand<PushDebugGroupCmd>();
+ const PushDebugGroupCmd* cmd = commands->NextCommand<PushDebugGroupCmd>();
commands->NextData<char>(cmd->length + 1);
debugGroupStackSize++;
} break;