#ifndef LAYER_CONTEXT_HH_ #define LAYER_CONTEXT_HH_ #include #include #include "device_context.hh" #include "instance_context.hh" #include "queue_context.hh" // The purpose of this file is to provide a definition for the highest level // entry point struct of our vulkan state. // // All Context structs have deleted copy/move constructors. This is because we // want to be extremely explicit with how/when we delete things, and this allows // us to use destructors for cleanup without much worry about weird copies // floating around. Most contexts will probably live inside std::unique_ptr's as // a result so they can be used in standard containers. namespace low_latency { template concept DispatchableType = std::same_as, VkInstance> || std::same_as, VkDevice> || std::same_as, VkPhysicalDevice> || std::same_as, VkQueue>; struct LayerContext { public: using ContextVariant = std::variant, std::unique_ptr>; public: std::mutex mutex; std::unordered_map contexts; std::uint64_t current_frame = 0; public: LayerContext(); LayerContext(const LayerContext&) = delete; LayerContext(LayerContext&&) = delete; LayerContext operator==(const LayerContext&) = delete; LayerContext operator==(LayerContext&&) = delete; ~LayerContext(); public: template static void* get_key(const T& dt) { return *reinterpret_cast(dt); } template requires(!std::same_as) T& get_context(const DispatchableType& dt) { const auto key = get_key(dt); const auto it = this->contexts.find(key); assert(it != std::end(this->contexts)); const auto ptr = std::get_if>(&it->second); assert(ptr && *ptr); return **ptr; } // QueueContext's are actually owned by a device so look there instead. template requires(std::same_as) T& get_context(const DispatchableType& dt) { const auto& device_context = this->get_context(dt); const auto& queue_context = device_context.queue_contexts; const auto it = device_context.queue_contexts.find(dt); assert(it != std::end(queue_context)); const auto& ptr = it->second; return *ptr; } }; }; // namespace low_latency #endif