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/Buffer.cpp b/src/dawn_native/Buffer.cpp
index a44e3c2..c57d23a 100644
--- a/src/dawn_native/Buffer.cpp
+++ b/src/dawn_native/Buffer.cpp
@@ -116,7 +116,7 @@
mUsage(descriptor->usage),
mState(BufferState::Unmapped) {
// Add readonly storage usage if the buffer has a storage usage. The validation rules in
- // PassResourceUsageTracker::ValidateUsages will make sure we don't use both at the same
+ // ValidatePassResourceUsage will make sure we don't use both at the same
// time.
if (mUsage & wgpu::BufferUsage::Storage) {
mUsage |= kReadOnlyStorage;
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;
diff --git a/src/dawn_native/CommandEncoder.h b/src/dawn_native/CommandEncoder.h
index 406ff33..2c89c4b 100644
--- a/src/dawn_native/CommandEncoder.h
+++ b/src/dawn_native/CommandEncoder.h
@@ -61,12 +61,12 @@
CommandBufferBase* Finish(const CommandBufferDescriptor* descriptor);
private:
- MaybeError ValidateFinish(const CommandBufferDescriptor* descriptor);
+ MaybeError ValidateFinish(CommandIterator* commands,
+ const PerPassUsages& perPassUsages) const;
EncodingContext mEncodingContext;
-
- bool mWereResourceUsagesAcquired = false;
- CommandBufferResourceUsage mResourceUsages;
+ std::set<BufferBase*> mTopLevelBuffers;
+ std::set<TextureBase*> mTopLevelTextures;
};
} // namespace dawn_native
diff --git a/src/dawn_native/CommandValidation.cpp b/src/dawn_native/CommandValidation.cpp
index cdcb470..dc7a3cc 100644
--- a/src/dawn_native/CommandValidation.cpp
+++ b/src/dawn_native/CommandValidation.cpp
@@ -19,7 +19,7 @@
#include "dawn_native/Buffer.h"
#include "dawn_native/CommandBufferStateTracker.h"
#include "dawn_native/Commands.h"
-#include "dawn_native/PassResourceUsageTracker.h"
+#include "dawn_native/PassResourceUsage.h"
#include "dawn_native/RenderBundle.h"
#include "dawn_native/RenderPipeline.h"
@@ -27,47 +27,8 @@
namespace {
- void TrackBindGroupResourceUsage(BindGroupBase* group,
- PassResourceUsageTracker* usageTracker) {
- const auto& layoutInfo = group->GetLayout()->GetBindingInfo();
-
- for (uint32_t i : IterateBitSet(layoutInfo.mask)) {
- wgpu::BindingType type = layoutInfo.types[i];
-
- switch (type) {
- case wgpu::BindingType::UniformBuffer: {
- BufferBase* buffer = group->GetBindingAsBufferBinding(i).buffer;
- usageTracker->BufferUsedAs(buffer, wgpu::BufferUsage::Uniform);
- } break;
-
- case wgpu::BindingType::StorageBuffer: {
- BufferBase* buffer = group->GetBindingAsBufferBinding(i).buffer;
- usageTracker->BufferUsedAs(buffer, wgpu::BufferUsage::Storage);
- } break;
-
- case wgpu::BindingType::SampledTexture: {
- TextureBase* texture = group->GetBindingAsTextureView(i)->GetTexture();
- usageTracker->TextureUsedAs(texture, wgpu::TextureUsage::Sampled);
- } break;
-
- case wgpu::BindingType::ReadonlyStorageBuffer: {
- BufferBase* buffer = group->GetBindingAsBufferBinding(i).buffer;
- usageTracker->BufferUsedAs(buffer, kReadOnlyStorage);
- } break;
-
- case wgpu::BindingType::Sampler:
- break;
-
- case wgpu::BindingType::StorageTexture:
- UNREACHABLE();
- break;
- }
- }
- }
-
inline MaybeError ValidateRenderBundleCommand(CommandIterator* commands,
Command type,
- PassResourceUsageTracker* usageTracker,
CommandBufferStateTracker* commandBufferState,
const AttachmentState* attachmentState,
uint64_t* debugGroupStackSize,
@@ -84,17 +45,13 @@
} break;
case Command::DrawIndirect: {
- DrawIndirectCmd* cmd = commands->NextCommand<DrawIndirectCmd>();
+ commands->NextCommand<DrawIndirectCmd>();
DAWN_TRY(commandBufferState->ValidateCanDraw());
- usageTracker->BufferUsedAs(cmd->indirectBuffer.Get(),
- wgpu::BufferUsage::Indirect);
} break;
case Command::DrawIndexedIndirect: {
- DrawIndexedIndirectCmd* cmd = commands->NextCommand<DrawIndexedIndirectCmd>();
+ commands->NextCommand<DrawIndexedIndirectCmd>();
DAWN_TRY(commandBufferState->ValidateCanDrawIndexed());
- usageTracker->BufferUsedAs(cmd->indirectBuffer.Get(),
- wgpu::BufferUsage::Indirect);
} break;
case Command::InsertDebugMarker: {
@@ -130,21 +87,16 @@
commands->NextData<uint32_t>(cmd->dynamicOffsetCount);
}
- TrackBindGroupResourceUsage(cmd->group.Get(), usageTracker);
commandBufferState->SetBindGroup(cmd->index, cmd->group.Get());
} break;
case Command::SetIndexBuffer: {
- SetIndexBufferCmd* cmd = commands->NextCommand<SetIndexBufferCmd>();
-
- usageTracker->BufferUsedAs(cmd->buffer.Get(), wgpu::BufferUsage::Index);
+ commands->NextCommand<SetIndexBufferCmd>();
commandBufferState->SetIndexBuffer();
} break;
case Command::SetVertexBuffer: {
SetVertexBufferCmd* cmd = commands->NextCommand<SetVertexBufferCmd>();
-
- usageTracker->BufferUsedAs(cmd->buffer.Get(), wgpu::BufferUsage::Vertex);
commandBufferState->SetVertexBuffer(cmd->slot);
} break;
@@ -172,63 +124,31 @@
}
MaybeError ValidateRenderBundle(CommandIterator* commands,
- const AttachmentState* attachmentState,
- PassResourceUsage* resourceUsage) {
- PassResourceUsageTracker usageTracker;
+ const AttachmentState* attachmentState) {
CommandBufferStateTracker commandBufferState;
uint64_t debugGroupStackSize = 0;
Command type;
while (commands->NextCommandId(&type)) {
- DAWN_TRY(ValidateRenderBundleCommand(commands, type, &usageTracker, &commandBufferState,
+ DAWN_TRY(ValidateRenderBundleCommand(commands, type, &commandBufferState,
attachmentState, &debugGroupStackSize,
"Command disallowed inside a render bundle"));
}
DAWN_TRY(ValidateFinalDebugGroupStackSize(debugGroupStackSize));
- DAWN_TRY(usageTracker.ValidateRenderPassUsages());
- ASSERT(resourceUsage != nullptr);
- *resourceUsage = usageTracker.AcquireResourceUsage();
-
return {};
}
- MaybeError ValidateRenderPass(CommandIterator* commands,
- BeginRenderPassCmd* renderPass,
- std::vector<PassResourceUsage>* perPassResourceUsages) {
- PassResourceUsageTracker usageTracker;
+ MaybeError ValidateRenderPass(CommandIterator* commands, const BeginRenderPassCmd* renderPass) {
CommandBufferStateTracker commandBufferState;
uint64_t debugGroupStackSize = 0;
- // Track usage of the render pass attachments
- for (uint32_t i : IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
- RenderPassColorAttachmentInfo* colorAttachment = &renderPass->colorAttachments[i];
- TextureBase* texture = colorAttachment->view->GetTexture();
- usageTracker.TextureUsedAs(texture, wgpu::TextureUsage::OutputAttachment);
-
- TextureViewBase* resolveTarget = colorAttachment->resolveTarget.Get();
- if (resolveTarget != nullptr) {
- usageTracker.TextureUsedAs(resolveTarget->GetTexture(),
- wgpu::TextureUsage::OutputAttachment);
- }
- }
-
- if (renderPass->attachmentState->HasDepthStencilAttachment()) {
- TextureBase* texture = renderPass->depthStencilAttachment.view->GetTexture();
- usageTracker.TextureUsedAs(texture, wgpu::TextureUsage::OutputAttachment);
- }
-
Command type;
while (commands->NextCommandId(&type)) {
switch (type) {
case Command::EndRenderPass: {
commands->NextCommand<EndRenderPassCmd>();
-
DAWN_TRY(ValidateFinalDebugGroupStackSize(debugGroupStackSize));
- DAWN_TRY(usageTracker.ValidateRenderPassUsages());
- ASSERT(perPassResourceUsages != nullptr);
- perPassResourceUsages->push_back(usageTracker.AcquireResourceUsage());
-
return {};
} break;
@@ -241,15 +161,6 @@
return DAWN_VALIDATION_ERROR(
"Render bundle is not compatible with render pass");
}
-
- const PassResourceUsage& usages = bundles[i]->GetResourceUsage();
- for (uint32_t i = 0; i < usages.buffers.size(); ++i) {
- usageTracker.BufferUsedAs(usages.buffers[i], usages.bufferUsages[i]);
- }
-
- for (uint32_t i = 0; i < usages.textures.size(); ++i) {
- usageTracker.TextureUsedAs(usages.textures[i], usages.textureUsages[i]);
- }
}
if (cmd->count > 0) {
@@ -277,9 +188,8 @@
default:
DAWN_TRY(ValidateRenderBundleCommand(
- commands, type, &usageTracker, &commandBufferState,
- renderPass->attachmentState.Get(), &debugGroupStackSize,
- "Command disallowed inside a render pass"));
+ commands, type, &commandBufferState, renderPass->attachmentState.Get(),
+ &debugGroupStackSize, "Command disallowed inside a render pass"));
}
}
@@ -287,9 +197,7 @@
return DAWN_VALIDATION_ERROR("Unfinished render pass");
}
- MaybeError ValidateComputePass(CommandIterator* commands,
- std::vector<PassResourceUsage>* perPassResourceUsages) {
- PassResourceUsageTracker usageTracker;
+ MaybeError ValidateComputePass(CommandIterator* commands) {
CommandBufferStateTracker commandBufferState;
uint64_t debugGroupStackSize = 0;
@@ -298,11 +206,7 @@
switch (type) {
case Command::EndComputePass: {
commands->NextCommand<EndComputePassCmd>();
-
DAWN_TRY(ValidateFinalDebugGroupStackSize(debugGroupStackSize));
- DAWN_TRY(usageTracker.ValidateComputePassUsages());
- ASSERT(perPassResourceUsages != nullptr);
- perPassResourceUsages->push_back(usageTracker.AcquireResourceUsage());
return {};
} break;
@@ -312,10 +216,8 @@
} break;
case Command::DispatchIndirect: {
- DispatchIndirectCmd* cmd = commands->NextCommand<DispatchIndirectCmd>();
+ commands->NextCommand<DispatchIndirectCmd>();
DAWN_TRY(commandBufferState.ValidateCanDispatch());
- usageTracker.BufferUsedAs(cmd->indirectBuffer.Get(),
- wgpu::BufferUsage::Indirect);
} break;
case Command::InsertDebugMarker: {
@@ -346,8 +248,6 @@
if (cmd->dynamicOffsetCount > 0) {
commands->NextData<uint32_t>(cmd->dynamicOffsetCount);
}
-
- TrackBindGroupResourceUsage(cmd->group.Get(), &usageTracker);
commandBufferState.SetBindGroup(cmd->index, cmd->group.Get());
} break;
@@ -360,4 +260,46 @@
return DAWN_VALIDATION_ERROR("Unfinished compute pass");
}
+ // Performs the per-pass usage validation checks
+ // This will eventually need to differentiate between render and compute passes.
+ // It will be valid to use a buffer both as uniform and storage in the same compute pass.
+ MaybeError ValidatePassResourceUsage(const PassResourceUsage& pass) {
+ // Buffers can only be used as single-write or multiple read.
+ for (size_t i = 0; i < pass.buffers.size(); ++i) {
+ const BufferBase* buffer = pass.buffers[i];
+ wgpu::BufferUsage usage = pass.bufferUsages[i];
+
+ if (usage & ~buffer->GetUsage()) {
+ return DAWN_VALIDATION_ERROR("Buffer missing usage for the pass");
+ }
+
+ bool readOnly = (usage & kReadOnlyBufferUsages) == usage;
+ bool singleUse = wgpu::HasZeroOrOneBits(usage);
+
+ if (!readOnly && !singleUse) {
+ return DAWN_VALIDATION_ERROR(
+ "Buffer used as writable usage and another usage in pass");
+ }
+ }
+
+ // Textures can only be used as single-write or multiple read.
+ // TODO(cwallez@chromium.org): implement per-subresource tracking
+ for (size_t i = 0; i < pass.textures.size(); ++i) {
+ const TextureBase* texture = pass.textures[i];
+ wgpu::TextureUsage usage = pass.textureUsages[i];
+
+ if (usage & ~texture->GetUsage()) {
+ return DAWN_VALIDATION_ERROR("Texture missing usage for the pass");
+ }
+
+ // For textures the only read-only usage in a pass is Sampled, so checking the
+ // usage constraint simplifies to checking a single usage bit is set.
+ if (!wgpu::HasZeroOrOneBits(usage)) {
+ return DAWN_VALIDATION_ERROR("Texture used with more than one usage in pass");
+ }
+ }
+
+ return {};
+ }
+
} // namespace dawn_native
diff --git a/src/dawn_native/CommandValidation.h b/src/dawn_native/CommandValidation.h
index b5a1493..d649ce3 100644
--- a/src/dawn_native/CommandValidation.h
+++ b/src/dawn_native/CommandValidation.h
@@ -30,13 +30,11 @@
MaybeError ValidateFinalDebugGroupStackSize(uint64_t debugGroupStackSize);
MaybeError ValidateRenderBundle(CommandIterator* commands,
- const AttachmentState* attachmentState,
- PassResourceUsage* resourceUsage);
- MaybeError ValidateRenderPass(CommandIterator* commands,
- BeginRenderPassCmd* renderPass,
- std::vector<PassResourceUsage>* perPassResourceUsages);
- MaybeError ValidateComputePass(CommandIterator* commands,
- std::vector<PassResourceUsage>* perPassResourceUsages);
+ const AttachmentState* attachmentState);
+ MaybeError ValidateRenderPass(CommandIterator* commands, const BeginRenderPassCmd* renderPass);
+ MaybeError ValidateComputePass(CommandIterator* commands);
+
+ MaybeError ValidatePassResourceUsage(const PassResourceUsage& usage);
} // namespace dawn_native
diff --git a/src/dawn_native/ComputePassEncoder.cpp b/src/dawn_native/ComputePassEncoder.cpp
index 3c0f442..cd88c87 100644
--- a/src/dawn_native/ComputePassEncoder.cpp
+++ b/src/dawn_native/ComputePassEncoder.cpp
@@ -48,7 +48,7 @@
return {};
})) {
- mEncodingContext->ExitPass(this);
+ mEncodingContext->ExitPass(this, mUsageTracker.AcquireResourceUsage());
}
}
@@ -77,6 +77,8 @@
dispatch->indirectBuffer = indirectBuffer;
dispatch->indirectOffset = indirectOffset;
+ mUsageTracker.BufferUsedAs(indirectBuffer, wgpu::BufferUsage::Indirect);
+
return {};
});
}
diff --git a/src/dawn_native/EncodingContext.cpp b/src/dawn_native/EncodingContext.cpp
index ea156a6..b8be069 100644
--- a/src/dawn_native/EncodingContext.cpp
+++ b/src/dawn_native/EncodingContext.cpp
@@ -15,9 +15,11 @@
#include "dawn_native/EncodingContext.h"
#include "common/Assert.h"
+#include "dawn_native/CommandEncoder.h"
#include "dawn_native/Commands.h"
#include "dawn_native/Device.h"
#include "dawn_native/ErrorData.h"
+#include "dawn_native/RenderBundleEncoder.h"
namespace dawn_native {
@@ -32,17 +34,23 @@
}
CommandIterator EncodingContext::AcquireCommands() {
+ MoveToIterator();
ASSERT(!mWereCommandsAcquired);
mWereCommandsAcquired = true;
return std::move(mIterator);
}
CommandIterator* EncodingContext::GetIterator() {
+ MoveToIterator();
+ ASSERT(!mWereCommandsAcquired);
+ return &mIterator;
+ }
+
+ void EncodingContext::MoveToIterator() {
if (!mWasMovedToIterator) {
mIterator = std::move(mAllocator);
mWasMovedToIterator = true;
}
- return &mIterator;
}
void EncodingContext::HandleError(wgpu::ErrorType type, const char* message) {
@@ -66,13 +74,25 @@
mCurrentEncoder = passEncoder;
}
- void EncodingContext::ExitPass(const ObjectBase* passEncoder) {
+ void EncodingContext::ExitPass(const ObjectBase* passEncoder, PassResourceUsage passUsage) {
// Assert we're not at the top level.
ASSERT(mCurrentEncoder != mTopLevelEncoder);
// Assert the pass encoder is current.
ASSERT(mCurrentEncoder == passEncoder);
mCurrentEncoder = mTopLevelEncoder;
+ mPassUsages.push_back(std::move(passUsage));
+ }
+
+ const PerPassUsages& EncodingContext::GetPassUsages() const {
+ ASSERT(!mWerePassUsagesAcquired);
+ return mPassUsages;
+ }
+
+ PerPassUsages EncodingContext::AcquirePassUsages() {
+ ASSERT(!mWerePassUsagesAcquired);
+ mWerePassUsagesAcquired = true;
+ return std::move(mPassUsages);
}
MaybeError EncodingContext::Finish() {
diff --git a/src/dawn_native/EncodingContext.h b/src/dawn_native/EncodingContext.h
index ecb0505..c16d544 100644
--- a/src/dawn_native/EncodingContext.h
+++ b/src/dawn_native/EncodingContext.h
@@ -18,14 +18,15 @@
#include "dawn_native/CommandAllocator.h"
#include "dawn_native/Error.h"
#include "dawn_native/ErrorData.h"
+#include "dawn_native/PassResourceUsageTracker.h"
#include "dawn_native/dawn_platform.h"
#include <string>
namespace dawn_native {
- class ObjectBase;
class DeviceBase;
+ class ObjectBase;
// Base class for allocating/iterating commands.
// It performs error tracking as well as encoding state for render/compute passes.
@@ -54,7 +55,7 @@
}
template <typename EncodeFunction>
- inline bool TryEncode(const void* encoder, EncodeFunction&& encodeFunction) {
+ inline bool TryEncode(const ObjectBase* encoder, EncodeFunction&& encodeFunction) {
if (DAWN_UNLIKELY(encoder != mCurrentEncoder)) {
if (mCurrentEncoder != mTopLevelEncoder) {
// The top level encoder was used when a pass encoder was current.
@@ -72,11 +73,15 @@
// Functions to set current encoder state
void EnterPass(const ObjectBase* passEncoder);
- void ExitPass(const ObjectBase* passEncoder);
+ void ExitPass(const ObjectBase* passEncoder, PassResourceUsage passUsages);
MaybeError Finish();
+ const PerPassUsages& GetPassUsages() const;
+ PerPassUsages AcquirePassUsages();
+
private:
bool IsFinished() const;
+ void MoveToIterator();
DeviceBase* mDevice;
@@ -90,6 +95,9 @@
// CommandEncoder::Begin/EndPass.
const ObjectBase* mCurrentEncoder;
+ PerPassUsages mPassUsages;
+ bool mWerePassUsagesAcquired = false;
+
CommandAllocator mAllocator;
CommandIterator mIterator;
bool mWasMovedToIterator = false;
diff --git a/src/dawn_native/PassResourceUsage.h b/src/dawn_native/PassResourceUsage.h
index 226ad31..c2a2071 100644
--- a/src/dawn_native/PassResourceUsage.h
+++ b/src/dawn_native/PassResourceUsage.h
@@ -36,8 +36,10 @@
std::vector<wgpu::TextureUsage> textureUsages;
};
+ using PerPassUsages = std::vector<PassResourceUsage>;
+
struct CommandBufferResourceUsage {
- std::vector<PassResourceUsage> perPass;
+ PerPassUsages perPass;
std::set<BufferBase*> topLevelBuffers;
std::set<TextureBase*> topLevelTextures;
};
diff --git a/src/dawn_native/PassResourceUsageTracker.cpp b/src/dawn_native/PassResourceUsageTracker.cpp
index 18980b8..4831b36 100644
--- a/src/dawn_native/PassResourceUsageTracker.cpp
+++ b/src/dawn_native/PassResourceUsageTracker.cpp
@@ -31,54 +31,6 @@
mTextureUsages[texture] |= usage;
}
- MaybeError PassResourceUsageTracker::ValidateComputePassUsages() const {
- return ValidateUsages();
- }
-
- MaybeError PassResourceUsageTracker::ValidateRenderPassUsages() const {
- return ValidateUsages();
- }
-
- // Performs the per-pass usage validation checks
- MaybeError PassResourceUsageTracker::ValidateUsages() const {
- // Buffers can only be used as single-write or multiple read.
- for (auto& it : mBufferUsages) {
- BufferBase* buffer = it.first;
- wgpu::BufferUsage usage = it.second;
-
- if (usage & ~buffer->GetUsage()) {
- return DAWN_VALIDATION_ERROR("Buffer missing usage for the pass");
- }
-
- bool readOnly = (usage & kReadOnlyBufferUsages) == usage;
- bool singleUse = wgpu::HasZeroOrOneBits(usage);
-
- if (!readOnly && !singleUse) {
- return DAWN_VALIDATION_ERROR(
- "Buffer used as writable usage and another usage in pass");
- }
- }
-
- // Textures can only be used as single-write or multiple read.
- // TODO(cwallez@chromium.org): implement per-subresource tracking
- for (auto& it : mTextureUsages) {
- TextureBase* texture = it.first;
- wgpu::TextureUsage usage = it.second;
-
- if (usage & ~texture->GetUsage()) {
- return DAWN_VALIDATION_ERROR("Texture missing usage for the pass");
- }
-
- // For textures the only read-only usage in a pass is Sampled, so checking the
- // usage constraint simplifies to checking a single usage bit is set.
- if (!wgpu::HasZeroOrOneBits(it.second)) {
- return DAWN_VALIDATION_ERROR("Texture used with more than one usage in pass");
- }
- }
-
- return {};
- }
-
// Returns the per-pass usage for use by backends for APIs with explicit barriers.
PassResourceUsage PassResourceUsageTracker::AcquireResourceUsage() {
PassResourceUsage result;
@@ -97,6 +49,9 @@
result.textureUsages.push_back(it.second);
}
+ mBufferUsages.clear();
+ mTextureUsages.clear();
+
return result;
}
diff --git a/src/dawn_native/PassResourceUsageTracker.h b/src/dawn_native/PassResourceUsageTracker.h
index ff168fb..458b175 100644
--- a/src/dawn_native/PassResourceUsageTracker.h
+++ b/src/dawn_native/PassResourceUsageTracker.h
@@ -15,7 +15,6 @@
#ifndef DAWNNATIVE_PASSRESOURCEUSAGETRACKER_H_
#define DAWNNATIVE_PASSRESOURCEUSAGETRACKER_H_
-#include "dawn_native/Error.h"
#include "dawn_native/PassResourceUsage.h"
#include "dawn_native/dawn_platform.h"
@@ -36,16 +35,10 @@
void BufferUsedAs(BufferBase* buffer, wgpu::BufferUsage usage);
void TextureUsedAs(TextureBase* texture, wgpu::TextureUsage usage);
- MaybeError ValidateComputePassUsages() const;
- MaybeError ValidateRenderPassUsages() const;
-
// Returns the per-pass usage for use by backends for APIs with explicit barriers.
PassResourceUsage AcquireResourceUsage();
private:
- // Performs the per-pass usage validation checks
- MaybeError ValidateUsages() const;
-
std::map<BufferBase*, wgpu::BufferUsage> mBufferUsages;
std::map<TextureBase*, wgpu::TextureUsage> mTextureUsages;
};
diff --git a/src/dawn_native/ProgrammablePassEncoder.cpp b/src/dawn_native/ProgrammablePassEncoder.cpp
index 8013ccb..bedf0c4 100644
--- a/src/dawn_native/ProgrammablePassEncoder.cpp
+++ b/src/dawn_native/ProgrammablePassEncoder.cpp
@@ -14,6 +14,7 @@
#include "dawn_native/ProgrammablePassEncoder.h"
+#include "common/BitSetIterator.h"
#include "dawn_native/BindGroup.h"
#include "dawn_native/Buffer.h"
#include "dawn_native/CommandBuffer.h"
@@ -25,6 +26,46 @@
namespace dawn_native {
+ namespace {
+ void TrackBindGroupResourceUsage(PassResourceUsageTracker* usageTracker,
+ BindGroupBase* group) {
+ const auto& layoutInfo = group->GetLayout()->GetBindingInfo();
+
+ for (uint32_t i : IterateBitSet(layoutInfo.mask)) {
+ wgpu::BindingType type = layoutInfo.types[i];
+
+ switch (type) {
+ case wgpu::BindingType::UniformBuffer: {
+ BufferBase* buffer = group->GetBindingAsBufferBinding(i).buffer;
+ usageTracker->BufferUsedAs(buffer, wgpu::BufferUsage::Uniform);
+ } break;
+
+ case wgpu::BindingType::StorageBuffer: {
+ BufferBase* buffer = group->GetBindingAsBufferBinding(i).buffer;
+ usageTracker->BufferUsedAs(buffer, wgpu::BufferUsage::Storage);
+ } break;
+
+ case wgpu::BindingType::SampledTexture: {
+ TextureBase* texture = group->GetBindingAsTextureView(i)->GetTexture();
+ usageTracker->TextureUsedAs(texture, wgpu::TextureUsage::Sampled);
+ } break;
+
+ case wgpu::BindingType::ReadonlyStorageBuffer: {
+ BufferBase* buffer = group->GetBindingAsBufferBinding(i).buffer;
+ usageTracker->BufferUsedAs(buffer, kReadOnlyStorage);
+ } break;
+
+ case wgpu::BindingType::Sampler:
+ break;
+
+ case wgpu::BindingType::StorageTexture:
+ UNREACHABLE();
+ break;
+ }
+ }
+ }
+ } // namespace
+
ProgrammablePassEncoder::ProgrammablePassEncoder(DeviceBase* device,
EncodingContext* encodingContext)
: ObjectBase(device), mEncodingContext(encodingContext) {
@@ -75,34 +116,36 @@
uint32_t dynamicOffsetCount,
const uint32_t* dynamicOffsets) {
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
- DAWN_TRY(GetDevice()->ValidateObject(group));
+ if (GetDevice()->IsValidationEnabled()) {
+ DAWN_TRY(GetDevice()->ValidateObject(group));
- if (groupIndex >= kMaxBindGroups) {
- return DAWN_VALIDATION_ERROR("Setting bind group over the max");
- }
-
- // Dynamic offsets count must match the number required by the layout perfectly.
- const BindGroupLayoutBase* layout = group->GetLayout();
- if (layout->GetDynamicBufferCount() != dynamicOffsetCount) {
- return DAWN_VALIDATION_ERROR("dynamicOffset count mismatch");
- }
-
- for (uint32_t i = 0; i < dynamicOffsetCount; ++i) {
- if (dynamicOffsets[i] % kMinDynamicBufferOffsetAlignment != 0) {
- return DAWN_VALIDATION_ERROR("Dynamic Buffer Offset need to be aligned");
+ if (groupIndex >= kMaxBindGroups) {
+ return DAWN_VALIDATION_ERROR("Setting bind group over the max");
}
- BufferBinding bufferBinding = group->GetBindingAsBufferBinding(i);
+ // Dynamic offsets count must match the number required by the layout perfectly.
+ const BindGroupLayoutBase* layout = group->GetLayout();
+ if (layout->GetDynamicBufferCount() != dynamicOffsetCount) {
+ return DAWN_VALIDATION_ERROR("dynamicOffset count mismatch");
+ }
- // During BindGroup creation, validation ensures binding offset + binding size <=
- // buffer size.
- DAWN_ASSERT(bufferBinding.buffer->GetSize() >= bufferBinding.size);
- DAWN_ASSERT(bufferBinding.buffer->GetSize() - bufferBinding.size >=
- bufferBinding.offset);
+ for (uint32_t i = 0; i < dynamicOffsetCount; ++i) {
+ if (dynamicOffsets[i] % kMinDynamicBufferOffsetAlignment != 0) {
+ return DAWN_VALIDATION_ERROR("Dynamic Buffer Offset need to be aligned");
+ }
- if ((dynamicOffsets[i] >
- bufferBinding.buffer->GetSize() - bufferBinding.offset - bufferBinding.size)) {
- return DAWN_VALIDATION_ERROR("dynamic offset out of bounds");
+ BufferBinding bufferBinding = group->GetBindingAsBufferBinding(i);
+
+ // During BindGroup creation, validation ensures binding offset + binding size
+ // <= buffer size.
+ DAWN_ASSERT(bufferBinding.buffer->GetSize() >= bufferBinding.size);
+ DAWN_ASSERT(bufferBinding.buffer->GetSize() - bufferBinding.size >=
+ bufferBinding.offset);
+
+ if ((dynamicOffsets[i] > bufferBinding.buffer->GetSize() -
+ bufferBinding.offset - bufferBinding.size)) {
+ return DAWN_VALIDATION_ERROR("dynamic offset out of bounds");
+ }
}
}
@@ -115,6 +158,8 @@
memcpy(offsets, dynamicOffsets, dynamicOffsetCount * sizeof(uint32_t));
}
+ TrackBindGroupResourceUsage(&mUsageTracker, group);
+
return {};
});
}
diff --git a/src/dawn_native/ProgrammablePassEncoder.h b/src/dawn_native/ProgrammablePassEncoder.h
index 2508059..17bfeb4 100644
--- a/src/dawn_native/ProgrammablePassEncoder.h
+++ b/src/dawn_native/ProgrammablePassEncoder.h
@@ -18,6 +18,7 @@
#include "dawn_native/CommandEncoder.h"
#include "dawn_native/Error.h"
#include "dawn_native/ObjectBase.h"
+#include "dawn_native/PassResourceUsageTracker.h"
#include "dawn_native/dawn_platform.h"
@@ -47,6 +48,7 @@
ErrorTag errorTag);
EncodingContext* mEncodingContext = nullptr;
+ PassResourceUsageTracker mUsageTracker;
};
} // namespace dawn_native
diff --git a/src/dawn_native/Queue.cpp b/src/dawn_native/Queue.cpp
index 41d16e9..0fbcdc7 100644
--- a/src/dawn_native/Queue.cpp
+++ b/src/dawn_native/Queue.cpp
@@ -35,7 +35,8 @@
void QueueBase::Submit(uint32_t commandCount, CommandBufferBase* const* commands) {
DeviceBase* device = GetDevice();
TRACE_EVENT0(device->GetPlatform(), General, "Queue::Submit");
- if (device->ConsumedError(ValidateSubmit(commandCount, commands))) {
+ if (device->IsValidationEnabled() &&
+ device->ConsumedError(ValidateSubmit(commandCount, commands))) {
return;
}
ASSERT(!IsError());
diff --git a/src/dawn_native/RenderBundleEncoder.cpp b/src/dawn_native/RenderBundleEncoder.cpp
index 7d89876..956fa8b 100644
--- a/src/dawn_native/RenderBundleEncoder.cpp
+++ b/src/dawn_native/RenderBundleEncoder.cpp
@@ -102,26 +102,27 @@
}
RenderBundleBase* RenderBundleEncoder::Finish(const RenderBundleDescriptor* descriptor) {
- if (GetDevice()->ConsumedError(ValidateFinish(descriptor))) {
- return RenderBundleBase::MakeError(GetDevice());
- }
- ASSERT(!IsError());
+ PassResourceUsage usages = mUsageTracker.AcquireResourceUsage();
- return new RenderBundleBase(this, descriptor, mAttachmentState.Get(),
- std::move(mResourceUsage));
+ DeviceBase* device = GetDevice();
+ // Even if mEncodingContext.Finish() validation fails, calling it will mutate the internal
+ // state of the encoding context. Subsequent calls to encode commands will generate errors.
+ if (device->ConsumedError(mEncodingContext.Finish()) ||
+ (device->IsValidationEnabled() &&
+ device->ConsumedError(ValidateFinish(mEncodingContext.GetIterator(), usages)))) {
+ return RenderBundleBase::MakeError(device);
+ }
+
+ ASSERT(!IsError());
+ return new RenderBundleBase(this, descriptor, mAttachmentState.Get(), std::move(usages));
}
- MaybeError RenderBundleEncoder::ValidateFinish(const RenderBundleDescriptor* descriptor) {
+ MaybeError RenderBundleEncoder::ValidateFinish(CommandIterator* commands,
+ const PassResourceUsage& usages) const {
TRACE_EVENT0(GetDevice()->GetPlatform(), Validation, "RenderBundleEncoder::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());
-
- CommandIterator* commands = mEncodingContext.GetIterator();
-
- DAWN_TRY(ValidateRenderBundle(commands, mAttachmentState.Get(), &mResourceUsage));
+ DAWN_TRY(ValidatePassResourceUsage(usages));
+ DAWN_TRY(ValidateRenderBundle(commands, mAttachmentState.Get()));
return {};
}
diff --git a/src/dawn_native/RenderBundleEncoder.h b/src/dawn_native/RenderBundleEncoder.h
index f3919b0..0581719 100644
--- a/src/dawn_native/RenderBundleEncoder.h
+++ b/src/dawn_native/RenderBundleEncoder.h
@@ -42,11 +42,10 @@
private:
RenderBundleEncoder(DeviceBase* device, ErrorTag errorTag);
- MaybeError ValidateFinish(const RenderBundleDescriptor* descriptor);
+ MaybeError ValidateFinish(CommandIterator* commands, const PassResourceUsage& usages) const;
EncodingContext mEncodingContext;
Ref<AttachmentState> mAttachmentState;
- PassResourceUsage mResourceUsage;
};
} // namespace dawn_native
diff --git a/src/dawn_native/RenderEncoderBase.cpp b/src/dawn_native/RenderEncoderBase.cpp
index aecaf30..885f7a1 100644
--- a/src/dawn_native/RenderEncoderBase.cpp
+++ b/src/dawn_native/RenderEncoderBase.cpp
@@ -81,6 +81,8 @@
cmd->indirectBuffer = indirectBuffer;
cmd->indirectOffset = indirectOffset;
+ mUsageTracker.BufferUsedAs(indirectBuffer, wgpu::BufferUsage::Indirect);
+
return {};
});
}
@@ -100,6 +102,8 @@
cmd->indirectBuffer = indirectBuffer;
cmd->indirectOffset = indirectOffset;
+ mUsageTracker.BufferUsedAs(indirectBuffer, wgpu::BufferUsage::Indirect);
+
return {};
});
}
@@ -125,6 +129,8 @@
cmd->buffer = buffer;
cmd->offset = offset;
+ mUsageTracker.BufferUsedAs(buffer, wgpu::BufferUsage::Index);
+
return {};
});
}
@@ -139,6 +145,8 @@
cmd->buffer = buffer;
cmd->offset = offset;
+ mUsageTracker.BufferUsedAs(buffer, wgpu::BufferUsage::Vertex);
+
return {};
});
}
diff --git a/src/dawn_native/RenderPassEncoder.cpp b/src/dawn_native/RenderPassEncoder.cpp
index 5e74acb..9dbb2ee 100644
--- a/src/dawn_native/RenderPassEncoder.cpp
+++ b/src/dawn_native/RenderPassEncoder.cpp
@@ -27,10 +27,15 @@
namespace dawn_native {
+ // The usage tracker is passed in here, because it is prepopulated with usages from the
+ // BeginRenderPassCmd. If we had RenderPassEncoder responsible for recording the
+ // command, then this wouldn't be necessary.
RenderPassEncoder::RenderPassEncoder(DeviceBase* device,
CommandEncoder* commandEncoder,
- EncodingContext* encodingContext)
+ EncodingContext* encodingContext,
+ PassResourceUsageTracker usageTracker)
: RenderEncoderBase(device, encodingContext), mCommandEncoder(commandEncoder) {
+ mUsageTracker = std::move(usageTracker);
}
RenderPassEncoder::RenderPassEncoder(DeviceBase* device,
@@ -52,7 +57,7 @@
return {};
})) {
- mEncodingContext->ExitPass(this);
+ mEncodingContext->ExitPass(this, mUsageTracker.AcquireResourceUsage());
}
}
@@ -143,6 +148,14 @@
Ref<RenderBundleBase>* bundles = allocator->AllocateData<Ref<RenderBundleBase>>(count);
for (uint32_t i = 0; i < count; ++i) {
bundles[i] = renderBundles[i];
+
+ const PassResourceUsage& usages = bundles[i]->GetResourceUsage();
+ for (uint32_t i = 0; i < usages.buffers.size(); ++i) {
+ mUsageTracker.BufferUsedAs(usages.buffers[i], usages.bufferUsages[i]);
+ }
+ for (uint32_t i = 0; i < usages.textures.size(); ++i) {
+ mUsageTracker.TextureUsedAs(usages.textures[i], usages.textureUsages[i]);
+ }
}
return {};
diff --git a/src/dawn_native/RenderPassEncoder.h b/src/dawn_native/RenderPassEncoder.h
index 12b9342..cd9ac01 100644
--- a/src/dawn_native/RenderPassEncoder.h
+++ b/src/dawn_native/RenderPassEncoder.h
@@ -26,7 +26,8 @@
public:
RenderPassEncoder(DeviceBase* device,
CommandEncoder* commandEncoder,
- EncodingContext* encodingContext);
+ EncodingContext* encodingContext,
+ PassResourceUsageTracker usageTracker);
static RenderPassEncoder* MakeError(DeviceBase* device,
CommandEncoder* commandEncoder,
diff --git a/src/tests/perf_tests/DrawCallPerf.cpp b/src/tests/perf_tests/DrawCallPerf.cpp
index e21c9ae..662a3be 100644
--- a/src/tests/perf_tests/DrawCallPerf.cpp
+++ b/src/tests/perf_tests/DrawCallPerf.cpp
@@ -605,7 +605,8 @@
DAWN_INSTANTIATE_PERF_TEST_SUITE_P(
DrawCallPerf,
- {D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend},
+ {D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend,
+ ForceWorkarounds(VulkanBackend, {"skip_validation"})},
{
// Baseline
MakeParam(),