diff options
Diffstat (limited to 'layers/threading.h')
-rw-r--r-- | layers/threading.h | 445 |
1 files changed, 0 insertions, 445 deletions
diff --git a/layers/threading.h b/layers/threading.h deleted file mode 100644 index 4404692f1..000000000 --- a/layers/threading.h +++ /dev/null @@ -1,445 +0,0 @@ -/* Copyright (c) 2015-2018 The Khronos Group Inc. - * Copyright (c) 2015-2018 Valve Corporation - * Copyright (c) 2015-2018 LunarG, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Author: Cody Northrop <cody@lunarg.com> - * Author: Mike Stroyan <mike@LunarG.com> - */ - -#ifndef THREADING_H -#define THREADING_H -#include <condition_variable> -#include <mutex> -#include <vector> -#include <unordered_set> -#include <string> -#include "vk_layer_config.h" -#include "vk_layer_logging.h" - -VK_DEFINE_NON_DISPATCHABLE_HANDLE(DISTINCT_NONDISPATCHABLE_PHONY_HANDLE) -// The following line must match the vulkan_core.h condition guarding VK_DEFINE_NON_DISPATCHABLE_HANDLE -#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || \ - defined(_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) -// If pointers are 64-bit, then there can be separate counters for each -// NONDISPATCHABLE_HANDLE type. Otherwise they are all typedef uint64_t. -#define DISTINCT_NONDISPATCHABLE_HANDLES -// Make sure we catch any disagreement between us and the vulkan definition -static_assert(std::is_pointer<DISTINCT_NONDISPATCHABLE_PHONY_HANDLE>::value, - "Mismatched non-dispatchable handle handle, expected pointer type."); -#else -// Make sure we catch any disagreement between us and the vulkan definition -static_assert(std::is_same<uint64_t, DISTINCT_NONDISPATCHABLE_PHONY_HANDLE>::value, - "Mismatched non-dispatchable handle handle, expected uint64_t."); -#endif - -// Suppress unused warning on Linux -#if defined(__GNUC__) -#define DECORATE_UNUSED __attribute__((unused)) -#else -#define DECORATE_UNUSED -#endif - -// clang-format off -static const char DECORATE_UNUSED *kVUID_Threading_Info = "UNASSIGNED-Threading-Info"; -static const char DECORATE_UNUSED *kVUID_Threading_MultipleThreads = "UNASSIGNED-Threading-MultipleThreads"; -static const char DECORATE_UNUSED *kVUID_Threading_SingleThreadReuse = "UNASSIGNED-Threading-SingleThreadReuse"; -// clang-format on - -#undef DECORATE_UNUSED - -struct object_use_data { - loader_platform_thread_id thread; - int reader_count; - int writer_count; -}; - -struct layer_data; - -namespace threading { -volatile bool vulkan_in_use = false; -volatile bool vulkan_multi_threaded = false; -// starting check if an application is using vulkan from multiple threads. -inline bool startMultiThread() { - if (vulkan_multi_threaded) { - return true; - } - if (vulkan_in_use) { - vulkan_multi_threaded = true; - return true; - } - vulkan_in_use = true; - return false; -} - -// finishing check if an application is using vulkan from multiple threads. -inline void finishMultiThread() { vulkan_in_use = false; } -} // namespace threading - -template <typename T> -class counter { - public: - const char *typeName; - VkDebugReportObjectTypeEXT objectType; - std::unordered_map<T, object_use_data> uses; - std::mutex counter_lock; - std::condition_variable counter_condition; - void startWrite(debug_report_data *report_data, T object) { - if (object == VK_NULL_HANDLE) { - return; - } - bool skipCall = false; - loader_platform_thread_id tid = loader_platform_get_thread_id(); - std::unique_lock<std::mutex> lock(counter_lock); - if (uses.find(object) == uses.end()) { - // There is no current use of the object. Record writer thread. - struct object_use_data *use_data = &uses[object]; - use_data->reader_count = 0; - use_data->writer_count = 1; - use_data->thread = tid; - } else { - struct object_use_data *use_data = &uses[object]; - if (use_data->reader_count == 0) { - // There are no readers. Two writers just collided. - if (use_data->thread != tid) { - skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, (uint64_t)(object), - kVUID_Threading_MultipleThreads, - "THREADING ERROR : object of type %s is simultaneously used in " - "thread 0x%" PRIx64 " and thread 0x%" PRIx64, - typeName, (uint64_t)use_data->thread, (uint64_t)tid); - if (skipCall) { - // Wait for thread-safe access to object instead of skipping call. - while (uses.find(object) != uses.end()) { - counter_condition.wait(lock); - } - // There is now no current use of the object. Record writer thread. - struct object_use_data *new_use_data = &uses[object]; - new_use_data->thread = tid; - new_use_data->reader_count = 0; - new_use_data->writer_count = 1; - } else { - // Continue with an unsafe use of the object. - use_data->thread = tid; - use_data->writer_count += 1; - } - } else { - // This is either safe multiple use in one call, or recursive use. - // There is no way to make recursion safe. Just forge ahead. - use_data->writer_count += 1; - } - } else { - // There are readers. This writer collided with them. - if (use_data->thread != tid) { - skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, (uint64_t)(object), - kVUID_Threading_MultipleThreads, - "THREADING ERROR : object of type %s is simultaneously used in " - "thread 0x%" PRIx64 " and thread 0x%" PRIx64, - typeName, (uint64_t)use_data->thread, (uint64_t)tid); - if (skipCall) { - // Wait for thread-safe access to object instead of skipping call. - while (uses.find(object) != uses.end()) { - counter_condition.wait(lock); - } - // There is now no current use of the object. Record writer thread. - struct object_use_data *new_use_data = &uses[object]; - new_use_data->thread = tid; - new_use_data->reader_count = 0; - new_use_data->writer_count = 1; - } else { - // Continue with an unsafe use of the object. - use_data->thread = tid; - use_data->writer_count += 1; - } - } else { - // This is either safe multiple use in one call, or recursive use. - // There is no way to make recursion safe. Just forge ahead. - use_data->writer_count += 1; - } - } - } - } - - void finishWrite(T object) { - if (object == VK_NULL_HANDLE) { - return; - } - // Object is no longer in use - std::unique_lock<std::mutex> lock(counter_lock); - uses[object].writer_count -= 1; - if ((uses[object].reader_count == 0) && (uses[object].writer_count == 0)) { - uses.erase(object); - } - // Notify any waiting threads that this object may be safe to use - lock.unlock(); - counter_condition.notify_all(); - } - - void startRead(debug_report_data *report_data, T object) { - if (object == VK_NULL_HANDLE) { - return; - } - bool skipCall = false; - loader_platform_thread_id tid = loader_platform_get_thread_id(); - std::unique_lock<std::mutex> lock(counter_lock); - if (uses.find(object) == uses.end()) { - // There is no current use of the object. Record reader count - struct object_use_data *use_data = &uses[object]; - use_data->reader_count = 1; - use_data->writer_count = 0; - use_data->thread = tid; - } else if (uses[object].writer_count > 0 && uses[object].thread != tid) { - // There is a writer of the object. - skipCall |= - log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, (uint64_t)(object), kVUID_Threading_MultipleThreads, - "THREADING ERROR : object of type %s is simultaneously used in " - "thread 0x%" PRIx64 " and thread 0x%" PRIx64, - typeName, (uint64_t)uses[object].thread, (uint64_t)tid); - if (skipCall) { - // Wait for thread-safe access to object instead of skipping call. - while (uses.find(object) != uses.end()) { - counter_condition.wait(lock); - } - // There is no current use of the object. Record reader count - struct object_use_data *use_data = &uses[object]; - use_data->reader_count = 1; - use_data->writer_count = 0; - use_data->thread = tid; - } else { - uses[object].reader_count += 1; - } - } else { - // There are other readers of the object. Increase reader count - uses[object].reader_count += 1; - } - } - void finishRead(T object) { - if (object == VK_NULL_HANDLE) { - return; - } - std::unique_lock<std::mutex> lock(counter_lock); - uses[object].reader_count -= 1; - if ((uses[object].reader_count == 0) && (uses[object].writer_count == 0)) { - uses.erase(object); - } - // Notify any waiting threads that this object may be safe to use - lock.unlock(); - counter_condition.notify_all(); - } - counter(const char *name = "", VkDebugReportObjectTypeEXT type = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT) { - typeName = name; - objectType = type; - } -}; - -struct layer_data { - VkInstance instance; - - debug_report_data *report_data; - std::vector<VkDebugReportCallbackEXT> logging_callback; - std::vector<VkDebugUtilsMessengerEXT> logging_messenger; - VkLayerDispatchTable *device_dispatch_table; - VkLayerInstanceDispatchTable *instance_dispatch_table; - std::unordered_set<std::string> device_extension_set; - - // The following are for keeping track of the temporary callbacks that can - // be used in vkCreateInstance and vkDestroyInstance: - uint32_t num_tmp_report_callbacks; - VkDebugReportCallbackCreateInfoEXT *tmp_report_create_infos; - VkDebugReportCallbackEXT *tmp_report_callbacks; - uint32_t num_tmp_debug_messengers; - VkDebugUtilsMessengerCreateInfoEXT *tmp_messenger_create_infos; - VkDebugUtilsMessengerEXT *tmp_debug_messengers; - - counter<VkCommandBuffer> c_VkCommandBuffer; - counter<VkDevice> c_VkDevice; - counter<VkInstance> c_VkInstance; - counter<VkQueue> c_VkQueue; -#ifdef DISTINCT_NONDISPATCHABLE_HANDLES - counter<VkBuffer> c_VkBuffer; - counter<VkBufferView> c_VkBufferView; - counter<VkCommandPool> c_VkCommandPool; - counter<VkDescriptorPool> c_VkDescriptorPool; - counter<VkDescriptorSet> c_VkDescriptorSet; - counter<VkDescriptorSetLayout> c_VkDescriptorSetLayout; - counter<VkDeviceMemory> c_VkDeviceMemory; - counter<VkEvent> c_VkEvent; - counter<VkFence> c_VkFence; - counter<VkFramebuffer> c_VkFramebuffer; - counter<VkImage> c_VkImage; - counter<VkImageView> c_VkImageView; - counter<VkPipeline> c_VkPipeline; - counter<VkPipelineCache> c_VkPipelineCache; - counter<VkPipelineLayout> c_VkPipelineLayout; - counter<VkQueryPool> c_VkQueryPool; - counter<VkRenderPass> c_VkRenderPass; - counter<VkSampler> c_VkSampler; - counter<VkSemaphore> c_VkSemaphore; - counter<VkShaderModule> c_VkShaderModule; - counter<VkDebugReportCallbackEXT> c_VkDebugReportCallbackEXT; - counter<VkObjectTableNVX> c_VkObjectTableNVX; - counter<VkIndirectCommandsLayoutNVX> c_VkIndirectCommandsLayoutNVX; - counter<VkDisplayKHR> c_VkDisplayKHR; - counter<VkDisplayModeKHR> c_VkDisplayModeKHR; - counter<VkSurfaceKHR> c_VkSurfaceKHR; - counter<VkSwapchainKHR> c_VkSwapchainKHR; - counter<VkDescriptorUpdateTemplateKHR> c_VkDescriptorUpdateTemplateKHR; - counter<VkValidationCacheEXT> c_VkValidationCacheEXT; - counter<VkSamplerYcbcrConversionKHR> c_VkSamplerYcbcrConversionKHR; - counter<VkDebugUtilsMessengerEXT> c_VkDebugUtilsMessengerEXT; - counter<VkAccelerationStructureNVX> c_VkAccelerationStructureNVX; -#else // DISTINCT_NONDISPATCHABLE_HANDLES - counter<uint64_t> c_uint64_t; -#endif // DISTINCT_NONDISPATCHABLE_HANDLES - - layer_data() - : report_data(nullptr), - num_tmp_report_callbacks(0), - tmp_report_create_infos(nullptr), - tmp_report_callbacks(nullptr), - num_tmp_debug_messengers(0), - tmp_messenger_create_infos(nullptr), - tmp_debug_messengers(nullptr), - c_VkCommandBuffer("VkCommandBuffer", VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT), - c_VkDevice("VkDevice", VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT), - c_VkInstance("VkInstance", VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT), - c_VkQueue("VkQueue", VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT), -#ifdef DISTINCT_NONDISPATCHABLE_HANDLES - c_VkBuffer("VkBuffer", VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT), - c_VkBufferView("VkBufferView", VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT), - c_VkCommandPool("VkCommandPool", VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT), - c_VkDescriptorPool("VkDescriptorPool", VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT), - c_VkDescriptorSet("VkDescriptorSet", VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT), - c_VkDescriptorSetLayout("VkDescriptorSetLayout", VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT), - c_VkDeviceMemory("VkDeviceMemory", VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT), - c_VkEvent("VkEvent", VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT), - c_VkFence("VkFence", VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT), - c_VkFramebuffer("VkFramebuffer", VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT), - c_VkImage("VkImage", VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT), - c_VkImageView("VkImageView", VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT), - c_VkPipeline("VkPipeline", VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT), - c_VkPipelineCache("VkPipelineCache", VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT), - c_VkPipelineLayout("VkPipelineLayout", VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT), - c_VkQueryPool("VkQueryPool", VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT), - c_VkRenderPass("VkRenderPass", VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT), - c_VkSampler("VkSampler", VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT), - c_VkSemaphore("VkSemaphore", VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT), - c_VkShaderModule("VkShaderModule", VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT), - c_VkDebugReportCallbackEXT("VkDebugReportCallbackEXT", VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT), - c_VkObjectTableNVX("VkObjectTableNVX", VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT), - c_VkIndirectCommandsLayoutNVX("VkIndirectCommandsLayoutNVX", - VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT), - c_VkDisplayKHR("VkDisplayKHR", VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT), - c_VkDisplayModeKHR("VkDisplayModeKHR", VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT), - c_VkSurfaceKHR("VkSurfaceKHR", VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT), - c_VkSwapchainKHR("VkSwapchainKHR", VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT), - c_VkDescriptorUpdateTemplateKHR("VkDescriptorUpdateTemplateKHR", - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT), - c_VkSamplerYcbcrConversionKHR("VkSamplerYcbcrConversionKHR", - VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT), - c_VkDebugUtilsMessengerEXT("VkDebugUtilsMessengerEXT", VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT), - c_VkAccelerationStructureNVX("VkAccelerationStructureNVX", VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NVX_EXT) -#else // DISTINCT_NONDISPATCHABLE_HANDLES - c_uint64_t("NON_DISPATCHABLE_HANDLE", VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT) -#endif // DISTINCT_NONDISPATCHABLE_HANDLES - {}; -}; - -#define WRAPPER(type) \ - static void startWriteObject(struct layer_data *my_data, type object) { \ - my_data->c_##type.startWrite(my_data->report_data, object); \ - } \ - static void finishWriteObject(struct layer_data *my_data, type object) { my_data->c_##type.finishWrite(object); } \ - static void startReadObject(struct layer_data *my_data, type object) { \ - my_data->c_##type.startRead(my_data->report_data, object); \ - } \ - static void finishReadObject(struct layer_data *my_data, type object) { my_data->c_##type.finishRead(object); } - -WRAPPER(VkDevice) -WRAPPER(VkInstance) -WRAPPER(VkQueue) -#ifdef DISTINCT_NONDISPATCHABLE_HANDLES -WRAPPER(VkBuffer) -WRAPPER(VkBufferView) -WRAPPER(VkCommandPool) -WRAPPER(VkDescriptorPool) -WRAPPER(VkDescriptorSet) -WRAPPER(VkDescriptorSetLayout) -WRAPPER(VkDeviceMemory) -WRAPPER(VkEvent) -WRAPPER(VkFence) -WRAPPER(VkFramebuffer) -WRAPPER(VkImage) -WRAPPER(VkImageView) -WRAPPER(VkPipeline) -WRAPPER(VkPipelineCache) -WRAPPER(VkPipelineLayout) -WRAPPER(VkQueryPool) -WRAPPER(VkRenderPass) -WRAPPER(VkSampler) -WRAPPER(VkSemaphore) -WRAPPER(VkShaderModule) -WRAPPER(VkDebugReportCallbackEXT) -WRAPPER(VkObjectTableNVX) -WRAPPER(VkIndirectCommandsLayoutNVX) -WRAPPER(VkDisplayKHR) -WRAPPER(VkDisplayModeKHR) -WRAPPER(VkSurfaceKHR) -WRAPPER(VkSwapchainKHR) -WRAPPER(VkDescriptorUpdateTemplateKHR) -WRAPPER(VkValidationCacheEXT) -WRAPPER(VkSamplerYcbcrConversionKHR) -WRAPPER(VkDebugUtilsMessengerEXT) -WRAPPER(VkAccelerationStructureNVX) -#else // DISTINCT_NONDISPATCHABLE_HANDLES -WRAPPER(uint64_t) -#endif // DISTINCT_NONDISPATCHABLE_HANDLES - -static std::unordered_map<void *, layer_data *> layer_data_map; -static std::mutex command_pool_lock; -static std::unordered_map<VkCommandBuffer, VkCommandPool> command_pool_map; - -// VkCommandBuffer needs check for implicit use of command pool -static void startWriteObject(struct layer_data *my_data, VkCommandBuffer object, bool lockPool = true) { - if (lockPool) { - std::unique_lock<std::mutex> lock(command_pool_lock); - VkCommandPool pool = command_pool_map[object]; - lock.unlock(); - startWriteObject(my_data, pool); - } - my_data->c_VkCommandBuffer.startWrite(my_data->report_data, object); -} -static void finishWriteObject(struct layer_data *my_data, VkCommandBuffer object, bool lockPool = true) { - my_data->c_VkCommandBuffer.finishWrite(object); - if (lockPool) { - std::unique_lock<std::mutex> lock(command_pool_lock); - VkCommandPool pool = command_pool_map[object]; - lock.unlock(); - finishWriteObject(my_data, pool); - } -} -static void startReadObject(struct layer_data *my_data, VkCommandBuffer object) { - std::unique_lock<std::mutex> lock(command_pool_lock); - VkCommandPool pool = command_pool_map[object]; - lock.unlock(); - startReadObject(my_data, pool); - my_data->c_VkCommandBuffer.startRead(my_data->report_data, object); -} -static void finishReadObject(struct layer_data *my_data, VkCommandBuffer object) { - my_data->c_VkCommandBuffer.finishRead(object); - std::unique_lock<std::mutex> lock(command_pool_lock); - VkCommandPool pool = command_pool_map[object]; - lock.unlock(); - finishReadObject(my_data, pool); -} -#endif // THREADING_H |