Validate if device is alive in EncodeFunction of EncodingContext::TryEncode
GetOrCreateAttachmentState access mCaches in Device even if device is already destroyed. Gate the function by checking if encoder is destroyed. Bug: chromium:1323310 Change-Id: I8151c5ec696e4da28b8296d9142f3120379782ef Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/89860 Reviewed-by: Austin Eng <enga@chromium.org> Reviewed-by: Loko Kung <lokokung@google.com> Commit-Queue: Shrek Shao <shrekshao@google.com>
This commit is contained in:
parent
83fc247d4b
commit
8faaad9b5e
|
@ -25,7 +25,10 @@
|
|||
namespace dawn::native {
|
||||
|
||||
EncodingContext::EncodingContext(DeviceBase* device, const ApiObjectBase* initialEncoder)
|
||||
: mDevice(device), mTopLevelEncoder(initialEncoder), mCurrentEncoder(initialEncoder) {}
|
||||
: mDevice(device),
|
||||
mTopLevelEncoder(initialEncoder),
|
||||
mCurrentEncoder(initialEncoder),
|
||||
mDestroyed(device->IsLost()) {}
|
||||
|
||||
EncodingContext::~EncodingContext() {
|
||||
Destroy();
|
||||
|
|
|
@ -79,10 +79,13 @@ class EncodingContext {
|
|||
}
|
||||
|
||||
inline bool CheckCurrentEncoder(const ApiObjectBase* encoder) {
|
||||
if (DAWN_UNLIKELY(encoder != mCurrentEncoder)) {
|
||||
if (mDestroyed) {
|
||||
HandleError(DAWN_FORMAT_VALIDATION_ERROR("Recording in a destroyed %s.", encoder));
|
||||
} else if (mCurrentEncoder != mTopLevelEncoder) {
|
||||
HandleError(
|
||||
DAWN_FORMAT_VALIDATION_ERROR("Recording in a destroyed %s.", mCurrentEncoder));
|
||||
return false;
|
||||
}
|
||||
if (DAWN_UNLIKELY(encoder != mCurrentEncoder)) {
|
||||
if (mCurrentEncoder != mTopLevelEncoder) {
|
||||
// The top level encoder was used when a pass encoder was current.
|
||||
HandleError(DAWN_FORMAT_VALIDATION_ERROR(
|
||||
"Command cannot be recorded while %s is active.", mCurrentEncoder));
|
||||
|
|
|
@ -31,12 +31,12 @@ TEST_F(CommandBufferValidationTest, Empty) {
|
|||
|
||||
// Test that a command buffer cannot be ended mid render pass
|
||||
TEST_F(CommandBufferValidationTest, EndedMidRenderPass) {
|
||||
PlaceholderRenderPass PlaceholderRenderPass(device);
|
||||
PlaceholderRenderPass placeholderRenderPass(device);
|
||||
|
||||
// Control case, command buffer ended after the pass is ended.
|
||||
{
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&PlaceholderRenderPass);
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&placeholderRenderPass);
|
||||
pass.End();
|
||||
encoder.Finish();
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ TEST_F(CommandBufferValidationTest, EndedMidRenderPass) {
|
|||
// Error case, command buffer ended mid-pass.
|
||||
{
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&PlaceholderRenderPass);
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&placeholderRenderPass);
|
||||
ASSERT_DEVICE_ERROR(
|
||||
encoder.Finish(),
|
||||
HasSubstr("Command buffer recording ended before [RenderPassEncoder] was ended."));
|
||||
|
@ -54,7 +54,7 @@ TEST_F(CommandBufferValidationTest, EndedMidRenderPass) {
|
|||
// should fail too.
|
||||
{
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&PlaceholderRenderPass);
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&placeholderRenderPass);
|
||||
ASSERT_DEVICE_ERROR(
|
||||
encoder.Finish(),
|
||||
HasSubstr("Command buffer recording ended before [RenderPassEncoder] was ended."));
|
||||
|
@ -97,12 +97,12 @@ TEST_F(CommandBufferValidationTest, EndedMidComputePass) {
|
|||
|
||||
// Test that a render pass cannot be ended twice
|
||||
TEST_F(CommandBufferValidationTest, RenderPassEndedTwice) {
|
||||
PlaceholderRenderPass PlaceholderRenderPass(device);
|
||||
PlaceholderRenderPass placeholderRenderPass(device);
|
||||
|
||||
// Control case, pass is ended once
|
||||
{
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&PlaceholderRenderPass);
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&placeholderRenderPass);
|
||||
pass.End();
|
||||
encoder.Finish();
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ TEST_F(CommandBufferValidationTest, RenderPassEndedTwice) {
|
|||
// Error case, pass ended twice
|
||||
{
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&PlaceholderRenderPass);
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&placeholderRenderPass);
|
||||
pass.End();
|
||||
pass.End();
|
||||
ASSERT_DEVICE_ERROR(
|
||||
|
@ -143,12 +143,12 @@ TEST_F(CommandBufferValidationTest, ComputePassEndedTwice) {
|
|||
|
||||
// Test that beginning a compute pass before ending the previous pass causes an error.
|
||||
TEST_F(CommandBufferValidationTest, BeginComputePassBeforeEndPreviousPass) {
|
||||
PlaceholderRenderPass PlaceholderRenderPass(device);
|
||||
PlaceholderRenderPass placeholderRenderPass(device);
|
||||
|
||||
// Beginning a compute pass before ending a render pass causes an error.
|
||||
{
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
wgpu::RenderPassEncoder renderPass = encoder.BeginRenderPass(&PlaceholderRenderPass);
|
||||
wgpu::RenderPassEncoder renderPass = encoder.BeginRenderPass(&placeholderRenderPass);
|
||||
wgpu::ComputePassEncoder computePass = encoder.BeginComputePass();
|
||||
computePass.End();
|
||||
renderPass.End();
|
||||
|
@ -168,13 +168,13 @@ TEST_F(CommandBufferValidationTest, BeginComputePassBeforeEndPreviousPass) {
|
|||
|
||||
// Test that beginning a render pass before ending the previous pass causes an error.
|
||||
TEST_F(CommandBufferValidationTest, BeginRenderPassBeforeEndPreviousPass) {
|
||||
PlaceholderRenderPass PlaceholderRenderPass(device);
|
||||
PlaceholderRenderPass placeholderRenderPass(device);
|
||||
|
||||
// Beginning a render pass before ending the render pass causes an error.
|
||||
{
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
wgpu::RenderPassEncoder renderPass1 = encoder.BeginRenderPass(&PlaceholderRenderPass);
|
||||
wgpu::RenderPassEncoder renderPass2 = encoder.BeginRenderPass(&PlaceholderRenderPass);
|
||||
wgpu::RenderPassEncoder renderPass1 = encoder.BeginRenderPass(&placeholderRenderPass);
|
||||
wgpu::RenderPassEncoder renderPass2 = encoder.BeginRenderPass(&placeholderRenderPass);
|
||||
renderPass2.End();
|
||||
renderPass1.End();
|
||||
ASSERT_DEVICE_ERROR(encoder.Finish());
|
||||
|
@ -184,7 +184,7 @@ TEST_F(CommandBufferValidationTest, BeginRenderPassBeforeEndPreviousPass) {
|
|||
{
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
wgpu::ComputePassEncoder computePass = encoder.BeginComputePass();
|
||||
wgpu::RenderPassEncoder renderPass = encoder.BeginRenderPass(&PlaceholderRenderPass);
|
||||
wgpu::RenderPassEncoder renderPass = encoder.BeginRenderPass(&placeholderRenderPass);
|
||||
renderPass.End();
|
||||
computePass.End();
|
||||
ASSERT_DEVICE_ERROR(encoder.Finish());
|
||||
|
@ -229,12 +229,12 @@ TEST_F(CommandBufferValidationTest, CallsAfterAFailedFinish) {
|
|||
// Test that passes which are de-referenced prior to ending still allow the correct errors to be
|
||||
// produced.
|
||||
TEST_F(CommandBufferValidationTest, PassDereferenced) {
|
||||
PlaceholderRenderPass PlaceholderRenderPass(device);
|
||||
PlaceholderRenderPass placeholderRenderPass(device);
|
||||
|
||||
// Control case, command buffer ended after the pass is ended.
|
||||
{
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&PlaceholderRenderPass);
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&placeholderRenderPass);
|
||||
pass.End();
|
||||
encoder.Finish();
|
||||
}
|
||||
|
@ -242,7 +242,7 @@ TEST_F(CommandBufferValidationTest, PassDereferenced) {
|
|||
// Error case, no reference is kept to a render pass.
|
||||
{
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
encoder.BeginRenderPass(&PlaceholderRenderPass);
|
||||
encoder.BeginRenderPass(&placeholderRenderPass);
|
||||
ASSERT_DEVICE_ERROR(
|
||||
encoder.Finish(),
|
||||
HasSubstr("Command buffer recording ended before [RenderPassEncoder] was ended."));
|
||||
|
@ -260,7 +260,7 @@ TEST_F(CommandBufferValidationTest, PassDereferenced) {
|
|||
// Error case, beginning a new pass after failing to end a de-referenced pass.
|
||||
{
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
encoder.BeginRenderPass(&PlaceholderRenderPass);
|
||||
encoder.BeginRenderPass(&placeholderRenderPass);
|
||||
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
|
||||
pass.End();
|
||||
ASSERT_DEVICE_ERROR(
|
||||
|
@ -301,12 +301,12 @@ TEST_F(CommandBufferValidationTest, DestroyEncoder) {
|
|||
// only way to trigger the destroy call is by losing all references which means we cannot
|
||||
// call finish.
|
||||
DAWN_SKIP_TEST_IF(UsesWire());
|
||||
PlaceholderRenderPass PlaceholderRenderPass(device);
|
||||
PlaceholderRenderPass placeholderRenderPass(device);
|
||||
|
||||
// Control case, command buffer ended after the pass is ended.
|
||||
{
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&PlaceholderRenderPass);
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&placeholderRenderPass);
|
||||
pass.End();
|
||||
encoder.Finish();
|
||||
}
|
||||
|
@ -314,7 +314,7 @@ TEST_F(CommandBufferValidationTest, DestroyEncoder) {
|
|||
// Destroyed encoder with encoded commands should emit error on finish.
|
||||
{
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&PlaceholderRenderPass);
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&placeholderRenderPass);
|
||||
pass.End();
|
||||
dawn::native::FromAPI(encoder.Get())->Destroy();
|
||||
ASSERT_DEVICE_ERROR(encoder.Finish(), HasSubstr("Destroyed encoder cannot be finished."));
|
||||
|
@ -323,7 +323,7 @@ TEST_F(CommandBufferValidationTest, DestroyEncoder) {
|
|||
// Destroyed encoder with encoded commands shouldn't emit an error if never finished.
|
||||
{
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&PlaceholderRenderPass);
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&placeholderRenderPass);
|
||||
pass.End();
|
||||
dawn::native::FromAPI(encoder.Get())->Destroy();
|
||||
}
|
||||
|
@ -332,7 +332,7 @@ TEST_F(CommandBufferValidationTest, DestroyEncoder) {
|
|||
{
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
dawn::native::FromAPI(encoder.Get())->Destroy();
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&PlaceholderRenderPass);
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&placeholderRenderPass);
|
||||
pass.End();
|
||||
ASSERT_DEVICE_ERROR(encoder.Finish(), HasSubstr("Destroyed encoder cannot be finished."));
|
||||
}
|
||||
|
@ -341,14 +341,14 @@ TEST_F(CommandBufferValidationTest, DestroyEncoder) {
|
|||
{
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
dawn::native::FromAPI(encoder.Get())->Destroy();
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&PlaceholderRenderPass);
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&placeholderRenderPass);
|
||||
pass.End();
|
||||
}
|
||||
|
||||
// Destroying a finished encoder should not emit any errors.
|
||||
{
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&PlaceholderRenderPass);
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&placeholderRenderPass);
|
||||
pass.End();
|
||||
encoder.Finish();
|
||||
dawn::native::FromAPI(encoder.Get())->Destroy();
|
||||
|
@ -369,3 +369,32 @@ TEST_F(CommandBufferValidationTest, DestroyEncoder) {
|
|||
ASSERT_DEVICE_ERROR(encoder.Finish(), HasSubstr("Destroyed encoder cannot be finished."));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CommandBufferValidationTest, EncodeAfterDeviceDestroyed) {
|
||||
PlaceholderRenderPass placeholderRenderPass(device);
|
||||
|
||||
// Device destroyed before encoding.
|
||||
{
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
ExpectDeviceDestruction();
|
||||
device.Destroy();
|
||||
// The encoder should not accessing any device info if device is destroyed when try
|
||||
// encoding.
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&placeholderRenderPass);
|
||||
pass.End();
|
||||
ASSERT_DEVICE_ERROR(encoder.Finish(), HasSubstr("Destroyed encoder cannot be finished."));
|
||||
}
|
||||
|
||||
// Device destroyed after encoding.
|
||||
{
|
||||
ExpectDeviceDestruction();
|
||||
device.Destroy();
|
||||
ASSERT_DEVICE_ERROR(wgpu::CommandEncoder encoder = device.CreateCommandEncoder(),
|
||||
HasSubstr("[Device] is lost"));
|
||||
// The encoder should not accessing any device info if device is destroyed when try
|
||||
// encoding.
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&placeholderRenderPass);
|
||||
pass.End();
|
||||
ASSERT_DEVICE_ERROR(encoder.Finish(), HasSubstr("[Invalid CommandEncoder] is invalid."));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue