#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 #include namespace Libs::Graphics { struct VulkanImage; 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 compute_subgroup_size_control_enabled = false; bool sample_rate_shading_enabled = false; bool shader_image_int64_atomics_enabled = false; // bool fp64_denorm_preserve = false; // Temporarily disabled. bool attachment_feedback_loop_enabled = false; bool provoking_vertex_last_enabled = false; bool maintenance8_enabled = false; bool supports_block_texel_view = false; bool mesh_shader_enabled = false; vk::PhysicalDeviceMeshShaderPropertiesEXT mesh_shader_properties = {}; 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]] bool SupportsComputeWave64() const noexcept { return subgroup_size == 64u || compute_subgroup_size_control_enabled; } [[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; struct HeapUsage { uint64_t usage = 0; // Whole process, as reported by VK_EXT_memory_budget. uint64_t budget = 0; uint32_t allocations = 0; bool device_local = false; }; [[nodiscard]] uint32_t GetHeapUsage(std::span heaps) const; [[nodiscard]] bool CreateImage(const vk::ImageCreateInfo& info, VulkanImage& image); void DeleteImage(VulkanImage& image); 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 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 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; VmaAllocation allocation = nullptr; }; } // namespace Libs::Graphics #endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GRAPHICCONTEXT_H_ */