#pragma once #include #include #include #include #include namespace orange { struct BufferSlice { VkBuffer buffer; VkDeviceSize offset; VkDeviceSize size; void* ptr; }; struct GPUMemoryBuffer { VkDeviceMemory memory; VkBuffer buffer; VkDeviceSize size; void* ptr; }; class MemoryPool { public: MemoryPool(GPUMemoryBuffer buffer) : m_buffer{ buffer } {} Result AllocSlice(VkDeviceSize size, VkDeviceSize alignment = 1u) { uint32_t offset = Align(m_offset, alignment); BufferSlice slice{ m_buffer.buffer, offset, size, m_buffer.ptr ? reinterpret_cast(m_buffer.ptr) + offset : nullptr }; if (offset + size > m_buffer.size) return Result::Error(); m_offset = offset + size; return Result::Success(slice); } VkDeviceMemory Memory() const { return m_buffer.memory; } private: GPUMemoryBuffer m_buffer = {}; VkDeviceSize m_offset = 0u; }; template using VulkanResult = Result; struct VkMemoryTypes { uint32_t cpuTypeIdx = -1; uint32_t gpuOnlyTypeIdx = -1; uint32_t gpuHostVisibleTypeIdx = -1; }; class RenderContext { public: ~RenderContext(); static VulkanResult Create(const char *appName); VkInstance Instance() const { return m_instance; } VkPhysicalDevice PhysicalDevice() const { return m_physicalDevice; } VkDevice Device() const { return m_device; } VkQueue Queue() const { return m_queue; } VkCommandPool CommandPool() const { return m_commandPool; } VulkanResult CreateFence(bool signalled); VulkanResult CreateSemaphore(); VulkanResult BeginCommandBuffer(VkCommandBuffer buffer); VulkanResult EndCommandBuffer(VkCommandBuffer buffer); VulkanResult CreateBuffer(VkDeviceSize size); VulkanResult CreateImage(MemoryPool& pool, uint32_t width, uint32_t height, VkFormat format, VkImageUsageFlags usage); VulkanResult CreateImageView(VkImage image, VkFormat format, VkImageAspectFlagBits aspect); VulkanResult CreateShader(Span code); const VkPhysicalDeviceProperties& Props() const { return m_props; } protected: friend VulkanResult; RenderContext(VkInstance instance, VkPhysicalDevice physicalDevice, VkDevice device, VkQueue queue, VkCommandPool commandPool) : m_instance{ instance }, m_physicalDevice{ physicalDevice }, m_device{ device } , m_queue{ queue }, m_commandPool{ commandPool } { VkPhysicalDeviceMemoryProperties memoryProps; vkGetPhysicalDeviceMemoryProperties(m_physicalDevice, &memoryProps); struct { uint32_t* ptr; VkMemoryPropertyFlags flags; } memoryTypeMapping[] = { { &m_memoryTypes.gpuHostVisibleTypeIdx, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT }, { &m_memoryTypes.gpuOnlyTypeIdx, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT }, { &m_memoryTypes.cpuTypeIdx, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT }, }; for (auto& mapping : memoryTypeMapping) { for (uint32_t i = 0; i < memoryProps.memoryTypeCount; i++) { if (memoryProps.memoryTypes[i].propertyFlags & mapping.flags) { *mapping.ptr = i; if (memoryProps.memoryTypes[i].propertyFlags == mapping.flags) break; } } } vkGetPhysicalDeviceProperties(m_physicalDevice, &m_props); } private: VkInstance m_instance = VK_NULL_HANDLE; VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE; VkDevice m_device = VK_NULL_HANDLE; VkQueue m_queue = VK_NULL_HANDLE; VkCommandPool m_commandPool = VK_NULL_HANDLE; VkPhysicalDeviceProperties m_props{}; VkMemoryTypes m_memoryTypes{}; }; }