Add cleanup when encoding indirect draw validations.
- Cleanup is necessary because otherwise encoded render commands may be leaked if the validation encoding fails. (The leaked render commands can then trigger an assert in ~Device::Cache because the commands can hold a ref to an AttachmentState that was not destroyed, and hence still be in the device cache. - Added explicit check in EncoderIndirectDrawValidationCommands for device 'alive-ness' since it may create new objects later and hit the same error later on anyways. - Added regression test. Fixed: chromium:1365011 Change-Id: I342479a4227fc43d82ea35f662d049e6db2b1740 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/103340 Reviewed-by: Austin Eng <enga@chromium.org> Commit-Queue: Loko Kung <lokokung@google.com> Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
parent
c4ebf2cc57
commit
3354bf0d91
|
@ -127,9 +127,12 @@ MaybeError EncodingContext::ExitRenderPass(const ApiObjectBase* passEncoder,
|
|||
// mPendingCommands contains only the commands from BeginRenderPassCmd to
|
||||
// EndRenderPassCmd, inclusive. Now we swap out this allocator with a fresh one to give
|
||||
// the validation encoder a chance to insert its commands first.
|
||||
// Note: If encoding validation commands fails, no commands should be in mPendingCommands,
|
||||
// so swap back the renderCommands to ensure that they are not leaked.
|
||||
CommandAllocator renderCommands = std::move(mPendingCommands);
|
||||
DAWN_TRY(EncodeIndirectDrawValidationCommands(mDevice, commandEncoder, &usageTracker,
|
||||
&indirectDrawMetadata));
|
||||
DAWN_TRY_WITH_CLEANUP(EncodeIndirectDrawValidationCommands(
|
||||
mDevice, commandEncoder, &usageTracker, &indirectDrawMetadata),
|
||||
{ mPendingCommands = std::move(renderCommands); });
|
||||
CommitCommands(std::move(mPendingCommands));
|
||||
CommitCommands(std::move(renderCommands));
|
||||
}
|
||||
|
|
|
@ -239,6 +239,12 @@ MaybeError EncodeIndirectDrawValidationCommands(DeviceBase* device,
|
|||
CommandEncoder* commandEncoder,
|
||||
RenderPassResourceUsageTracker* usageTracker,
|
||||
IndirectDrawMetadata* indirectDrawMetadata) {
|
||||
// Since encoding validation commands may create new objects, verify that the device is alive.
|
||||
// TODO(dawn:1199): This check is obsolete if device loss causes device.destroy().
|
||||
// - This function only happens within the context of a TryEncode which would catch the
|
||||
// same issue if device loss implied device.destroy().
|
||||
DAWN_TRY(device->ValidateIsAlive());
|
||||
|
||||
struct Batch {
|
||||
const IndirectDrawMetadata::IndirectValidationBatch* metadata;
|
||||
uint64_t numIndexBufferElements;
|
||||
|
|
|
@ -475,6 +475,37 @@ TEST_P(DeviceLostTest, FreeBindGroupAfterDeviceLossWithPendingCommands) {
|
|||
bg = nullptr;
|
||||
}
|
||||
|
||||
// This is a regression test for crbug.com/1365011 where ending a render pass with an indirect draw
|
||||
// in it after the device is lost would cause render commands to be leaked.
|
||||
TEST_P(DeviceLostTest, DeviceLostInRenderPassWithDrawIndirect) {
|
||||
utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 4u, 4u);
|
||||
utils::ComboRenderPipelineDescriptor desc;
|
||||
desc.vertex.module = utils::CreateShaderModule(device, R"(
|
||||
@vertex fn main(@builtin(vertex_index) i : u32) -> @builtin(position) vec4<f32> {
|
||||
var pos = array<vec2<f32>, 3>(
|
||||
vec2<f32>(-1.0, -1.0),
|
||||
vec2<f32>(3.0, -1.0),
|
||||
vec2<f32>(-1.0, 3.0));
|
||||
return vec4<f32>(pos[i], 0.0, 1.0);
|
||||
}
|
||||
)");
|
||||
desc.cFragment.module = utils::CreateShaderModule(device, R"(
|
||||
@fragment fn main() -> @location(0) vec4<f32> {
|
||||
return vec4<f32>(0.0, 1.0, 0.0, 1.0);
|
||||
}
|
||||
)");
|
||||
desc.cTargets[0].format = renderPass.colorFormat;
|
||||
wgpu::Buffer indirectBuffer =
|
||||
utils::CreateBufferFromData<uint32_t>(device, wgpu::BufferUsage::Indirect, {3, 1, 0, 0});
|
||||
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&desc);
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
|
||||
pass.SetPipeline(pipeline);
|
||||
pass.DrawIndirect(indirectBuffer, 0);
|
||||
LoseDeviceForTesting();
|
||||
pass.End();
|
||||
}
|
||||
|
||||
// Attempting to set an object label after device loss should not cause an error.
|
||||
TEST_P(DeviceLostTest, SetLabelAfterDeviceLoss) {
|
||||
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
|
||||
|
|
Loading…
Reference in New Issue