Vulkan: Fix crashes on Device destruction if Device::Initialize fails
If Device creation fails, several things are just partially initialized and the destroy sequence crashes dereferencing null data. This commit marks the Vulkan device as lost until after it is created. This avoids parts of the destroy sequence which are unecessary since the Device was never successfully created and no commands are in flight. Bug: chromium:1043095 Change-Id: I8e121709fa19b215e118a615b639380d1db1f3f2 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/15460 Reviewed-by: Kai Ninomiya <kainino@chromium.org> Commit-Queue: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
parent
13e2e139a5
commit
0df4753ba6
|
@ -50,6 +50,9 @@ namespace dawn_native { namespace vulkan {
|
||||||
if (descriptor != nullptr) {
|
if (descriptor != nullptr) {
|
||||||
ApplyToggleOverrides(descriptor);
|
ApplyToggleOverrides(descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the device as lost until successfully created.
|
||||||
|
mLossStatus = LossStatus::AlreadyLost;
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeError Device::Initialize() {
|
MaybeError Device::Initialize() {
|
||||||
|
@ -91,14 +94,22 @@ namespace dawn_native { namespace vulkan {
|
||||||
|
|
||||||
mDescriptorSetService = nullptr;
|
mDescriptorSetService = nullptr;
|
||||||
|
|
||||||
|
// The frontend asserts DynamicUploader is destructed by the backend.
|
||||||
|
// It is usually destructed in Destroy(), but Destroy isn't always called if device
|
||||||
|
// initialization failed.
|
||||||
|
mDynamicUploader = nullptr;
|
||||||
|
|
||||||
// We still need to properly handle Vulkan object deletion even if the device has been lost,
|
// 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().
|
// 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
|
// 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
|
// force all operations to look as if they were completed, and delete all objects before
|
||||||
// destroying the Deleter and vkDevice.
|
// destroying the Deleter and vkDevice.
|
||||||
mCompletedSerial = std::numeric_limits<Serial>::max();
|
// The Deleter may be null if initialization failed.
|
||||||
mDeleter->Tick(mCompletedSerial);
|
if (mDeleter != nullptr) {
|
||||||
mDeleter = nullptr;
|
mCompletedSerial = std::numeric_limits<Serial>::max();
|
||||||
|
mDeleter->Tick(mCompletedSerial);
|
||||||
|
mDeleter = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// VkQueues are destroyed when the VkDevice is destroyed
|
// VkQueues are destroyed when the VkDevice is destroyed
|
||||||
// The VkDevice is needed to destroy child objects, so it must be destroyed last after all
|
// The VkDevice is needed to destroy child objects, so it must be destroyed last after all
|
||||||
|
@ -406,6 +417,8 @@ namespace dawn_native { namespace vulkan {
|
||||||
DAWN_TRY(CheckVkSuccess(fn.CreateDevice(physicalDevice, &createInfo, nullptr, &mVkDevice),
|
DAWN_TRY(CheckVkSuccess(fn.CreateDevice(physicalDevice, &createInfo, nullptr, &mVkDevice),
|
||||||
"vkCreateDevice"));
|
"vkCreateDevice"));
|
||||||
|
|
||||||
|
// Device created. Mark it as alive.
|
||||||
|
mLossStatus = LossStatus::Alive;
|
||||||
return usedKnobs;
|
return usedKnobs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue