Rework buffers synchronization

This commit is contained in:
Lynix 2020-03-13 18:44:49 +01:00
parent 63547fcd4e
commit b774a879b6
19 changed files with 223 additions and 68 deletions

View File

@ -130,9 +130,6 @@ int main()
Nz::UInt32 uniformSize = sizeof(ubo); Nz::UInt32 uniformSize = sizeof(ubo);
Nz::UniformBuffer uniformBuffer(uniformSize, Nz::DataStorage_Hardware, Nz::BufferUsage_Dynamic);
uniformBuffer.Fill(&ubo, 0, uniformSize);
Nz::RenderPipelineLayoutInfo pipelineLayoutInfo; Nz::RenderPipelineLayoutInfo pipelineLayoutInfo;
auto& bindingInfo = pipelineLayoutInfo.bindings.emplace_back(); auto& bindingInfo = pipelineLayoutInfo.bindings.emplace_back();
bindingInfo.index = 0; bindingInfo.index = 0;
@ -162,13 +159,14 @@ int main()
Nz::Vk::DescriptorSet descriptorSet = descriptorPool.AllocateDescriptorSet(descriptorLayout); Nz::Vk::DescriptorSet descriptorSet = descriptorPool.AllocateDescriptorSet(descriptorLayout);
Nz::RenderBuffer* renderBufferUB = static_cast<Nz::RenderBuffer*>(uniformBuffer.GetBuffer()->GetImpl()); std::unique_ptr<Nz::AbstractBuffer> uniformBuffer = device->InstantiateBuffer(Nz::BufferType_Uniform);
if (!renderBufferUB->Synchronize(&vulkanDevice)) if (!uniformBuffer->Initialize(uniformSize, Nz::BufferUsage_DeviceLocal))
{ {
NazaraError("Failed to create uniform buffer"); NazaraError("Failed to create uniform buffer");
return __LINE__; return __LINE__;
} }
Nz::VulkanBuffer* uniformBufferImpl = static_cast<Nz::VulkanBuffer*>(renderBufferUB->GetHardwareBuffer(&vulkanDevice));
Nz::VulkanBuffer* uniformBufferImpl = static_cast<Nz::VulkanBuffer*>(uniformBuffer.get());
descriptorSet.WriteUniformDescriptor(0, uniformBufferImpl->GetBufferHandle(), 0, uniformSize); descriptorSet.WriteUniformDescriptor(0, uniformBufferImpl->GetBufferHandle(), 0, uniformSize);
Nz::RenderPipelineInfo pipelineInfo; 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]; ImageSync& syncPrimitives = frameSync[currentFrame];
syncPrimitives.inflightFence.Wait(); syncPrimitives.inflightFence.Wait();
@ -381,6 +367,18 @@ int main()
inflightFences[imageIndex] = &syncPrimitives.inflightFence; inflightFences[imageIndex] = &syncPrimitives.inflightFence;
inflightFences[imageIndex]->Reset(); 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)) if (!graphicsQueue.Submit(renderCmds[imageIndex], syncPrimitives.imageAvailableSemaphore, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, syncPrimitives.renderFinishedSemaphore, syncPrimitives.inflightFence))
return false; return false;

View File

@ -18,7 +18,6 @@
namespace Nz namespace Nz
{ {
class Buffer;
class ShaderStageImpl; class ShaderStageImpl;
class NAZARA_RENDERER_API RenderDevice class NAZARA_RENDERER_API RenderDevice
@ -27,7 +26,7 @@ namespace Nz
RenderDevice() = default; RenderDevice() = default;
virtual ~RenderDevice(); virtual ~RenderDevice();
virtual std::unique_ptr<AbstractBuffer> InstantiateBuffer(Buffer* parent, BufferType type) = 0; virtual std::unique_ptr<AbstractBuffer> InstantiateBuffer(BufferType type) = 0;
virtual std::unique_ptr<RenderPipeline> InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo) = 0; virtual std::unique_ptr<RenderPipeline> InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo) = 0;
virtual std::shared_ptr<RenderPipelineLayout> InstantiateRenderPipelineLayout(RenderPipelineLayoutInfo pipelineLayoutInfo) = 0; virtual std::shared_ptr<RenderPipelineLayout> InstantiateRenderPipelineLayout(RenderPipelineLayoutInfo pipelineLayoutInfo) = 0;
virtual std::shared_ptr<ShaderStageImpl> InstantiateShaderStage(ShaderStageType type, ShaderLanguage lang, const void* source, std::size_t sourceSize) = 0; virtual std::shared_ptr<ShaderStageImpl> InstantiateShaderStage(ShaderStageType type, ShaderLanguage lang, const void* source, std::size_t sourceSize) = 0;

View File

@ -56,10 +56,10 @@ namespace Nz
enum BufferUsage enum BufferUsage
{ {
BufferUsage_Dynamic, BufferUsage_DeviceLocal,
BufferUsage_FastRead, BufferUsage_DirectMapping,
BufferUsage_Max = BufferUsage_FastRead BufferUsage_Max = BufferUsage_DirectMapping
}; };
template<> template<>

View File

@ -12,9 +12,11 @@
#include <Nazara/Renderer/Enums.hpp> #include <Nazara/Renderer/Enums.hpp>
#include <Nazara/Utility/Enums.hpp> #include <Nazara/Utility/Enums.hpp>
#include <Nazara/VulkanRenderer/Wrapper/Loader.hpp> #include <Nazara/VulkanRenderer/Wrapper/Loader.hpp>
#include <string>
namespace Nz namespace Nz
{ {
inline VkBufferUsageFlags ToVulkan(BufferType bufferType);
inline VkFormat ToVulkan(ComponentType componentType); inline VkFormat ToVulkan(ComponentType componentType);
inline VkCullModeFlagBits ToVulkan(FaceSide faceSide); inline VkCullModeFlagBits ToVulkan(FaceSide faceSide);
inline VkPolygonMode ToVulkan(FaceFilling faceFilling); inline VkPolygonMode ToVulkan(FaceFilling faceFilling);
@ -26,7 +28,7 @@ namespace Nz
inline VkStencilOp ToVulkan(StencilOperation stencilOp); inline VkStencilOp ToVulkan(StencilOperation stencilOp);
inline VkVertexInputRate ToVulkan(VertexInputRate inputRate); inline VkVertexInputRate ToVulkan(VertexInputRate inputRate);
NAZARA_VULKANRENDERER_API String TranslateVulkanError(VkResult code); NAZARA_VULKANRENDERER_API std::string TranslateVulkanError(VkResult code);
} }
#include <Nazara/VulkanRenderer/Utils.inl> #include <Nazara/VulkanRenderer/Utils.inl>

View File

@ -10,6 +10,19 @@
namespace Nz 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) VkFormat ToVulkan(ComponentType componentType)
{ {
switch (componentType) switch (componentType)

View File

@ -18,12 +18,10 @@
namespace Nz namespace Nz
{ {
class Buffer;
class NAZARA_VULKANRENDERER_API VulkanBuffer : public AbstractBuffer class NAZARA_VULKANRENDERER_API VulkanBuffer : public AbstractBuffer
{ {
public: public:
inline VulkanBuffer(Vk::Device& device, Buffer* parent, BufferType type); inline VulkanBuffer(Vk::Device& device, BufferType type);
VulkanBuffer(const VulkanBuffer&) = delete; VulkanBuffer(const VulkanBuffer&) = delete;
VulkanBuffer(VulkanBuffer&&) = delete; ///TODO VulkanBuffer(VulkanBuffer&&) = delete; ///TODO
virtual ~VulkanBuffer(); virtual ~VulkanBuffer();
@ -35,18 +33,22 @@ namespace Nz
DataStorage GetStorage() const override; 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; bool Unmap() override;
VulkanBuffer& operator=(const VulkanBuffer&) = delete; VulkanBuffer& operator=(const VulkanBuffer&) = delete;
VulkanBuffer& operator=(VulkanBuffer&&) = delete; ///TODO VulkanBuffer& operator=(VulkanBuffer&&) = delete; ///TODO
private: private:
Buffer* m_parent; Vk::Buffer m_stagingBuffer;
Vk::DeviceMemory m_stagingMemory;
BufferType m_type; BufferType m_type;
Nz::Vk::Buffer m_buffer; BufferUsageFlags m_usage;
Nz::Vk::DeviceMemory m_memory; UInt32 m_size;
Vk::Buffer m_buffer;
Vk::Fence m_stagingFence;
Vk::Device& m_device; Vk::Device& m_device;
Vk::DeviceMemory m_memory;
}; };
} }

View File

@ -7,14 +7,13 @@
namespace Nz namespace Nz
{ {
inline VulkanBuffer::VulkanBuffer(Vk::Device& device, Buffer* /*parent*/, BufferType type) : inline VulkanBuffer::VulkanBuffer(Vk::Device& device, BufferType type) :
m_device(device), m_device(device),
m_parent(parent),
m_type(type) m_type(type)
{ {
} }
inline Nz::Vk::Buffer& Nz::VulkanBuffer::GetBufferHandle() inline Vk::Buffer& VulkanBuffer::GetBufferHandle()
{ {
return m_buffer; return m_buffer;
} }

View File

@ -23,7 +23,7 @@ namespace Nz
VulkanDevice(VulkanDevice&&) = delete; ///TODO? VulkanDevice(VulkanDevice&&) = delete; ///TODO?
~VulkanDevice(); ~VulkanDevice();
std::unique_ptr<AbstractBuffer> InstantiateBuffer(Buffer* parent, BufferType type) override; std::unique_ptr<AbstractBuffer> InstantiateBuffer(BufferType type) override;
std::unique_ptr<RenderPipeline> InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo) override; std::unique_ptr<RenderPipeline> InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo) override;
std::shared_ptr<RenderPipelineLayout> InstantiateRenderPipelineLayout(RenderPipelineLayoutInfo pipelineLayoutInfo) override; std::shared_ptr<RenderPipelineLayout> InstantiateRenderPipelineLayout(RenderPipelineLayoutInfo pipelineLayoutInfo) override;
std::shared_ptr<ShaderStageImpl> InstantiateShaderStage(ShaderStageType type, ShaderLanguage lang, const void* source, std::size_t sourceSize) override; std::shared_ptr<ShaderStageImpl> InstantiateShaderStage(ShaderStageType type, ShaderLanguage lang, const void* source, std::size_t sourceSize) override;

View File

@ -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, const VkImageSubresourceRange& range);
inline void ClearDepthStencilImage(VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue& depthStencil, UInt32 rangeCount, const VkImageSubresourceRange* ranges); 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 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); inline void DrawIndexed(UInt32 indexCount, UInt32 instanceCount = 1, UInt32 firstVertex = 0, Int32 vertexOffset = 0, UInt32 firstInstance = 0);

View File

