aboutsummaryrefslogtreecommitdiff
path: root/layers/core_validation.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'layers/core_validation.cpp')
-rw-r--r--layers/core_validation.cpp163
1 files changed, 89 insertions, 74 deletions
diff --git a/layers/core_validation.cpp b/layers/core_validation.cpp
index b2f71b36..fca9c8e9 100644
--- a/layers/core_validation.cpp
+++ b/layers/core_validation.cpp
@@ -3104,7 +3104,7 @@ static bool PreCallValidateFreeMemory(layer_data *dev_data, VkDeviceMemory mem,
return skip;
}
-static void PostCallRecordFreeMemory(layer_data *dev_data, VkDeviceMemory mem, DEVICE_MEM_INFO *mem_info, VK_OBJECT obj_struct) {
+static void PreCallRecordFreeMemory(layer_data *dev_data, VkDeviceMemory mem, DEVICE_MEM_INFO *mem_info, VK_OBJECT obj_struct) {
// Clear mem binding for any bound objects
for (auto obj : mem_info->obj_bindings) {
log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, get_debug_report_enum[obj.type], obj.handle,
@@ -3139,12 +3139,12 @@ VKAPI_ATTR void VKAPI_CALL FreeMemory(VkDevice device, VkDeviceMemory mem, const
unique_lock_t lock(global_lock);
bool skip = PreCallValidateFreeMemory(dev_data, mem, &mem_info, &obj_struct);
if (!skip) {
- lock.unlock();
- dev_data->dispatch_table.FreeMemory(device, mem, pAllocator);
- lock.lock();
if (mem != VK_NULL_HANDLE) {
- PostCallRecordFreeMemory(dev_data, mem, mem_info, obj_struct);
+ // Avoid free/alloc race by recording state change before dispatching
+ PreCallRecordFreeMemory(dev_data, mem, mem_info, obj_struct);
}
+ lock.unlock();
+ dev_data->dispatch_table.FreeMemory(device, mem, pAllocator);
}
}
@@ -3456,7 +3456,7 @@ static bool PreCallValidateDestroyFence(layer_data *dev_data, VkFence fence, FEN
return skip;
}
-static void PostCallRecordDestroyFence(layer_data *dev_data, VkFence fence) { dev_data->fenceMap.erase(fence); }
+static void PreCallRecordDestroyFence(layer_data *dev_data, VkFence fence) { dev_data->fenceMap.erase(fence); }
VKAPI_ATTR void VKAPI_CALL DestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator) {
layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
@@ -3467,10 +3467,10 @@ VKAPI_ATTR void VKAPI_CALL DestroyFence(VkDevice device, VkFence fence, const Vk
bool skip = PreCallValidateDestroyFence(dev_data, fence, &fence_node, &obj_struct);
if (!skip) {
+ // Pre-record to avoid Destroy/Create race
+ PreCallRecordDestroyFence(dev_data, fence);
lock.unlock();
dev_data->dispatch_table.DestroyFence(device, fence, pAllocator);
- lock.lock();
- PostCallRecordDestroyFence(dev_data, fence);
}
}
@@ -3486,7 +3486,7 @@ static bool PreCallValidateDestroySemaphore(layer_data *dev_data, VkSemaphore se
return skip;
}
-static void PostCallRecordDestroySemaphore(layer_data *dev_data, VkSemaphore sema) { dev_data->semaphoreMap.erase(sema); }
+static void PreCallRecordDestroySemaphore(layer_data *dev_data, VkSemaphore sema) { dev_data->semaphoreMap.erase(sema); }
VKAPI_ATTR void VKAPI_CALL DestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator) {
layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
@@ -3495,10 +3495,10 @@ VKAPI_ATTR void VKAPI_CALL DestroySemaphore(VkDevice device, VkSemaphore semapho
unique_lock_t lock(global_lock);
bool skip = PreCallValidateDestroySemaphore(dev_data, semaphore, &sema_node, &obj_struct);
if (!skip) {
+ // Pre-record to avoid Destroy/Create race
+ PreCallRecordDestroySemaphore(dev_data, semaphore);
lock.unlock();
dev_data->dispatch_table.DestroySemaphore(device, semaphore, pAllocator);
- lock.lock();
- PostCallRecordDestroySemaphore(dev_data, semaphore);
}
}
@@ -3513,7 +3513,7 @@ static bool PreCallValidateDestroyEvent(layer_data *dev_data, VkEvent event, EVE
return skip;
}
-static void PostCallRecordDestroyEvent(layer_data *dev_data, VkEvent event, EVENT_STATE *event_state, VK_OBJECT obj_struct) {
+static void PreCallRecordDestroyEvent(layer_data *dev_data, VkEvent event, EVENT_STATE *event_state, VK_OBJECT obj_struct) {
invalidateCommandBuffers(dev_data, event_state->cb_bindings, obj_struct);
dev_data->eventMap.erase(event);
}
@@ -3525,12 +3525,12 @@ VKAPI_ATTR void VKAPI_CALL DestroyEvent(VkDevice device, VkEvent event, const Vk
unique_lock_t lock(global_lock);
bool skip = PreCallValidateDestroyEvent(dev_data, event, &event_state, &obj_struct);
if (!skip) {
- lock.unlock();
- dev_data->dispatch_table.DestroyEvent(device, event, pAllocator);
- lock.lock();
if (event != VK_NULL_HANDLE) {
- PostCallRecordDestroyEvent(dev_data, event, event_state, obj_struct);
+ // Pre-record to avoid Destroy/Create race
+ PreCallRecordDestroyEvent(dev_data, event, event_state, obj_struct);
}
+ lock.unlock();
+ dev_data->dispatch_table.DestroyEvent(device, event, pAllocator);
}
}
@@ -3546,8 +3546,8 @@ static bool PreCallValidateDestroyQueryPool(layer_data *dev_data, VkQueryPool qu
return skip;
}
-static void PostCallRecordDestroyQueryPool(layer_data *dev_data, VkQueryPool query_pool, QUERY_POOL_NODE *qp_state,
- VK_OBJECT obj_struct) {
+static void PreCallRecordDestroyQueryPool(layer_data *dev_data, VkQueryPool query_pool, QUERY_POOL_NODE *qp_state,
+ VK_OBJECT obj_struct) {
invalidateCommandBuffers(dev_data, qp_state->cb_bindings, obj_struct);
dev_data->queryPoolMap.erase(query_pool);
}
@@ -3559,12 +3559,12 @@ VKAPI_ATTR void VKAPI_CALL DestroyQueryPool(VkDevice device, VkQueryPool queryPo
unique_lock_t lock(global_lock);
bool skip = PreCallValidateDestroyQueryPool(dev_data, queryPool, &qp_state, &obj_struct);
if (!skip) {
- lock.unlock();
- dev_data->dispatch_table.DestroyQueryPool(device, queryPool, pAllocator);
- lock.lock();
if (queryPool != VK_NULL_HANDLE) {
- PostCallRecordDestroyQueryPool(dev_data, queryPool, qp_state, obj_struct);
+ // Pre-record to avoid Destroy/Create race
+ PreCallRecordDestroyQueryPool(dev_data, queryPool, qp_state, obj_struct);
}
+ lock.unlock();
+ dev_data->dispatch_table.DestroyQueryPool(device, queryPool, pAllocator);
}
}
static bool PreCallValidateGetQueryPoolResults(layer_data *dev_data, VkQueryPool query_pool, uint32_t first_query,
@@ -3865,12 +3865,12 @@ VKAPI_ATTR void VKAPI_CALL DestroyBuffer(VkDevice device, VkBuffer buffer, const
unique_lock_t lock(global_lock);
bool skip = PreCallValidateDestroyBuffer(dev_data, buffer, &buffer_state, &obj_struct);
if (!skip) {
- lock.unlock();
- dev_data->dispatch_table.DestroyBuffer(device, buffer, pAllocator);
- lock.lock();
if (buffer != VK_NULL_HANDLE) {
- PostCallRecordDestroyBuffer(dev_data, buffer, buffer_state, obj_struct);
+ // Pre-record to avoid Destroy/Create race
+ PreCallRecordDestroyBuffer(dev_data, buffer, buffer_state, obj_struct);
}
+ lock.unlock();
+ dev_data->dispatch_table.DestroyBuffer(device, buffer, pAllocator);
}
}
@@ -3883,12 +3883,12 @@ VKAPI_ATTR void VKAPI_CALL DestroyBufferView(VkDevice device, VkBufferView buffe
// Validate state before calling down chain, update common data if we'll be calling down chain
bool skip = PreCallValidateDestroyBufferView(dev_data, bufferView, &buffer_view_state, &obj_struct);
if (!skip) {
- lock.unlock();
- dev_data->dispatch_table.DestroyBufferView(device, bufferView, pAllocator);
- lock.lock();
if (bufferView != VK_NULL_HANDLE) {
- PostCallRecordDestroyBufferView(dev_data, bufferView, buffer_view_state, obj_struct);
+ // Pre-record to avoid Destroy/Create race
+ PreCallRecordDestroyBufferView(dev_data, bufferView, buffer_view_state, obj_struct);
}
+ lock.unlock();
+ dev_data->dispatch_table.DestroyBufferView(device, bufferView, pAllocator);
}
}
@@ -3899,12 +3899,12 @@ VKAPI_ATTR void VKAPI_CALL DestroyImage(VkDevice device, VkImage image, const Vk
unique_lock_t lock(global_lock);
bool skip = PreCallValidateDestroyImage(dev_data, image, &image_state, &obj_struct);
if (!skip) {
- lock.unlock();
- dev_data->dispatch_table.DestroyImage(device, image, pAllocator);
- lock.lock();
if (image != VK_NULL_HANDLE) {
- PostCallRecordDestroyImage(dev_data, image, image_state, obj_struct);
+ // Pre-record to avoid Destroy/Create race
+ PreCallRecordDestroyImage(dev_data, image, image_state, obj_struct);
}
+ lock.unlock();
+ dev_data->dispatch_table.DestroyImage(device, image, pAllocator);
}
}
@@ -4283,12 +4283,12 @@ VKAPI_ATTR void VKAPI_CALL DestroyImageView(VkDevice device, VkImageView imageVi
unique_lock_t lock(global_lock);
bool skip = PreCallValidateDestroyImageView(dev_data, imageView, &image_view_state, &obj_struct);
if (!skip) {
- lock.unlock();
- dev_data->dispatch_table.DestroyImageView(device, imageView, pAllocator);
- lock.lock();
if (imageView != VK_NULL_HANDLE) {
- PostCallRecordDestroyImageView(dev_data, imageView, image_view_state, obj_struct);
+ // Pre-record to avoid Destroy/Create race
+ PreCallRecordDestroyImageView(dev_data, imageView, image_view_state, obj_struct);
}
+ lock.unlock();
+ dev_data->dispatch_table.DestroyImageView(device, imageView, pAllocator);
}
}
@@ -4297,6 +4297,7 @@ VKAPI_ATTR void VKAPI_CALL DestroyShaderModule(VkDevice device, VkShaderModule s
layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
unique_lock_t lock(global_lock);
+ // Pre-record to avoid Destroy/Create race
dev_data->shaderModuleMap.erase(shaderModule);
lock.unlock();
@@ -4315,8 +4316,8 @@ static bool PreCallValidateDestroyPipeline(layer_data *dev_data, VkPipeline pipe
return skip;
}
-static void PostCallRecordDestroyPipeline(layer_data *dev_data, VkPipeline pipeline, PIPELINE_STATE *pipeline_state,
- VK_OBJECT obj_struct) {
+static void PreCallRecordDestroyPipeline(layer_data *dev_data, VkPipeline pipeline, PIPELINE_STATE *pipeline_state,
+ VK_OBJECT obj_struct) {
// Any bound cmd buffers are now invalid
invalidateCommandBuffers(dev_data, pipeline_state->cb_bindings, obj_struct);
dev_data->pipelineMap.erase(pipeline);
@@ -4329,12 +4330,12 @@ VKAPI_ATTR void VKAPI_CALL DestroyPipeline(VkDevice device, VkPipeline pipeline,
unique_lock_t lock(global_lock);
bool skip = PreCallValidateDestroyPipeline(dev_data, pipeline, &pipeline_state, &obj_struct);
if (!skip) {
- lock.unlock();
- dev_data->dispatch_table.DestroyPipeline(device, pipeline, pAllocator);
- lock.lock();
if (pipeline != VK_NULL_HANDLE) {
- PostCallRecordDestroyPipeline(dev_data, pipeline, pipeline_state, obj_struct);
+ // Pre-record to avoid Destroy/Create race
+ PreCallRecordDestroyPipeline(dev_data, pipeline, pipeline_state, obj_struct);
}
+ lock.unlock();
+ dev_data->dispatch_table.DestroyPipeline(device, pipeline, pAllocator);
}
}
@@ -4342,6 +4343,7 @@ VKAPI_ATTR void VKAPI_CALL DestroyPipelineLayout(VkDevice device, VkPipelineLayo
const VkAllocationCallbacks *pAllocator) {
layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
unique_lock_t lock(global_lock);
+ // Pre-record to avoid Destroy/Create race
dev_data->pipelineLayoutMap.erase(pipelineLayout);
lock.unlock();
@@ -4360,8 +4362,8 @@ static bool PreCallValidateDestroySampler(layer_data *dev_data, VkSampler sample
return skip;
}
-static void PostCallRecordDestroySampler(layer_data *dev_data, VkSampler sampler, SAMPLER_STATE *sampler_state,
- VK_OBJECT obj_struct) {
+static void PreCallRecordDestroySampler(layer_data *dev_data, VkSampler sampler, SAMPLER_STATE *sampler_state,
+ VK_OBJECT obj_struct) {
// Any bound cmd buffers are now invalid
if (sampler_state) invalidateCommandBuffers(dev_data, sampler_state->cb_bindings, obj_struct);
dev_data->samplerMap.erase(sampler);
@@ -4374,16 +4376,16 @@ VKAPI_ATTR void VKAPI_CALL DestroySampler(VkDevice device, VkSampler sampler, co
unique_lock_t lock(global_lock);
bool skip = PreCallValidateDestroySampler(dev_data, sampler, &sampler_state, &obj_struct);
if (!skip) {
- lock.unlock();
- dev_data->dispatch_table.DestroySampler(device, sampler, pAllocator);
- lock.lock();
if (sampler != VK_NULL_HANDLE) {
- PostCallRecordDestroySampler(dev_data, sampler, sampler_state, obj_struct);
+ // Pre-record to avoid Destroy/Create race
+ PreCallRecordDestroySampler(dev_data, sampler, sampler_state, obj_struct);
}
+ lock.unlock();
+ dev_data->dispatch_table.DestroySampler(device, sampler, pAllocator);
}
}
-static void PostCallRecordDestroyDescriptorSetLayout(layer_data *dev_data, VkDescriptorSetLayout ds_layout) {
+static void PreCallRecordDestroyDescriptorSetLayout(layer_data *dev_data, VkDescriptorSetLayout ds_layout) {
auto layout_it = dev_data->descriptorSetLayoutMap.find(ds_layout);
if (layout_it != dev_data->descriptorSetLayoutMap.end()) {
layout_it->second.get()->MarkDestroyed();
@@ -4394,9 +4396,12 @@ static void PostCallRecordDestroyDescriptorSetLayout(layer_data *dev_data, VkDes
VKAPI_ATTR void VKAPI_CALL DestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout,
const VkAllocationCallbacks *pAllocator) {
layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+ {
+ lock_guard_t lock(global_lock);
+ // Pre-record to avoid Destroy/Create race
+ PreCallRecordDestroyDescriptorSetLayout(dev_data, descriptorSetLayout);
+ }
dev_data->dispatch_table.DestroyDescriptorSetLayout(device, descriptorSetLayout, pAllocator);
- unique_lock_t lock(global_lock);
- PostCallRecordDestroyDescriptorSetLayout(dev_data, descriptorSetLayout);
}
static bool PreCallValidateDestroyDescriptorPool(layer_data *dev_data, VkDescriptorPool pool,
@@ -4434,6 +4439,7 @@ VKAPI_ATTR void VKAPI_CALL DestroyDescriptorPool(VkDevice device, VkDescriptorPo
unique_lock_t lock(global_lock);
bool skip = PreCallValidateDestroyDescriptorPool(dev_data, descriptorPool, &desc_pool_state, &obj_struct);
if (!skip) {
+ // Pre-record to avoid Destroy/Create race
PreCallRecordDestroyDescriptorPool(dev_data, descriptorPool, desc_pool_state, obj_struct);
lock.unlock();
dev_data->dispatch_table.DestroyDescriptorPool(device, descriptorPool, pAllocator);
@@ -4575,6 +4581,7 @@ VKAPI_ATTR void VKAPI_CALL DestroyCommandPool(VkDevice device, VkCommandPool com
unique_lock_t lock(global_lock);
bool skip = PreCallValidateDestroyCommandPool(dev_data, commandPool);
if (!skip) {
+ // Pre-record to avoid Destroy/Create race
PreCallRecordDestroyCommandPool(dev_data, commandPool);
lock.unlock();
dev_data->dispatch_table.DestroyCommandPool(device, commandPool, pAllocator);
@@ -4675,8 +4682,8 @@ static bool PreCallValidateDestroyFramebuffer(layer_data *dev_data, VkFramebuffe
return skip;
}
-static void PostCallRecordDestroyFramebuffer(layer_data *dev_data, VkFramebuffer framebuffer, FRAMEBUFFER_STATE *framebuffer_state,
- VK_OBJECT obj_struct) {
+static void PreCallRecordDestroyFramebuffer(layer_data *dev_data, VkFramebuffer framebuffer, FRAMEBUFFER_STATE *framebuffer_state,
+ VK_OBJECT obj_struct) {
invalidateCommandBuffers(dev_data, framebuffer_state->cb_bindings, obj_struct);
dev_data->frameBufferMap.erase(framebuffer);
}
@@ -4688,12 +4695,12 @@ VKAPI_ATTR void VKAPI_CALL DestroyFramebuffer(VkDevice device, VkFramebuffer fra
unique_lock_t lock(global_lock);
bool skip = PreCallValidateDestroyFramebuffer(dev_data, framebuffer, &framebuffer_state, &obj_struct);
if (!skip) {
- lock.unlock();
- dev_data->dispatch_table.DestroyFramebuffer(device, framebuffer, pAllocator);
- lock.lock();
if (framebuffer != VK_NULL_HANDLE) {
- PostCallRecordDestroyFramebuffer(dev_data, framebuffer, framebuffer_state, obj_struct);
+ // Pre-record to avoid Destroy/Create race
+ PreCallRecordDestroyFramebuffer(dev_data, framebuffer, framebuffer_state, obj_struct);
}
+ lock.unlock();
+ dev_data->dispatch_table.DestroyFramebuffer(device, framebuffer, pAllocator);
}
}
@@ -4709,8 +4716,8 @@ static bool PreCallValidateDestroyRenderPass(layer_data *dev_data, VkRenderPass
return skip;
}
-static void PostCallRecordDestroyRenderPass(layer_data *dev_data, VkRenderPass render_pass, RENDER_PASS_STATE *rp_state,
- VK_OBJECT obj_struct) {
+static void PreCallRecordDestroyRenderPass(layer_data *dev_data, VkRenderPass render_pass, RENDER_PASS_STATE *rp_state,
+ VK_OBJECT obj_struct) {
invalidateCommandBuffers(dev_data, rp_state->cb_bindings, obj_struct);
dev_data->renderPassMap.erase(render_pass);
}
@@ -4722,12 +4729,12 @@ VKAPI_ATTR void VKAPI_CALL DestroyRenderPass(VkDevice device, VkRenderPass rende
unique_lock_t lock(global_lock);
bool skip = PreCallValidateDestroyRenderPass(dev_data, renderPass, &rp_state, &obj_struct);
if (!skip) {
- lock.unlock();
- dev_data->dispatch_table.DestroyRenderPass(device, renderPass, pAllocator);
- lock.lock();
if (renderPass != VK_NULL_HANDLE) {
- PostCallRecordDestroyRenderPass(dev_data, renderPass, rp_state, obj_struct);
+ // Pre-record to avoid Destroy/Create race
+ PreCallRecordDestroyRenderPass(dev_data, renderPass, rp_state, obj_struct);
}
+ lock.unlock();
+ dev_data->dispatch_table.DestroyRenderPass(device, renderPass, pAllocator);
}
}
@@ -4886,6 +4893,7 @@ VKAPI_ATTR VkResult VKAPI_CALL CreatePipelineCache(VkDevice device, const VkPipe
VKAPI_ATTR void VKAPI_CALL DestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache,
const VkAllocationCallbacks *pAllocator) {
layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+ // Pre-record to avoid Destroy/Create race (if/when implemented)
dev_data->dispatch_table.DestroyPipelineCache(device, pipelineCache, pAllocator);
}
@@ -5870,9 +5878,9 @@ static bool PreCallValidateFreeDescriptorSets(const layer_data *dev_data, VkDesc
}
return skip;
}
-// Sets have been removed from the pool so update underlying state
-static void PostCallRecordFreeDescriptorSets(layer_data *dev_data, VkDescriptorPool pool, uint32_t count,
- const VkDescriptorSet *descriptor_sets) {
+// Sets are being returned to the pool so update the pool state
+static void PreCallRecordFreeDescriptorSets(layer_data *dev_data, VkDescriptorPool pool, uint32_t count,
+ const VkDescriptorSet *descriptor_sets) {
DESCRIPTOR_POOL_STATE *pool_state = GetDescriptorPoolState(dev_data, pool);
// Update available descriptor sets in pool
pool_state->availableSets += count;
@@ -5899,14 +5907,15 @@ VKAPI_ATTR VkResult VKAPI_CALL FreeDescriptorSets(VkDevice device, VkDescriptorP
// Make sure that no sets being destroyed are in-flight
unique_lock_t lock(global_lock);
bool skip = PreCallValidateFreeDescriptorSets(dev_data, descriptorPool, count, pDescriptorSets);
- lock.unlock();
- if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
- VkResult result = dev_data->dispatch_table.FreeDescriptorSets(device, descriptorPool, count, pDescriptorSets);
- if (VK_SUCCESS == result) {
- lock.lock();
- PostCallRecordFreeDescriptorSets(dev_data, descriptorPool, count, pDescriptorSets);
+ VkResult result;
+ if (skip) {
+ result = VK_ERROR_VALIDATION_FAILED_EXT;
+ } else {
+ // A race here is invalid (descriptorPool should be externally sync'd), but code defensively against an invalid race
+ PreCallRecordFreeDescriptorSets(dev_data, descriptorPool, count, pDescriptorSets);
lock.unlock();
+ result = dev_data->dispatch_table.FreeDescriptorSets(device, descriptorPool, count, pDescriptorSets);
}
return result;
}
@@ -10863,6 +10872,7 @@ VKAPI_ATTR void VKAPI_CALL DestroySwapchainKHR(VkDevice device, VkSwapchainKHR s
unique_lock_t lock(global_lock);
auto swapchain_data = GetSwapchainNode(dev_data, swapchain);
if (swapchain_data) {
+ // Pre-record to avoid Destroy/Create race
if (swapchain_data->images.size() > 0) {
for (auto swapchain_image : swapchain_data->images) {
auto image_sub = dev_data->imageSubresourceMap.find(swapchain_image);
@@ -11548,7 +11558,10 @@ VKAPI_ATTR void VKAPI_CALL DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR s
HandleToUint64(instance), VALIDATION_ERROR_26c009e4,
"vkDestroySurfaceKHR() called before its associated VkSwapchainKHR was destroyed.");
}
+
+ // Pre-record to avoid Destroy/Create race
instance_data->surface_map.erase(surface);
+
lock.unlock();
if (!skip) {
instance_data->dispatch_table.DestroySurfaceKHR(instance, surface, pAllocator);
@@ -12346,6 +12359,7 @@ VKAPI_ATTR void VKAPI_CALL DestroyDescriptorUpdateTemplate(VkDevice device, VkDe
const VkAllocationCallbacks *pAllocator) {
layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
unique_lock_t lock(global_lock);
+ // Pre-record to avoid Destroy/Create race
PreCallRecordDestroyDescriptorUpdateTemplate(device_data, descriptorUpdateTemplate);
lock.unlock();
device_data->dispatch_table.DestroyDescriptorUpdateTemplate(device, descriptorUpdateTemplate, pAllocator);
@@ -12356,6 +12370,7 @@ VKAPI_ATTR void VKAPI_CALL DestroyDescriptorUpdateTemplateKHR(VkDevice device,
const VkAllocationCallbacks *pAllocator) {
layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
unique_lock_t lock(global_lock);
+ // Pre-record to avoid Destroy/Create race
PreCallRecordDestroyDescriptorUpdateTemplate(device_data, descriptorUpdateTemplate);
lock.unlock();
device_data->dispatch_table.DestroyDescriptorUpdateTemplateKHR(device, descriptorUpdateTemplate, pAllocator);