Device Loss handle GetBindGroupLayout and test
This includes moving the destruction of vkDevice from Destroy to the Device Destructor since we need vkDevice to destroy child objects. Bug: dawn:68 Change-Id: Id477206b2e3f80138b3708eedcee073303f1b696 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/15220 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Austin Eng <enga@chromium.org> Commit-Queue: Natasha Lee <natlee@microsoft.com>
This commit is contained in:
parent
3003aa622b
commit
80880ee998
|
@ -67,6 +67,7 @@ namespace dawn_native {
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeError PipelineBase::ValidateGetBindGroupLayout(uint32_t group) {
|
MaybeError PipelineBase::ValidateGetBindGroupLayout(uint32_t group) {
|
||||||
|
DAWN_TRY(GetDevice()->ValidateIsAlive());
|
||||||
DAWN_TRY(GetDevice()->ValidateObject(this));
|
DAWN_TRY(GetDevice()->ValidateObject(this));
|
||||||
DAWN_TRY(GetDevice()->ValidateObject(mLayout.Get()));
|
DAWN_TRY(GetDevice()->ValidateObject(mLayout.Get()));
|
||||||
if (group >= kMaxBindGroups) {
|
if (group >= kMaxBindGroups) {
|
||||||
|
|
|
@ -88,6 +88,25 @@ namespace dawn_native { namespace vulkan {
|
||||||
|
|
||||||
Device::~Device() {
|
Device::~Device() {
|
||||||
BaseDestructor();
|
BaseDestructor();
|
||||||
|
|
||||||
|
mDescriptorSetService = nullptr;
|
||||||
|
|
||||||
|
// We still need to properly handle Vulkan object deletion even if the device has been lost,
|
||||||
|
// so the Deleter and vkDevice cannot be destroyed in Device::Destroy().
|
||||||
|
// We need handle deleting all child objects by calling Tick() again with a large serial to
|
||||||
|
// force all operations to look as if they were completed, and delete all objects before
|
||||||
|
// destroying the Deleter and vkDevice.
|
||||||
|
mCompletedSerial = std::numeric_limits<Serial>::max();
|
||||||
|
mDeleter->Tick(mCompletedSerial);
|
||||||
|
mDeleter = nullptr;
|
||||||
|
|
||||||
|
// VkQueues are destroyed when the VkDevice is destroyed
|
||||||
|
// The VkDevice is needed to destroy child objects, so it must be destroyed last after all
|
||||||
|
// child objects have been deleted.
|
||||||
|
if (mVkDevice != VK_NULL_HANDLE) {
|
||||||
|
fn.DestroyDevice(mVkDevice, nullptr);
|
||||||
|
mVkDevice = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultOrError<BindGroupBase*> Device::CreateBindGroupImpl(
|
ResultOrError<BindGroupBase*> Device::CreateBindGroupImpl(
|
||||||
|
@ -766,24 +785,16 @@ namespace dawn_native { namespace vulkan {
|
||||||
|
|
||||||
// Free services explicitly so that they can free Vulkan objects before vkDestroyDevice
|
// Free services explicitly so that they can free Vulkan objects before vkDestroyDevice
|
||||||
mDynamicUploader = nullptr;
|
mDynamicUploader = nullptr;
|
||||||
mDescriptorSetService = nullptr;
|
|
||||||
|
|
||||||
// Releasing the uploader enqueues buffers to be released.
|
// Releasing the uploader enqueues buffers to be released.
|
||||||
// Call Tick() again to clear them before releasing the deleter.
|
// Call Tick() again to clear them before releasing the deleter.
|
||||||
mDeleter->Tick(mCompletedSerial);
|
mDeleter->Tick(mCompletedSerial);
|
||||||
|
|
||||||
mDeleter = nullptr;
|
|
||||||
mMapRequestTracker = nullptr;
|
mMapRequestTracker = nullptr;
|
||||||
|
|
||||||
// The VkRenderPasses in the cache can be destroyed immediately since all commands referring
|
// The VkRenderPasses in the cache can be destroyed immediately since all commands referring
|
||||||
// to them are guaranteed to be finished executing.
|
// to them are guaranteed to be finished executing.
|
||||||
mRenderPassCache = nullptr;
|
mRenderPassCache = nullptr;
|
||||||
|
|
||||||
// VkQueues are destroyed when the VkDevice is destroyed
|
|
||||||
if (mVkDevice != VK_NULL_HANDLE) {
|
|
||||||
fn.DestroyDevice(mVkDevice, nullptr);
|
|
||||||
mVkDevice = VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}} // namespace dawn_native::vulkan
|
}} // namespace dawn_native::vulkan
|
||||||
|
|
|
@ -81,6 +81,28 @@ TEST_P(DeviceLostTest, CreateBindGroupLayoutFails) {
|
||||||
ASSERT_DEVICE_ERROR(device.CreateBindGroupLayout(&descriptor));
|
ASSERT_DEVICE_ERROR(device.CreateBindGroupLayout(&descriptor));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that GetBindGroupLayout fails when device is lost
|
||||||
|
TEST_P(DeviceLostTest, GetBindGroupLayoutFails) {
|
||||||
|
wgpu::ShaderModule csModule =
|
||||||
|
utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, R"(
|
||||||
|
#version 450
|
||||||
|
layout(set = 0, binding = 0) uniform UniformBuffer {
|
||||||
|
vec4 pos;
|
||||||
|
};
|
||||||
|
void main() {
|
||||||
|
})");
|
||||||
|
|
||||||
|
wgpu::ComputePipelineDescriptor descriptor;
|
||||||
|
descriptor.layout = nullptr;
|
||||||
|
descriptor.computeStage.module = csModule;
|
||||||
|
descriptor.computeStage.entryPoint = "main";
|
||||||
|
|
||||||
|
wgpu::ComputePipeline pipeline = device.CreateComputePipeline(&descriptor);
|
||||||
|
|
||||||
|
SetCallbackAndLoseForTesting();
|
||||||
|
ASSERT_DEVICE_ERROR(pipeline.GetBindGroupLayout(0).Get());
|
||||||
|
}
|
||||||
|
|
||||||
// Test that CreateBindGroup fails when device is lost
|
// Test that CreateBindGroup fails when device is lost
|
||||||
TEST_P(DeviceLostTest, CreateBindGroupFails) {
|
TEST_P(DeviceLostTest, CreateBindGroupFails) {
|
||||||
SetCallbackAndLoseForTesting();
|
SetCallbackAndLoseForTesting();
|
||||||
|
@ -189,4 +211,5 @@ TEST_P(DeviceLostTest, TickFails) {
|
||||||
SetCallbackAndLoseForTesting();
|
SetCallbackAndLoseForTesting();
|
||||||
ASSERT_DEVICE_ERROR(device.Tick());
|
ASSERT_DEVICE_ERROR(device.Tick());
|
||||||
}
|
}
|
||||||
|
|
||||||
DAWN_INSTANTIATE_TEST(DeviceLostTest, D3D12Backend, VulkanBackend);
|
DAWN_INSTANTIATE_TEST(DeviceLostTest, D3D12Backend, VulkanBackend);
|
Loading…
Reference in New Issue