@ -194,6 +194,16 @@ namespace Nz
return m_pool->GetDevice()->vkCmdClearDepthStencilImage(m_handle, image, imageLayout, &depthStencil, rangeCount, ranges); 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, &region);
}
inline void CommandBuffer::Draw(UInt32 vertexCount, UInt32 instanceCount, UInt32 firstVertex, UInt32 firstInstance) inline void CommandBuffer::Draw(UInt32 vertexCount, UInt32 instanceCount, UInt32 firstVertex, UInt32 firstInstance)
{ {
return m_pool->GetDevice()->vkCmdDraw(m_handle, vertexCount, instanceCount, firstVertex, firstInstance); return m_pool->GetDevice()->vkCmdDraw(m_handle, vertexCount, instanceCount, firstVertex, firstInstance);

View File

@ -19,6 +19,7 @@ namespace Nz
{ {
namespace Vk namespace Vk
{ {
class CommandBuffer;
class Instance; class Instance;
class Queue; class Queue;
@ -34,6 +35,8 @@ namespace Nz
Device(Device&&) = delete; Device(Device&&) = delete;
~Device(); ~Device();
CommandBuffer AllocateTransferCommandBuffer();
bool Create(const Vk::PhysicalDevice& deviceInfo, const VkDeviceCreateInfo& createInfo, const VkAllocationCallbacks* allocator = nullptr); bool Create(const Vk::PhysicalDevice& deviceInfo, const VkDeviceCreateInfo& createInfo, const VkAllocationCallbacks* allocator = nullptr);
inline void Destroy(); inline void Destroy();
@ -47,6 +50,8 @@ namespace Nz
inline VkPhysicalDevice GetPhysicalDevice() const; inline VkPhysicalDevice GetPhysicalDevice() const;
inline const Vk::PhysicalDevice& GetPhysicalDeviceInfo() const; inline const Vk::PhysicalDevice& GetPhysicalDeviceInfo() const;
inline UInt32 GetTransferQueueFamilyIndex() const;
inline bool IsExtensionLoaded(const std::string& extensionName); inline bool IsExtensionLoaded(const std::string& extensionName);
inline bool IsLayerLoaded(const std::string& layerName); inline bool IsLayerLoaded(const std::string& layerName);
@ -90,11 +95,15 @@ namespace Nz
inline PFN_vkVoidFunction GetProcAddr(const char* name); inline PFN_vkVoidFunction GetProcAddr(const char* name);
struct InternalData;
std::unique_ptr<InternalData> m_internalData;
Instance& m_instance; Instance& m_instance;
const Vk::PhysicalDevice* m_physicalDevice; const Vk::PhysicalDevice* m_physicalDevice;
VkAllocationCallbacks m_allocator; VkAllocationCallbacks m_allocator;
VkDevice m_device; VkDevice m_device;
VkResult m_lastErrorCode; VkResult m_lastErrorCode;
UInt32 m_transferQueueFamilyIndex;
std::unordered_set<std::string> m_loadedExtensions; std::unordered_set<std::string> m_loadedExtensions;
std::unordered_set<std::string> m_loadedLayers; std::unordered_set<std::string> m_loadedLayers;
std::vector<QueueFamilyInfo> m_enabledQueuesInfos; std::vector<QueueFamilyInfo> m_enabledQueuesInfos;

View File

@ -49,6 +49,11 @@ namespace Nz
return *m_physicalDevice; return *m_physicalDevice;
} }
inline UInt32 Device::GetTransferQueueFamilyIndex() const
{
return m_transferQueueFamilyIndex;
}
inline bool Device::IsExtensionLoaded(const std::string& extensionName) inline bool Device::IsExtensionLoaded(const std::string& extensionName)
{ {
return m_loadedExtensions.count(extensionName) > 0; return m_loadedExtensions.count(extensionName) > 0;

View File

@ -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 memoryType, const VkAllocationCallbacks* allocator = nullptr);
inline bool Create(Device& device, VkDeviceSize size, UInt32 typeBits, VkFlags properties, 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 void* GetMappedPointer();
inline bool Map(VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags = 0); inline bool Map(VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags = 0);

View File

@ -57,6 +57,31 @@ namespace Nz
return false; 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() inline void* DeviceMemory::GetMappedPointer()
{ {
return m_mappedPtr; return m_mappedPtr;

View File

@ -70,7 +70,7 @@ namespace Nz
if (it == m_hardwareBuffers.end()) if (it == m_hardwareBuffers.end())
{ {
HardwareBuffer hwBuffer; HardwareBuffer hwBuffer;
hwBuffer.buffer = device->InstantiateBuffer(m_parent, m_type); hwBuffer.buffer = device->InstantiateBuffer(m_type);
if (!hwBuffer.buffer->Initialize(m_size, m_usage)) if (!hwBuffer.buffer->Initialize(m_size, m_usage))
{ {
NazaraError("Failed to initialize hardware buffer"); NazaraError("Failed to initialize hardware buffer");

View File

@ -97,7 +97,7 @@ namespace Nz
bool largeIndices = (vertexCount > std::numeric_limits<UInt16>::max()); bool largeIndices = (vertexCount > std::numeric_limits<UInt16>::max());
IndexBufferRef indexBuffer = IndexBuffer::New(largeIndices, UInt32(indexCount), parameters.storage, parameters.indexBufferFlags); 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 // Index buffer
IndexMapper indexMapper(indexBuffer, BufferAccess_DiscardAndWrite); IndexMapper indexMapper(indexBuffer, BufferAccess_DiscardAndWrite);

View File

@ -7,7 +7,7 @@
namespace Nz 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 // From https://www.khronos.org/registry/vulkan/specs/1.0-wsi_extensions/xhtml/vkspec.html#VkResult
switch (code) switch (code)
@ -97,7 +97,7 @@ namespace Nz
break; break;
} }
return "Unknown Vulkan error (0x" + String::Number(code, 16) + ')'; return "Unknown Vulkan error (0x" + String::Number(code, 16).ToStdString() + ')';
} }
} }

View File

@ -5,6 +5,8 @@
#include <Nazara/VulkanRenderer/VulkanBuffer.hpp> #include <Nazara/VulkanRenderer/VulkanBuffer.hpp>
#include <Nazara/Core/CallOnExit.hpp> #include <Nazara/Core/CallOnExit.hpp>
#include <Nazara/Core/String.hpp> #include <Nazara/Core/String.hpp>
#include <Nazara/VulkanRenderer/Wrapper/CommandBuffer.hpp>
#include <Nazara/VulkanRenderer/Wrapper/Queue.hpp>
#include <Nazara/VulkanRenderer/Debug.hpp> #include <Nazara/VulkanRenderer/Debug.hpp>
namespace Nz namespace Nz
@ -26,37 +28,30 @@ namespace Nz
bool VulkanBuffer::Initialize(UInt32 size, BufferUsageFlags usage) bool VulkanBuffer::Initialize(UInt32 size, BufferUsageFlags usage)
{ {
VkBufferUsageFlags type; m_size = size;
switch (m_type) 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: NazaraError("Failed to create vulkan buffer");
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");
return false; return false;
} }
VkMemoryRequirements memRequirement = m_buffer.GetMemoryRequirements(); 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; return false;
} }
@ -76,15 +71,76 @@ namespace Nz
void* VulkanBuffer::Map(BufferAccess /*access*/, UInt32 offset, UInt32 size) void* VulkanBuffer::Map(BufferAccess /*access*/, UInt32 offset, UInt32 size)
{ {
if (!m_memory.Map(offset, size)) if (m_usage & BufferUsage_DirectMapping)
return nullptr; {
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() bool VulkanBuffer::Unmap()
{ {
m_memory.Unmap(); if (m_usage & BufferUsage_DirectMapping)
return true; {
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;
}
} }
} }

View File

@ -6,6 +6,8 @@
#include <Nazara/Core/CallOnExit.hpp> #include <Nazara/Core/CallOnExit.hpp>
#include <Nazara/Core/Error.hpp> #include <Nazara/Core/Error.hpp>
#include <Nazara/Core/ErrorFlags.hpp> #include <Nazara/Core/ErrorFlags.hpp>
#include <Nazara/VulkanRenderer/Wrapper/CommandBuffer.hpp>
#include <Nazara/VulkanRenderer/Wrapper/CommandPool.hpp>
#include <Nazara/VulkanRenderer/Wrapper/Queue.hpp> #include <Nazara/VulkanRenderer/Wrapper/Queue.hpp>
#include <Nazara/VulkanRenderer/Debug.hpp> #include <Nazara/VulkanRenderer/Debug.hpp>
@ -13,6 +15,11 @@ namespace Nz
{ {
namespace Vk namespace Vk
{ {
struct Device::InternalData
{
Vk::CommandPool transferCommandPool;
};
Device::Device(Instance& instance) : Device::Device(Instance& instance) :
m_instance(instance), m_instance(instance),
m_physicalDevice(nullptr), m_physicalDevice(nullptr),
@ -26,6 +33,11 @@ namespace Nz
WaitAndDestroyDevice(); WaitAndDestroyDevice();
} }
CommandBuffer Device::AllocateTransferCommandBuffer()
{
return m_internalData->transferCommandPool.AllocateCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY);
}
void Device::Destroy() void Device::Destroy()
{ {
if (m_device != VK_NULL_HANDLE) if (m_device != VK_NULL_HANDLE)
@ -83,6 +95,8 @@ namespace Nz
} }
// And retains informations about queues // And retains informations about queues
m_transferQueueFamilyIndex = UINT32_MAX;
UInt32 maxFamilyIndex = 0; UInt32 maxFamilyIndex = 0;
m_enabledQueuesInfos.resize(createInfo.queueCreateInfoCount); m_enabledQueuesInfos.resize(createInfo.queueCreateInfoCount);
for (UInt32 i = 0; i < createInfo.queueCreateInfoCount; ++i) for (UInt32 i = 0; i < createInfo.queueCreateInfoCount; ++i)
@ -107,12 +121,30 @@ namespace Nz
queueInfo.priority = queueCreateInfo.pQueuePriorities[queueIndex]; queueInfo.priority = queueCreateInfo.pQueuePriorities[queueIndex];
vkGetDeviceQueue(m_device, info.familyIndex, queueIndex, &queueInfo.queue); 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); m_queuesByFamily.resize(maxFamilyIndex + 1);
for (const QueueFamilyInfo& familyInfo : m_enabledQueuesInfos) for (const QueueFamilyInfo& familyInfo : m_enabledQueuesInfos)
m_queuesByFamily[familyInfo.familyIndex] = &familyInfo.queues; m_queuesByFamily[familyInfo.familyIndex] = &familyInfo.queues;
m_internalData = std::make_unique<InternalData>();
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(); destroyOnFailure.Reset();
return true; return true;