diff --git a/examples/VulkanTest/main.cpp b/examples/VulkanTest/main.cpp index 34333abb5..e8b9a7478 100644 --- a/examples/VulkanTest/main.cpp +++ b/examples/VulkanTest/main.cpp @@ -130,9 +130,6 @@ int main() Nz::UInt32 uniformSize = sizeof(ubo); - Nz::UniformBuffer uniformBuffer(uniformSize, Nz::DataStorage_Hardware, Nz::BufferUsage_Dynamic); - uniformBuffer.Fill(&ubo, 0, uniformSize); - Nz::RenderPipelineLayoutInfo pipelineLayoutInfo; auto& bindingInfo = pipelineLayoutInfo.bindings.emplace_back(); bindingInfo.index = 0; @@ -162,13 +159,14 @@ int main() Nz::Vk::DescriptorSet descriptorSet = descriptorPool.AllocateDescriptorSet(descriptorLayout); - Nz::RenderBuffer* renderBufferUB = static_cast(uniformBuffer.GetBuffer()->GetImpl()); - if (!renderBufferUB->Synchronize(&vulkanDevice)) + std::unique_ptr uniformBuffer = device->InstantiateBuffer(Nz::BufferType_Uniform); + if (!uniformBuffer->Initialize(uniformSize, Nz::BufferUsage_DeviceLocal)) { NazaraError("Failed to create uniform buffer"); return __LINE__; } - Nz::VulkanBuffer* uniformBufferImpl = static_cast(renderBufferUB->GetHardwareBuffer(&vulkanDevice)); + + Nz::VulkanBuffer* uniformBufferImpl = static_cast(uniformBuffer.get()); descriptorSet.WriteUniformDescriptor(0, uniformBufferImpl->GetBufferHandle(), 0, uniformSize); Nz::RenderPipelineInfo pipelineInfo; @@ -353,18 +351,6 @@ int main() } } - if (updateUniforms) - { - ubo.viewMatrix = Nz::Matrix4f::ViewMatrix(viewerPos, camAngles); - - uniformBuffer.Fill(&ubo, 0, uniformSize); - if (!renderBufferUB->Synchronize(&vulkanDevice)) - { - NazaraError("Failed to synchronize render buffer"); - return __LINE__; - } - } - ImageSync& syncPrimitives = frameSync[currentFrame]; syncPrimitives.inflightFence.Wait(); @@ -381,6 +367,18 @@ int main() inflightFences[imageIndex] = &syncPrimitives.inflightFence; inflightFences[imageIndex]->Reset(); + if (updateUniforms) + { + ubo.viewMatrix = Nz::Matrix4f::ViewMatrix(viewerPos, camAngles); + + void* mappedPtr = uniformBufferImpl->Map(Nz::BufferAccess_DiscardAndWrite, 0, sizeof(ubo)); + if (mappedPtr) + { + std::memcpy(mappedPtr, &ubo, sizeof(ubo)); + uniformBufferImpl->Unmap(); + } + } + if (!graphicsQueue.Submit(renderCmds[imageIndex], syncPrimitives.imageAvailableSemaphore, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, syncPrimitives.renderFinishedSemaphore, syncPrimitives.inflightFence)) return false; diff --git a/include/Nazara/Renderer/RenderDevice.hpp b/include/Nazara/Renderer/RenderDevice.hpp index 739471ea4..daf74ca2e 100644 --- a/include/Nazara/Renderer/RenderDevice.hpp +++ b/include/Nazara/Renderer/RenderDevice.hpp @@ -18,7 +18,6 @@ namespace Nz { - class Buffer; class ShaderStageImpl; class NAZARA_RENDERER_API RenderDevice @@ -27,7 +26,7 @@ namespace Nz RenderDevice() = default; virtual ~RenderDevice(); - virtual std::unique_ptr InstantiateBuffer(Buffer* parent, BufferType type) = 0; + virtual std::unique_ptr InstantiateBuffer(BufferType type) = 0; virtual std::unique_ptr InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo) = 0; virtual std::shared_ptr InstantiateRenderPipelineLayout(RenderPipelineLayoutInfo pipelineLayoutInfo) = 0; virtual std::shared_ptr InstantiateShaderStage(ShaderStageType type, ShaderLanguage lang, const void* source, std::size_t sourceSize) = 0; diff --git a/include/Nazara/Utility/Enums.hpp b/include/Nazara/Utility/Enums.hpp index 70c64e527..bc958a07a 100644 --- a/include/Nazara/Utility/Enums.hpp +++ b/include/Nazara/Utility/Enums.hpp @@ -56,10 +56,10 @@ namespace Nz enum BufferUsage { - BufferUsage_Dynamic, - BufferUsage_FastRead, + BufferUsage_DeviceLocal, + BufferUsage_DirectMapping, - BufferUsage_Max = BufferUsage_FastRead + BufferUsage_Max = BufferUsage_DirectMapping }; template<> diff --git a/include/Nazara/VulkanRenderer/Utils.hpp b/include/Nazara/VulkanRenderer/Utils.hpp index 71c0af4c4..3d772abca 100644 --- a/include/Nazara/VulkanRenderer/Utils.hpp +++ b/include/Nazara/VulkanRenderer/Utils.hpp @@ -12,9 +12,11 @@ #include #include #include +#include namespace Nz { + inline VkBufferUsageFlags ToVulkan(BufferType bufferType); inline VkFormat ToVulkan(ComponentType componentType); inline VkCullModeFlagBits ToVulkan(FaceSide faceSide); inline VkPolygonMode ToVulkan(FaceFilling faceFilling); @@ -26,7 +28,7 @@ namespace Nz inline VkStencilOp ToVulkan(StencilOperation stencilOp); inline VkVertexInputRate ToVulkan(VertexInputRate inputRate); - NAZARA_VULKANRENDERER_API String TranslateVulkanError(VkResult code); + NAZARA_VULKANRENDERER_API std::string TranslateVulkanError(VkResult code); } #include diff --git a/include/Nazara/VulkanRenderer/Utils.inl b/include/Nazara/VulkanRenderer/Utils.inl index 4c9b5616d..aa0f18d38 100644 --- a/include/Nazara/VulkanRenderer/Utils.inl +++ b/include/Nazara/VulkanRenderer/Utils.inl @@ -10,6 +10,19 @@ namespace Nz { + VkBufferUsageFlags ToVulkan(BufferType bufferType) + { + switch (bufferType) + { + case BufferType_Index: return VK_BUFFER_USAGE_INDEX_BUFFER_BIT; + case BufferType_Vertex: return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + case BufferType_Uniform: return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + } + + NazaraError("Unhandled BufferType 0x" + String::Number(bufferType, 16)); + return 0; + } + VkFormat ToVulkan(ComponentType componentType) { switch (componentType) diff --git a/include/Nazara/VulkanRenderer/VulkanBuffer.hpp b/include/Nazara/VulkanRenderer/VulkanBuffer.hpp index 52adcf253..190277143 100644 --- a/include/Nazara/VulkanRenderer/VulkanBuffer.hpp +++ b/include/Nazara/VulkanRenderer/VulkanBuffer.hpp @@ -18,12 +18,10 @@ namespace Nz { - class Buffer; - class NAZARA_VULKANRENDERER_API VulkanBuffer : public AbstractBuffer { public: - inline VulkanBuffer(Vk::Device& device, Buffer* parent, BufferType type); + inline VulkanBuffer(Vk::Device& device, BufferType type); VulkanBuffer(const VulkanBuffer&) = delete; VulkanBuffer(VulkanBuffer&&) = delete; ///TODO virtual ~VulkanBuffer(); @@ -35,18 +33,22 @@ namespace Nz DataStorage GetStorage() const override; - void* Map(BufferAccess access, UInt32 offset = 0, UInt32 size = 0) override; + void* Map(BufferAccess access, UInt32 offset, UInt32 size) override; bool Unmap() override; VulkanBuffer& operator=(const VulkanBuffer&) = delete; VulkanBuffer& operator=(VulkanBuffer&&) = delete; ///TODO private: - Buffer* m_parent; + Vk::Buffer m_stagingBuffer; + Vk::DeviceMemory m_stagingMemory; BufferType m_type; - Nz::Vk::Buffer m_buffer; - Nz::Vk::DeviceMemory m_memory; + BufferUsageFlags m_usage; + UInt32 m_size; + Vk::Buffer m_buffer; + Vk::Fence m_stagingFence; Vk::Device& m_device; + Vk::DeviceMemory m_memory; }; } diff --git a/include/Nazara/VulkanRenderer/VulkanBuffer.inl b/include/Nazara/VulkanRenderer/VulkanBuffer.inl index 2e210c149..41eef8918 100644 --- a/include/Nazara/VulkanRenderer/VulkanBuffer.inl +++ b/include/Nazara/VulkanRenderer/VulkanBuffer.inl @@ -7,14 +7,13 @@ namespace Nz { - inline VulkanBuffer::VulkanBuffer(Vk::Device& device, Buffer* /*parent*/, BufferType type) : + inline VulkanBuffer::VulkanBuffer(Vk::Device& device, BufferType type) : m_device(device), - m_parent(parent), m_type(type) { } - inline Nz::Vk::Buffer& Nz::VulkanBuffer::GetBufferHandle() + inline Vk::Buffer& VulkanBuffer::GetBufferHandle() { return m_buffer; } diff --git a/include/Nazara/VulkanRenderer/VulkanDevice.hpp b/include/Nazara/VulkanRenderer/VulkanDevice.hpp index 7fe07729a..fb4a11c79 100644 --- a/include/Nazara/VulkanRenderer/VulkanDevice.hpp +++ b/include/Nazara/VulkanRenderer/VulkanDevice.hpp @@ -23,7 +23,7 @@ namespace Nz VulkanDevice(VulkanDevice&&) = delete; ///TODO? ~VulkanDevice(); - std::unique_ptr InstantiateBuffer(Buffer* parent, BufferType type) override; + std::unique_ptr InstantiateBuffer(BufferType type) override; std::unique_ptr InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo) override; std::shared_ptr InstantiateRenderPipelineLayout(RenderPipelineLayoutInfo pipelineLayoutInfo) override; std::shared_ptr InstantiateShaderStage(ShaderStageType type, ShaderLanguage lang, const void* source, std::size_t sourceSize) override; diff --git a/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.hpp b/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.hpp index 3191f76eb..80ff5b7f4 100644 --- a/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.hpp +++ b/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.hpp @@ -51,6 +51,8 @@ namespace Nz inline void ClearDepthStencilImage(VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue& depthStencil, const VkImageSubresourceRange& range); inline void ClearDepthStencilImage(VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue& depthStencil, UInt32 rangeCount, const VkImageSubresourceRange* ranges); + inline void CopyBuffer(VkBuffer source, VkBuffer target, UInt32 size, UInt32 sourceOffset = 0, UInt32 targetOffset = 0); + inline void Draw(UInt32 vertexCount, UInt32 instanceCount = 1, UInt32 firstVertex = 0, UInt32 firstInstance = 0); inline void DrawIndexed(UInt32 indexCount, UInt32 instanceCount = 1, UInt32 firstVertex = 0, Int32 vertexOffset = 0, UInt32 firstInstance = 0); diff --git a/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.inl b/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.inl index 93255ad58..bd2c4ce76 100644 --- a/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.inl +++ b/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.inl @@ -194,6 +194,16 @@ namespace Nz return m_pool->GetDevice()->vkCmdClearDepthStencilImage(m_handle, image, imageLayout, &depthStencil, rangeCount, ranges); } + inline void CommandBuffer::CopyBuffer(VkBuffer source, VkBuffer target, UInt32 size, UInt32 sourceOffset, UInt32 targetOffset) + { + VkBufferCopy region; + region.dstOffset = targetOffset; + region.size = size; + region.srcOffset = sourceOffset; + + return m_pool->GetDevice()->vkCmdCopyBuffer(m_handle, source, target, 1, ®ion); + } + inline void CommandBuffer::Draw(UInt32 vertexCount, UInt32 instanceCount, UInt32 firstVertex, UInt32 firstInstance) { return m_pool->GetDevice()->vkCmdDraw(m_handle, vertexCount, instanceCount, firstVertex, firstInstance); diff --git a/include/Nazara/VulkanRenderer/Wrapper/Device.hpp b/include/Nazara/VulkanRenderer/Wrapper/Device.hpp index b2a4cf70b..d7a5a3fce 100644 --- a/include/Nazara/VulkanRenderer/Wrapper/Device.hpp +++ b/include/Nazara/VulkanRenderer/Wrapper/Device.hpp @@ -19,6 +19,7 @@ namespace Nz { namespace Vk { + class CommandBuffer; class Instance; class Queue; @@ -34,6 +35,8 @@ namespace Nz Device(Device&&) = delete; ~Device(); + CommandBuffer AllocateTransferCommandBuffer(); + bool Create(const Vk::PhysicalDevice& deviceInfo, const VkDeviceCreateInfo& createInfo, const VkAllocationCallbacks* allocator = nullptr); inline void Destroy(); @@ -47,6 +50,8 @@ namespace Nz inline VkPhysicalDevice GetPhysicalDevice() const; inline const Vk::PhysicalDevice& GetPhysicalDeviceInfo() const; + inline UInt32 GetTransferQueueFamilyIndex() const; + inline bool IsExtensionLoaded(const std::string& extensionName); inline bool IsLayerLoaded(const std::string& layerName); @@ -90,11 +95,15 @@ namespace Nz inline PFN_vkVoidFunction GetProcAddr(const char* name); + struct InternalData; + + std::unique_ptr m_internalData; Instance& m_instance; const Vk::PhysicalDevice* m_physicalDevice; VkAllocationCallbacks m_allocator; VkDevice m_device; VkResult m_lastErrorCode; + UInt32 m_transferQueueFamilyIndex; std::unordered_set m_loadedExtensions; std::unordered_set m_loadedLayers; std::vector m_enabledQueuesInfos; diff --git a/include/Nazara/VulkanRenderer/Wrapper/Device.inl b/include/Nazara/VulkanRenderer/Wrapper/Device.inl index e3a069745..1d44e193d 100644 --- a/include/Nazara/VulkanRenderer/Wrapper/Device.inl +++ b/include/Nazara/VulkanRenderer/Wrapper/Device.inl @@ -49,6 +49,11 @@ namespace Nz return *m_physicalDevice; } + inline UInt32 Device::GetTransferQueueFamilyIndex() const + { + return m_transferQueueFamilyIndex; + } + inline bool Device::IsExtensionLoaded(const std::string& extensionName) { return m_loadedExtensions.count(extensionName) > 0; diff --git a/include/Nazara/VulkanRenderer/Wrapper/DeviceMemory.hpp b/include/Nazara/VulkanRenderer/Wrapper/DeviceMemory.hpp index 8b2d57ada..c6ec63832 100644 --- a/include/Nazara/VulkanRenderer/Wrapper/DeviceMemory.hpp +++ b/include/Nazara/VulkanRenderer/Wrapper/DeviceMemory.hpp @@ -28,6 +28,9 @@ namespace Nz inline bool Create(Device& device, VkDeviceSize size, UInt32 memoryType, const VkAllocationCallbacks* allocator = nullptr); inline bool Create(Device& device, VkDeviceSize size, UInt32 typeBits, VkFlags properties, const VkAllocationCallbacks* allocator = nullptr); + inline bool FlushMemory(); + inline bool FlushMemory(UInt64 offset, UInt64 size); + inline void* GetMappedPointer(); inline bool Map(VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags = 0); diff --git a/include/Nazara/VulkanRenderer/Wrapper/DeviceMemory.inl b/include/Nazara/VulkanRenderer/Wrapper/DeviceMemory.inl index 65fd619d4..a764fbbdb 100644 --- a/include/Nazara/VulkanRenderer/Wrapper/DeviceMemory.inl +++ b/include/Nazara/VulkanRenderer/Wrapper/DeviceMemory.inl @@ -57,6 +57,31 @@ namespace Nz return false; } + inline bool DeviceMemory::FlushMemory() + { + return FlushMemory(0, VK_WHOLE_SIZE); + } + + inline bool DeviceMemory::FlushMemory(UInt64 offset, UInt64 size) + { + VkMappedMemoryRange memoryRange = { + VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, + nullptr, + m_handle, + offset, + size + }; + + m_lastErrorCode = m_device->vkFlushMappedMemoryRanges(*m_device, 1, &memoryRange); + if (m_lastErrorCode != VK_SUCCESS) + { + NazaraError("Failed to flush memory: " + TranslateVulkanError(m_lastErrorCode)); + return false; + } + + return true; + } + inline void* DeviceMemory::GetMappedPointer() { return m_mappedPtr; diff --git a/src/Nazara/Renderer/RenderBuffer.cpp b/src/Nazara/Renderer/RenderBuffer.cpp index 470faf839..c8de03340 100644 --- a/src/Nazara/Renderer/RenderBuffer.cpp +++ b/src/Nazara/Renderer/RenderBuffer.cpp @@ -70,7 +70,7 @@ namespace Nz if (it == m_hardwareBuffers.end()) { HardwareBuffer hwBuffer; - hwBuffer.buffer = device->InstantiateBuffer(m_parent, m_type); + hwBuffer.buffer = device->InstantiateBuffer(m_type); if (!hwBuffer.buffer->Initialize(m_size, m_usage)) { NazaraError("Failed to initialize hardware buffer"); diff --git a/src/Nazara/Utility/Formats/MD5MeshLoader.cpp b/src/Nazara/Utility/Formats/MD5MeshLoader.cpp index 8894a7682..18f6c028e 100644 --- a/src/Nazara/Utility/Formats/MD5MeshLoader.cpp +++ b/src/Nazara/Utility/Formats/MD5MeshLoader.cpp @@ -97,7 +97,7 @@ namespace Nz bool largeIndices = (vertexCount > std::numeric_limits::max()); IndexBufferRef indexBuffer = IndexBuffer::New(largeIndices, UInt32(indexCount), parameters.storage, parameters.indexBufferFlags); - VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent_Skinning), UInt32(vertexCount), parameters.storage, parameters.vertexBufferFlags | BufferUsage_Dynamic); + VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent_Skinning), UInt32(vertexCount), parameters.storage, parameters.vertexBufferFlags); // Index buffer IndexMapper indexMapper(indexBuffer, BufferAccess_DiscardAndWrite); diff --git a/src/Nazara/VulkanRenderer/Utils_VulkanRenderer.cpp b/src/Nazara/VulkanRenderer/Utils_VulkanRenderer.cpp index a21630c9b..b1e29a6e4 100644 --- a/src/Nazara/VulkanRenderer/Utils_VulkanRenderer.cpp +++ b/src/Nazara/VulkanRenderer/Utils_VulkanRenderer.cpp @@ -7,7 +7,7 @@ namespace Nz { - String TranslateVulkanError(VkResult code) + std::string TranslateVulkanError(VkResult code) { // From https://www.khronos.org/registry/vulkan/specs/1.0-wsi_extensions/xhtml/vkspec.html#VkResult switch (code) @@ -97,7 +97,7 @@ namespace Nz break; } - return "Unknown Vulkan error (0x" + String::Number(code, 16) + ')'; + return "Unknown Vulkan error (0x" + String::Number(code, 16).ToStdString() + ')'; } } diff --git a/src/Nazara/VulkanRenderer/VulkanBuffer.cpp b/src/Nazara/VulkanRenderer/VulkanBuffer.cpp index 14944d9fc..c22bb9dc6 100644 --- a/src/Nazara/VulkanRenderer/VulkanBuffer.cpp +++ b/src/Nazara/VulkanRenderer/VulkanBuffer.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include namespace Nz @@ -26,37 +28,30 @@ namespace Nz bool VulkanBuffer::Initialize(UInt32 size, BufferUsageFlags usage) { - VkBufferUsageFlags type; - switch (m_type) + m_size = size; + m_usage = usage; + + VkBufferUsageFlags bufferUsage = ToVulkan(m_type); + VkMemoryPropertyFlags memoryProperties = 0; + if (usage & BufferUsage_DeviceLocal) + memoryProperties |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + + if (usage & BufferUsage_DirectMapping) + memoryProperties |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; + else + bufferUsage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + + if (!m_buffer.Create(m_device, 0, size, bufferUsage)) { - case BufferType_Index: - type = VK_BUFFER_USAGE_INDEX_BUFFER_BIT; - break; - - case BufferType_Vertex: - type = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; - break; - - case BufferType_Uniform: - type = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; - break; - - default: - NazaraError("Unhandled buffer usage 0x" + String::Number(m_type, 16)); - return false; - } - - if (!m_buffer.Create(m_device, 0, size, type)) - { - NazaraError("Failed to create vertex buffer"); + NazaraError("Failed to create vulkan buffer"); return false; } VkMemoryRequirements memRequirement = m_buffer.GetMemoryRequirements(); - if (!m_memory.Create(m_device, memRequirement.size, memRequirement.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) + if (!m_memory.Create(m_device, memRequirement.size, memRequirement.memoryTypeBits, memoryProperties)) { - NazaraError("Failed to allocate vertex buffer memory"); + NazaraError("Failed to allocate buffer memory"); return false; } @@ -76,15 +71,76 @@ namespace Nz void* VulkanBuffer::Map(BufferAccess /*access*/, UInt32 offset, UInt32 size) { - if (!m_memory.Map(offset, size)) - return nullptr; + if (m_usage & BufferUsage_DirectMapping) + { + if (!m_memory.Map(offset, size)) + return nullptr; - return m_memory.GetMappedPointer(); + return m_memory.GetMappedPointer(); + } + else + { + if (!m_stagingFence.Create(m_device)) + { + NazaraError("Failed to create staging fence"); + return nullptr; + } + + if (!m_stagingBuffer.Create(m_device, 0, m_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT)) + { + NazaraError("Failed to create staging buffer"); + return nullptr; + } + + VkMemoryPropertyFlags memoryProperties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; + + VkMemoryRequirements memRequirement = m_stagingBuffer.GetMemoryRequirements(); + if (!m_stagingMemory.Create(m_device, memRequirement.size, memRequirement.memoryTypeBits, memoryProperties)) + { + NazaraError("Failed to allocate vertex buffer memory"); + return nullptr; + } + + if (!m_stagingBuffer.BindBufferMemory(m_stagingMemory)) + { + NazaraError("Failed to bind vertex buffer to its memory"); + return nullptr; + } + + if (!m_stagingMemory.Map(offset, size)) + return nullptr; + + return m_stagingMemory.GetMappedPointer(); + } } bool VulkanBuffer::Unmap() { - m_memory.Unmap(); - return true; + if (m_usage & BufferUsage_DirectMapping) + { + m_memory.Unmap(); + return true; + } + else + { + m_stagingMemory.FlushMemory(); + m_stagingMemory.Unmap(); + + Vk::CommandBuffer copyCommandBuffer = m_device.AllocateTransferCommandBuffer(); + copyCommandBuffer.Begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + copyCommandBuffer.CopyBuffer(m_stagingBuffer, m_buffer, m_size); + copyCommandBuffer.End(); + + Vk::Queue transferQueue = m_device.GetQueue(m_device.GetTransferQueueFamilyIndex(), 0); + if (!transferQueue.Submit(copyCommandBuffer, VK_NULL_HANDLE, 0, VK_NULL_HANDLE, m_stagingFence)) + return false; + + m_stagingFence.Wait(); + + m_stagingBuffer.Destroy(); + m_stagingFence.Destroy(); + m_stagingMemory.Destroy(); + return true; + } } } diff --git a/src/Nazara/VulkanRenderer/Wrapper/Device.cpp b/src/Nazara/VulkanRenderer/Wrapper/Device.cpp index 65aa4c463..3105ae1a8 100644 --- a/src/Nazara/VulkanRenderer/Wrapper/Device.cpp +++ b/src/Nazara/VulkanRenderer/Wrapper/Device.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include #include @@ -13,6 +15,11 @@ namespace Nz { namespace Vk { + struct Device::InternalData + { + Vk::CommandPool transferCommandPool; + }; + Device::Device(Instance& instance) : m_instance(instance), m_physicalDevice(nullptr), @@ -26,6 +33,11 @@ namespace Nz WaitAndDestroyDevice(); } + CommandBuffer Device::AllocateTransferCommandBuffer() + { + return m_internalData->transferCommandPool.AllocateCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY); + } + void Device::Destroy() { if (m_device != VK_NULL_HANDLE) @@ -83,6 +95,8 @@ namespace Nz } // And retains informations about queues + m_transferQueueFamilyIndex = UINT32_MAX; + UInt32 maxFamilyIndex = 0; m_enabledQueuesInfos.resize(createInfo.queueCreateInfoCount); for (UInt32 i = 0; i < createInfo.queueCreateInfoCount; ++i) @@ -107,12 +121,30 @@ namespace Nz queueInfo.priority = queueCreateInfo.pQueuePriorities[queueIndex]; vkGetDeviceQueue(m_device, info.familyIndex, queueIndex, &queueInfo.queue); } + + if (info.flags & (VK_QUEUE_TRANSFER_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_GRAPHICS_BIT)) + { + if (m_transferQueueFamilyIndex == UINT32_MAX) + m_transferQueueFamilyIndex = info.familyIndex; + else if ((info.flags & (VK_QUEUE_COMPUTE_BIT | VK_QUEUE_GRAPHICS_BIT)) == 0) + { + m_transferQueueFamilyIndex = info.familyIndex; + break; + } + } } m_queuesByFamily.resize(maxFamilyIndex + 1); for (const QueueFamilyInfo& familyInfo : m_enabledQueuesInfos) m_queuesByFamily[familyInfo.familyIndex] = &familyInfo.queues; + m_internalData = std::make_unique(); + if (!m_internalData->transferCommandPool.Create(*this, m_transferQueueFamilyIndex, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT)) + { + NazaraError("Failed to create transfer command pool: " + TranslateVulkanError(m_internalData->transferCommandPool.GetLastErrorCode())); + return false; + } + destroyOnFailure.Reset(); return true;