Fix crash when device is removed before CreateReady*Pipeline callback

This patch fixes a crash issue when the device is destroyed before
the callback of CreateReady{Render, Compute}Pipeline is called. Now
when the callback is called in DeviceBase::ShutDown(), the cached
pipeline object will also be destroyed before the callback returns.

BUG=dawn:529
TEST=dawn_end2end_tests

Change-Id: I91ec2608b53591d265c0648f5c02daf7fadac85e
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/30744
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
This commit is contained in:
Jiawei Shao
2020-10-24 03:11:43 +00:00
committed by Commit Bot service account
parent ebdbc03b77
commit 42103bc2e9
9 changed files with 195 additions and 41 deletions

View File

@@ -26,7 +26,10 @@ namespace {
};
} // anonymous namespace
class CreateReadyPipelineTest : public DawnTest {};
class CreateReadyPipelineTest : public DawnTest {
protected:
CreateReadyPipelineTask task;
};
// Verify the basic use of CreateReadyComputePipeline works on all backends.
TEST_P(CreateReadyPipelineTest, BasicUseOfCreateReadyComputePipeline) {
@@ -42,7 +45,6 @@ TEST_P(CreateReadyPipelineTest, BasicUseOfCreateReadyComputePipeline) {
utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, computeShader);
csDesc.computeStage.entryPoint = "main";
CreateReadyPipelineTask task;
device.CreateReadyComputePipeline(
&csDesc,
[](WGPUCreateReadyPipelineStatus status, WGPUComputePipeline returnPipeline,
@@ -110,7 +112,6 @@ TEST_P(CreateReadyPipelineTest, CreateComputePipelineFailed) {
utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, computeShader);
csDesc.computeStage.entryPoint = "main0";
CreateReadyPipelineTask task;
device.CreateReadyComputePipeline(
&csDesc,
[](WGPUCreateReadyPipelineStatus status, WGPUComputePipeline returnPipeline,
@@ -159,7 +160,6 @@ TEST_P(CreateReadyPipelineTest, BasicUseOfCreateReadyRenderPipeline) {
renderPipelineDescriptor.cColorStates[0].format = kOutputAttachmentFormat;
renderPipelineDescriptor.primitiveTopology = wgpu::PrimitiveTopology::PointList;
CreateReadyPipelineTask task;
device.CreateReadyRenderPipeline(
&renderPipelineDescriptor,
[](WGPUCreateReadyPipelineStatus status, WGPURenderPipeline returnPipeline,
@@ -237,7 +237,6 @@ TEST_P(CreateReadyPipelineTest, CreateRenderPipelineFailed) {
renderPipelineDescriptor.cColorStates[0].format = kOutputAttachmentFormat;
renderPipelineDescriptor.primitiveTopology = wgpu::PrimitiveTopology::PointList;
CreateReadyPipelineTask task;
device.CreateReadyRenderPipeline(
&renderPipelineDescriptor,
[](WGPUCreateReadyPipelineStatus status, WGPURenderPipeline returnPipeline,
@@ -259,6 +258,75 @@ TEST_P(CreateReadyPipelineTest, CreateRenderPipelineFailed) {
ASSERT_EQ(nullptr, task.computePipeline.Get());
}
// Verify there is no error when the device is released before the callback of
// CreateReadyComputePipeline() is called.
TEST_P(CreateReadyPipelineTest, ReleaseDeviceBeforeCallbackOfCreateReadyComputePipeline) {
const char* computeShader = R"(
#version 450
void main() {
})";
wgpu::ComputePipelineDescriptor csDesc;
csDesc.computeStage.module =
utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, computeShader);
csDesc.computeStage.entryPoint = "main";
device.CreateReadyComputePipeline(
&csDesc,
[](WGPUCreateReadyPipelineStatus status, WGPUComputePipeline returnPipeline,
const char* message, void* userdata) {
ASSERT_EQ(WGPUCreateReadyPipelineStatus::WGPUCreateReadyPipelineStatus_DeviceDestroyed,
status);
CreateReadyPipelineTask* task = static_cast<CreateReadyPipelineTask*>(userdata);
task->computePipeline = wgpu::ComputePipeline::Acquire(returnPipeline);
task->isCompleted = true;
task->message = message;
},
&task);
}
// Verify there is no error when the device is released before the callback of
// CreateReadyRenderPipeline() is called.
TEST_P(CreateReadyPipelineTest, ReleaseDeviceBeforeCallbackOfCreateReadyRenderPipeline) {
const char* vertexShader = R"(
#version 450
void main() {
gl_Position = vec4(0.f, 0.f, 0.f, 1.f);
gl_PointSize = 1.0f;
})";
const char* fragmentShader = R"(
#version 450
layout(location = 0) out vec4 o_color;
void main() {
o_color = vec4(0.f, 1.f, 0.f, 1.f);
})";
utils::ComboRenderPipelineDescriptor renderPipelineDescriptor(device);
wgpu::ShaderModule vsModule =
utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, vertexShader);
wgpu::ShaderModule fsModule =
utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, fragmentShader);
renderPipelineDescriptor.vertexStage.module = vsModule;
renderPipelineDescriptor.cFragmentStage.module = fsModule;
renderPipelineDescriptor.cColorStates[0].format = wgpu::TextureFormat::RGBA8Unorm;
renderPipelineDescriptor.primitiveTopology = wgpu::PrimitiveTopology::PointList;
device.CreateReadyRenderPipeline(
&renderPipelineDescriptor,
[](WGPUCreateReadyPipelineStatus status, WGPURenderPipeline returnPipeline,
const char* message, void* userdata) {
ASSERT_EQ(WGPUCreateReadyPipelineStatus::WGPUCreateReadyPipelineStatus_DeviceDestroyed,
status);
CreateReadyPipelineTask* task = static_cast<CreateReadyPipelineTask*>(userdata);
task->renderPipeline = wgpu::RenderPipeline::Acquire(returnPipeline);
task->isCompleted = true;
task->message = message;
},
&task);
}
DAWN_INSTANTIATE_TEST(CreateReadyPipelineTest,
D3D12Backend(),
MetalBackend(),