#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GRAPHICCONTEXT_H_ #define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GRAPHICCONTEXT_H_ #include "common/abi.h" #include "common/common.h" #include "common/threads.h" #include "graphics/host_gpu/vulkanCommon.h" // IWYU pragma: export #include #include #include #include #include namespace Libs::Graphics { struct VulkanBuffer; struct VulkanImage; struct VulkanMemory; inline constexpr uint32_t VULKAN_TARGET_API_VERSION = VK_API_VERSION_1_3; struct GraphicContext { vk::Instance instance = nullptr; vk::DebugUtilsMessengerEXT debug_messenger = nullptr; vk::PhysicalDevice physical_device = nullptr; vk::PhysicalDeviceProperties physical_device_properties = {}; vk::PhysicalDeviceMemoryProperties physical_device_memory_properties = {}; vk::Device device = nullptr; VmaAllocator allocator = nullptr; bool memory_budget_ext_enabled = false; bool rt_extensions_enabled = false; bool compute_subgroup_size_control_enabled = false; bool compute_wave64_supported = false; bool sample_rate_shading_enabled = false; uint32_t subgroup_size = 0; uint32_t min_subgroup_size = 0; uint32_t max_subgroup_size = 0; uint32_t max_push_descriptors = 0; vk::ShaderStageFlags required_subgroup_size_stages = {}; Common::Mutex queue_mutex; uint32_t queue_family = static_cast(-1); vk::Queue queue = nullptr; [[nodiscard]] const vk::PhysicalDeviceProperties& GetPhysicalDeviceProperties() const { return physical_device_properties; } [[nodiscard]] const vk::PhysicalDeviceMemoryProperties& GetPhysicalDeviceMemoryProperties() const { return physical_device_memory_properties; } [[nodiscard]] vk::FormatProperties GetFormatProperties(vk::Format format) const { std::scoped_lock lock(m_format_properties_mutex); auto [it, inserted] = m_format_properties.try_emplace(format); if (inserted) { physical_device.getFormatProperties(format, &it->second); } return it->second; } [[nodiscard]] vk::Result GetImageFormatProperties(vk::Format format, vk::ImageType type, vk::ImageTiling tiling, vk::ImageUsageFlags usage, vk::ImageCreateFlags flags, vk::ImageFormatProperties* properties) const { using Key = std::tuple; std::scoped_lock lock(m_image_format_properties_mutex); auto [it, inserted] = m_image_format_properties.try_emplace(Key {format, type, tiling, usage, flags}); if (inserted) { it->second.first = physical_device.getImageFormatProperties(format, type, tiling, usage, flags, &it->second.second); } if (properties != nullptr) { *properties = it->second.second; } return it->second.first; } [[nodiscard]] vk::DeviceSize StorageMinAlignment() const { const auto alignment = physical_device_properties.limits.minStorageBufferOffsetAlignment; return alignment != 0 ? alignment : 1; } [[nodiscard]] bool CreateAllocator(); void DestroyAllocator(); void LogMemoryBudget() const; [[nodiscard]] bool CanReportMemoryUsage() const noexcept { return memory_budget_ext_enabled; } [[nodiscard]] uint64_t GetDeviceMemoryUsage() const; [[nodiscard]] uint64_t GetTotalMemoryBudget() const; void CreateBuffer(uint64_t size, VulkanBuffer& buffer); [[nodiscard]] bool CreateImage(const vk::ImageCreateInfo& info, VulkanImage& image); void DeleteImage(VulkanImage& image); void MapMemory(VulkanMemory& memory, void*& data); void UnmapMemory(VulkanMemory& memory); void AppendHardwareRayTracingDeviceExtensions( const std::vector& available_extensions, std::vector& device_extensions); void LoadHardwareRayTracingFunctions() const; uint32_t screen_width = 0; uint32_t screen_height = 0; private: mutable std::mutex m_format_properties_mutex; mutable std::map m_format_properties; mutable std::mutex m_image_format_properties_mutex; mutable std::map, std::pair> m_image_format_properties; }; struct VulkanMemory { vk::MemoryRequirements requirements = {}; vk::MemoryPropertyFlags property = {}; vk::MemoryPropertyFlags preferred_property = {}; vk::DeviceMemory memory = nullptr; VmaAllocation allocation = nullptr; VmaAllocationInfo allocation_info = {}; vk::DeviceSize offset = 0; uint32_t type = 0; uint64_t unique_id = 0; }; struct VulkanImageState { vk::PipelineStageFlags2 pl_stage = vk::PipelineStageFlagBits2::eAllCommands; vk::AccessFlags2 access_mask = vk::AccessFlagBits2::eNone; vk::ImageLayout layout = vk::ImageLayout::eUndefined; }; struct VulkanImage { VulkanImage() = default; KYTY_CLASS_NO_COPY(VulkanImage); vk::Format format = vk::Format::eUndefined; vk::ImageType image_type = vk::ImageType::e2D; vk::Extent3D extent = {1, 1, 1}; uint32_t guest_pitch = 0; uint32_t layers = 1; uint32_t mip_levels = 1; uint32_t samples = 1; vk::ImageUsageFlags usage = {}; vk::ImageCreateFlags flags = {}; vk::Image image = nullptr; VulkanImageState state; std::vector subresource_states; Graphics::VulkanMemory memory; }; struct VulkanBuffer { vk::Buffer buffer = nullptr; VulkanMemory memory; vk::BufferUsageFlags usage = {}; uint64_t buffer_size = 0; }; } // namespace Libs::Graphics #endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GRAPHICCONTEXT_H_ */