Vulkan: Refactor command buffer and introduce command pool
This commit is contained in:
parent
f6d21d066e
commit
87f1209327
|
|
@ -210,6 +210,8 @@ int main()
|
|||
Nz::VkRenderWindow& vulkanWindow = *static_cast<Nz::VkRenderWindow*>(window.GetImpl());
|
||||
Nz::VulkanDevice& vulkanDevice = vulkanWindow.GetDevice();
|
||||
|
||||
std::unique_ptr<Nz::CommandPool> commandPool = vulkanWindow.CreateCommandPool(Nz::QueueType::Graphics);
|
||||
|
||||
Nz::UInt32 imageCount = vulkanWindow.GetFramebufferCount();
|
||||
std::vector<std::unique_ptr<Nz::CommandBuffer>> renderCmds(imageCount);
|
||||
|
||||
|
|
@ -258,7 +260,7 @@ int main()
|
|||
clearValues.data() // const VkClearValue *pClearValues
|
||||
};
|
||||
|
||||
commandBufferPtr = vulkanWindow.BuildCommandBuffer([&](Nz::CommandBufferBuilder& builder)
|
||||
commandBufferPtr = commandPool->BuildCommandBuffer([&](Nz::CommandBufferBuilder& builder)
|
||||
{
|
||||
Nz::Vk::CommandBuffer& vkCommandBuffer = static_cast<Nz::VulkanCommandBufferBuilder&>(builder).GetCommandBuffer();
|
||||
|
||||
|
|
@ -372,11 +374,11 @@ int main()
|
|||
builder.PostTransferBarrier();
|
||||
}
|
||||
builder.EndDebugRegion();
|
||||
}, false);
|
||||
}, Nz::QueueType::Transfer);
|
||||
|
||||
Nz::UInt32 imageIndex = renderImage.GetImageIndex();
|
||||
|
||||
renderImage.SubmitCommandBuffer(renderCmds[imageIndex].get(), true);
|
||||
renderImage.SubmitCommandBuffer(renderCmds[imageIndex].get(), Nz::QueueType::Graphics);
|
||||
|
||||
renderImage.Present();
|
||||
|
||||
|
|
|
|||
|
|
@ -1208,7 +1208,8 @@ namespace Nz
|
|||
template<typename Block, class Allocator>
|
||||
Block Bitset<Block, Allocator>::GetLastBlockMask() const
|
||||
{
|
||||
return (Block(1U) << GetBitIndex(m_bitCount)) - 1U;
|
||||
std::size_t bitIndex = GetBitIndex(m_bitCount);
|
||||
return (bitIndex) ? (Block(1U) << bitIndex) - 1U : fullBitMask;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -1218,9 +1219,7 @@ namespace Nz
|
|||
template<typename Block, class Allocator>
|
||||
void Bitset<Block, Allocator>::ResetExtraBits()
|
||||
{
|
||||
Block mask = GetLastBlockMask();
|
||||
if (mask)
|
||||
m_blocks.back() &= mask;
|
||||
m_blocks.back() &= GetLastBlockMask();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
#include <Nazara/Renderer/CommandBuffer.hpp>
|
||||
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
|
||||
#include <Nazara/Renderer/CommandPool.hpp>
|
||||
#include <Nazara/Renderer/Config.hpp>
|
||||
#include <Nazara/Renderer/DebugDrawer.hpp>
|
||||
#include <Nazara/Renderer/Enums.hpp>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_COMMANDPOOL_HPP
|
||||
#define NAZARA_COMMANDPOOL_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Renderer/Config.hpp>
|
||||
#include <functional>
|
||||
#include <memory> //< temporary
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class CommandBuffer;
|
||||
class CommandBufferBuilder;
|
||||
|
||||
class NAZARA_RENDERER_API CommandPool
|
||||
{
|
||||
public:
|
||||
CommandPool() = default;
|
||||
CommandPool(const CommandPool&) = delete;
|
||||
CommandPool(CommandPool&&) = default;
|
||||
virtual ~CommandPool();
|
||||
|
||||
virtual std::unique_ptr<CommandBuffer> BuildCommandBuffer(const std::function<void(CommandBufferBuilder& builder)>& callback) = 0;
|
||||
|
||||
CommandPool& operator=(const CommandPool&) = delete;
|
||||
CommandPool& operator=(CommandPool&&) = default;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Renderer/CommandPool.inl>
|
||||
|
||||
#endif // NAZARA_COMMANDPOOL_HPP
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/CommandPool.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
}
|
||||
|
||||
#include <Nazara/Renderer/DebugOff.hpp>
|
||||
|
|
@ -69,6 +69,23 @@ namespace Nz
|
|||
using ShaderStageTypeFlags = Flags<ShaderStageType>;
|
||||
|
||||
constexpr ShaderStageTypeFlags ShaderStageType_All = ShaderStageType::Fragment | ShaderStageType::Vertex;
|
||||
|
||||
enum class QueueType
|
||||
{
|
||||
Compute,
|
||||
Graphics,
|
||||
Transfer,
|
||||
|
||||
Max = Transfer
|
||||
};
|
||||
|
||||
template<>
|
||||
struct EnumAsFlags<QueueType>
|
||||
{
|
||||
static constexpr QueueType max = QueueType::Max;
|
||||
};
|
||||
|
||||
using QueueTypeFlags = Flags<QueueType>;
|
||||
}
|
||||
|
||||
#endif // NAZARA_ENUMS_RENDERER_HPP
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
class CommandPool;
|
||||
class ShaderStageImpl;
|
||||
|
||||
class NAZARA_RENDERER_API RenderDevice
|
||||
|
|
@ -29,6 +30,7 @@ namespace Nz
|
|||
virtual ~RenderDevice();
|
||||
|
||||
virtual std::unique_ptr<AbstractBuffer> InstantiateBuffer(BufferType type) = 0;
|
||||
virtual std::unique_ptr<CommandPool> InstantiateCommandPool(QueueType queueType) = 0;
|
||||
virtual std::unique_ptr<RenderPipeline> InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo) = 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;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Renderer/Config.hpp>
|
||||
#include <Nazara/Renderer/Enums.hpp>
|
||||
#include <functional>
|
||||
|
||||
namespace Nz
|
||||
|
|
@ -23,11 +24,11 @@ namespace Nz
|
|||
RenderImage() = default;
|
||||
virtual ~RenderImage();
|
||||
|
||||
virtual void Execute(const std::function<void(CommandBufferBuilder& builder)>& callback, bool isGraphical) = 0;
|
||||
virtual void Execute(const std::function<void(CommandBufferBuilder& builder)>& callback, QueueTypeFlags queueTypeFlags) = 0;
|
||||
|
||||
virtual UploadPool& GetUploadPool() = 0;
|
||||
|
||||
virtual void SubmitCommandBuffer(CommandBuffer* commandBuffer, bool isGraphical) = 0;
|
||||
virtual void SubmitCommandBuffer(CommandBuffer* commandBuffer, QueueTypeFlags queueTypeFlags) = 0;
|
||||
|
||||
virtual void Present() = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -13,12 +13,10 @@
|
|||
#include <Nazara/Renderer/Config.hpp>
|
||||
#include <Nazara/Renderer/RenderDevice.hpp>
|
||||
#include <Nazara/Renderer/RenderWindowParameters.hpp>
|
||||
#include <functional>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class CommandBuffer;
|
||||
class CommandBufferBuilder;
|
||||
class CommandPool;
|
||||
class RendererImpl;
|
||||
class RenderImage;
|
||||
class RenderSurface;
|
||||
|
|
@ -31,9 +29,8 @@ namespace Nz
|
|||
|
||||
virtual RenderImage& Acquire() = 0;
|
||||
|
||||
virtual std::unique_ptr<CommandBuffer> BuildCommandBuffer(const std::function<void(CommandBufferBuilder& builder)>& callback) = 0;
|
||||
|
||||
virtual bool Create(RendererImpl* renderer, RenderSurface* surface, const Vector2ui& size, const RenderWindowParameters& parameters) = 0;
|
||||
virtual std::unique_ptr<CommandPool> CreateCommandPool(QueueType queueType) = 0;
|
||||
|
||||
virtual std::shared_ptr<RenderDevice> GetRenderDevice() = 0;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
#include <Nazara/VulkanRenderer/VulkanBuffer.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanCommandBuffer.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanCommandBufferBuilder.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanCommandPool.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanDevice.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanRenderer.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanRenderImage.hpp>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <Nazara/Core/Clock.hpp>
|
||||
#include <Nazara/Math/Rect.hpp>
|
||||
#include <Nazara/Math/Vector3.hpp>
|
||||
#include <Nazara/Renderer/Enums.hpp>
|
||||
#include <Nazara/Renderer/RendererImpl.hpp>
|
||||
#include <Nazara/Renderer/RenderWindowImpl.hpp>
|
||||
#include <Nazara/VulkanRenderer/Config.hpp>
|
||||
|
|
@ -40,9 +41,8 @@ namespace Nz
|
|||
|
||||
VulkanRenderImage& Acquire() override;
|
||||
|
||||
std::unique_ptr<CommandBuffer> BuildCommandBuffer(const std::function<void(CommandBufferBuilder& builder)>& callback) override;
|
||||
|
||||
bool Create(RendererImpl* renderer, RenderSurface* surface, const Vector2ui& size, const RenderWindowParameters& parameters) override;
|
||||
std::unique_ptr<CommandPool> CreateCommandPool(QueueType queueType) override;
|
||||
|
||||
inline const Vk::Framebuffer& GetFrameBuffer(UInt32 imageIndex) const override;
|
||||
inline UInt32 GetFramebufferCount() const override;
|
||||
|
|
@ -77,12 +77,12 @@ namespace Nz
|
|||
std::shared_ptr<VulkanDevice> m_device;
|
||||
std::vector<ImageData> m_imageData;
|
||||
std::vector<VulkanRenderImage> m_concurrentImageData;
|
||||
Vk::CommandPool m_graphicsCommandPool;
|
||||
Vk::DeviceMemory m_depthBufferMemory;
|
||||
Vk::Image m_depthBuffer;
|
||||
Vk::ImageView m_depthBufferView;
|
||||
Vk::QueueHandle m_graphicsQueue;
|
||||
Vk::QueueHandle m_presentQueue;
|
||||
Vk::QueueHandle m_transferQueue;
|
||||
Vk::Swapchain m_swapchain;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ namespace Nz
|
|||
~Vulkan() = delete;
|
||||
|
||||
static std::shared_ptr<VulkanDevice> CreateDevice(const Vk::PhysicalDevice& deviceInfo);
|
||||
static std::shared_ptr<VulkanDevice> CreateDevice(const Vk::PhysicalDevice& deviceInfo, const Vk::Surface& surface, UInt32* graphicsFamilyIndex, UInt32* presentableFamilyIndex);
|
||||
static std::shared_ptr<VulkanDevice> CreateDevice(const Vk::PhysicalDevice& deviceInfo, const Vk::Surface& surface, UInt32* graphicsFamilyIndex, UInt32* presentableFamilyIndex, UInt32* transferFamilyIndex);
|
||||
static std::shared_ptr<VulkanDevice> CreateDevice(const Vk::PhysicalDevice& deviceInfo, const QueueFamily* queueFamilies, std::size_t queueFamilyCount);
|
||||
|
||||
static Vk::Instance& GetInstance();
|
||||
|
|
@ -49,7 +49,7 @@ namespace Nz
|
|||
static bool IsInitialized();
|
||||
|
||||
static std::shared_ptr<VulkanDevice> SelectDevice(const Vk::PhysicalDevice& deviceInfo);
|
||||
static std::shared_ptr<VulkanDevice> SelectDevice(const Vk::PhysicalDevice& deviceInfo, const Vk::Surface& surface, UInt32* graphicsFamilyIndex, UInt32* presentableFamilyIndex);
|
||||
static std::shared_ptr<VulkanDevice> SelectDevice(const Vk::PhysicalDevice& deviceInfo, const Vk::Surface& surface, UInt32* graphicsFamilyIndex, UInt32* presentableFamilyIndex, UInt32* transferFamilyIndex);
|
||||
|
||||
static void Uninitialize();
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_VULKANRENDERER_VULKANCOMMANDPOOL_HPP
|
||||
#define NAZARA_VULKANRENDERER_VULKANCOMMANDPOOL_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Renderer/CommandPool.hpp>
|
||||
#include <Nazara/VulkanRenderer/Config.hpp>
|
||||
#include <Nazara/VulkanRenderer/Wrapper/CommandPool.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class NAZARA_VULKANRENDERER_API VulkanCommandPool final : public CommandPool
|
||||
{
|
||||
public:
|
||||
inline VulkanCommandPool(Vk::Device& device, QueueType queueType);
|
||||
inline VulkanCommandPool(Vk::Device& device, UInt32 queueFamilyIndex);
|
||||
VulkanCommandPool(const VulkanCommandPool&) = delete;
|
||||
VulkanCommandPool(VulkanCommandPool&&) noexcept = default;
|
||||
~VulkanCommandPool() = default;
|
||||
|
||||
std::unique_ptr<CommandBuffer> BuildCommandBuffer(const std::function<void(CommandBufferBuilder& builder)>& callback) override;
|
||||
|
||||
VulkanCommandPool& operator=(const VulkanCommandPool&) = delete;
|
||||
VulkanCommandPool& operator=(VulkanCommandPool&&) = delete;
|
||||
|
||||
private:
|
||||
Vk::CommandPool m_commandPool;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/VulkanRenderer/VulkanCommandPool.inl>
|
||||
|
||||
#endif // NAZARA_VULKANRENDERER_VULKANCOMMANDPOOL_HPP
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Vulkan Renderer"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/VulkanRenderer/VulkanCommandPool.hpp>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/VulkanRenderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
inline VulkanCommandPool::VulkanCommandPool(Vk::Device& device, QueueType queueType)
|
||||
{
|
||||
UInt32 queueFamilyIndex = device.GetDefaultFamilyIndex(queueType);
|
||||
if (queueFamilyIndex == Vk::Device::InvalidQueue)
|
||||
throw std::runtime_error("QueueType " + std::to_string(UnderlyingCast(queueType)) + " is not supported");
|
||||
|
||||
if (!m_commandPool.Create(device, queueFamilyIndex))
|
||||
throw std::runtime_error("Failed to create command pool: " + TranslateVulkanError(m_commandPool.GetLastErrorCode()));
|
||||
}
|
||||
|
||||
inline VulkanCommandPool::VulkanCommandPool(Vk::Device& device, UInt32 queueFamilyIndex)
|
||||
{
|
||||
if (!m_commandPool.Create(device, queueFamilyIndex))
|
||||
throw std::runtime_error("Failed to create command pool: " + TranslateVulkanError(m_commandPool.GetLastErrorCode()));
|
||||
}
|
||||
}
|
||||
|
||||
#include <Nazara/VulkanRenderer/DebugOff.hpp>
|
||||
|
|
@ -24,6 +24,7 @@ namespace Nz
|
|||
~VulkanDevice();
|
||||
|
||||
std::unique_ptr<AbstractBuffer> InstantiateBuffer(BufferType type) override;
|
||||
std::unique_ptr<CommandPool> InstantiateCommandPool(QueueType queueType) override;
|
||||
std::unique_ptr<RenderPipeline> InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo) 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;
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ namespace Nz
|
|||
VulkanRenderImage(VulkanRenderImage&&) noexcept = default;
|
||||
~VulkanRenderImage();
|
||||
|
||||
void Execute(const std::function<void(CommandBufferBuilder& builder)>& callback, bool isGraphical) override;
|
||||
void Execute(const std::function<void(CommandBufferBuilder& builder)>& callback, QueueTypeFlags queueTypeFlags) override;
|
||||
|
||||
inline Vk::Fence& GetInFlightFence();
|
||||
inline Vk::Semaphore& GetImageAvailableSemaphore();
|
||||
|
|
@ -36,8 +36,8 @@ namespace Nz
|
|||
inline Vk::Semaphore& GetRenderFinishedSemaphore();
|
||||
VulkanUploadPool& GetUploadPool() override;
|
||||
|
||||
void SubmitCommandBuffer(CommandBuffer* commandBuffer, bool isGraphical) override;
|
||||
void SubmitCommandBuffer(VkCommandBuffer commandBuffer, bool isGraphical);
|
||||
void SubmitCommandBuffer(CommandBuffer* commandBuffer, QueueTypeFlags queueTypeFlags) override;
|
||||
void SubmitCommandBuffer(VkCommandBuffer commandBuffer, QueueTypeFlags queueTypeFlags);
|
||||
|
||||
void Present() override;
|
||||
|
||||
|
|
|
|||
|
|
@ -8,10 +8,13 @@
|
|||
#define NAZARA_VULKANRENDERER_VKDEVICE_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Core/Algorithm.hpp>
|
||||
#include <Nazara/Renderer/Enums.hpp>
|
||||
#include <Nazara/VulkanRenderer/Config.hpp>
|
||||
#include <Nazara/VulkanRenderer/Wrapper/Loader.hpp>
|
||||
#include <Nazara/VulkanRenderer/Wrapper/PhysicalDevice.hpp>
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <unordered_set>
|
||||
|
||||
|
|
@ -38,7 +41,7 @@ namespace Nz
|
|||
Device(Device&&) = delete;
|
||||
~Device();
|
||||
|
||||
AutoCommandBuffer AllocateTransferCommandBuffer();
|
||||
AutoCommandBuffer AllocateCommandBuffer(QueueType queueType);
|
||||
|
||||
bool Create(const Vk::PhysicalDevice& deviceInfo, const VkDeviceCreateInfo& createInfo, const VkAllocationCallbacks* allocator = nullptr);
|
||||
inline void Destroy();
|
||||
|
|
@ -54,7 +57,7 @@ namespace Nz
|
|||
inline VkPhysicalDevice GetPhysicalDevice() const;
|
||||
inline const Vk::PhysicalDevice& GetPhysicalDeviceInfo() const;
|
||||
|
||||
inline UInt32 GetTransferQueueFamilyIndex() const;
|
||||
inline UInt32 GetDefaultFamilyIndex(QueueType queueType) const;
|
||||
|
||||
inline bool IsExtensionLoaded(const std::string& extensionName);
|
||||
inline bool IsLayerLoaded(const std::string& layerName);
|
||||
|
|
@ -99,6 +102,8 @@ namespace Nz
|
|||
UInt32 timestampValidBits;
|
||||
};
|
||||
|
||||
static constexpr UInt32 InvalidQueue = std::numeric_limits<UInt32>::max();
|
||||
|
||||
private:
|
||||
void ResetPointers();
|
||||
void WaitAndDestroyDevice();
|
||||
|
|
@ -107,6 +112,8 @@ namespace Nz
|
|||
|
||||
struct InternalData;
|
||||
|
||||
static constexpr std::size_t QueueCount = static_cast<std::size_t>(QueueType::Max) + 1;
|
||||
|
||||
std::unique_ptr<InternalData> m_internalData;
|
||||
Instance& m_instance;
|
||||
const Vk::PhysicalDevice* m_physicalDevice;
|
||||
|
|
@ -114,7 +121,7 @@ namespace Nz
|
|||
VkDevice m_device;
|
||||
VkResult m_lastErrorCode;
|
||||
VmaAllocator m_memAllocator;
|
||||
UInt32 m_transferQueueFamilyIndex;
|
||||
std::array<UInt32, QueueCount> m_defaultQueues;
|
||||
std::unordered_set<std::string> m_loadedExtensions;
|
||||
std::unordered_set<std::string> m_loadedLayers;
|
||||
std::vector<QueueFamilyInfo> m_enabledQueuesInfos;
|
||||
|
|
|
|||
|
|
@ -54,9 +54,9 @@ namespace Nz
|
|||
return *m_physicalDevice;
|
||||
}
|
||||
|
||||
inline UInt32 Device::GetTransferQueueFamilyIndex() const
|
||||
inline UInt32 Device::GetDefaultFamilyIndex(QueueType queueType) const
|
||||
{
|
||||
return m_transferQueueFamilyIndex;
|
||||
return m_defaultQueues[UnderlyingCast(queueType)];
|
||||
}
|
||||
|
||||
inline bool Device::IsExtensionLoaded(const std::string& extensionName)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/CommandPool.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
CommandPool::~CommandPool() = default;
|
||||
}
|
||||
|
|
@ -7,8 +7,7 @@
|
|||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/Utility/PixelFormat.hpp>
|
||||
#include <Nazara/VulkanRenderer/Vulkan.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanCommandBuffer.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanCommandBufferBuilder.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanCommandPool.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanDevice.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanSurface.hpp>
|
||||
#include <array>
|
||||
|
|
@ -29,7 +28,6 @@ namespace Nz
|
|||
m_device->WaitForIdle();
|
||||
|
||||
m_concurrentImageData.clear();
|
||||
m_graphicsCommandPool.Destroy();
|
||||
m_imageData.clear();
|
||||
m_renderPass.Destroy();
|
||||
m_swapchain.Destroy();
|
||||
|
|
@ -60,22 +58,6 @@ namespace Nz
|
|||
return currentFrame;
|
||||
}
|
||||
|
||||
std::unique_ptr<CommandBuffer> VkRenderWindow::BuildCommandBuffer(const std::function<void(CommandBufferBuilder& builder)>& callback)
|
||||
{
|
||||
Vk::AutoCommandBuffer commandBuffer = m_graphicsCommandPool.AllocateCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY);
|
||||
|
||||
if (!commandBuffer->Begin())
|
||||
throw std::runtime_error("failed to begin command buffer: " + TranslateVulkanError(commandBuffer->GetLastErrorCode()));
|
||||
|
||||
VulkanCommandBufferBuilder builder(commandBuffer.Get());
|
||||
callback(builder);
|
||||
|
||||
if (!commandBuffer->End())
|
||||
throw std::runtime_error("failed to build command buffer: " + TranslateVulkanError(commandBuffer->GetLastErrorCode()));
|
||||
|
||||
return std::make_unique<VulkanCommandBuffer>(std::move(commandBuffer));
|
||||
}
|
||||
|
||||
bool VkRenderWindow::Create(RendererImpl* /*renderer*/, RenderSurface* surface, const Vector2ui& size, const RenderWindowParameters& parameters)
|
||||
{
|
||||
const auto& deviceInfo = Vulkan::GetPhysicalDevices()[0];
|
||||
|
|
@ -84,7 +66,8 @@ namespace Nz
|
|||
|
||||
UInt32 graphicsFamilyQueueIndex;
|
||||
UInt32 presentableFamilyQueueIndex;
|
||||
m_device = Vulkan::SelectDevice(deviceInfo, vulkanSurface, &graphicsFamilyQueueIndex, &presentableFamilyQueueIndex);
|
||||
UInt32 transferFamilyQueueIndex;
|
||||
m_device = Vulkan::SelectDevice(deviceInfo, vulkanSurface, &graphicsFamilyQueueIndex, &presentableFamilyQueueIndex, &transferFamilyQueueIndex);
|
||||
if (!m_device)
|
||||
{
|
||||
NazaraError("Failed to get compatible Vulkan device");
|
||||
|
|
@ -93,6 +76,7 @@ namespace Nz
|
|||
|
||||
m_graphicsQueue = m_device->GetQueue(graphicsFamilyQueueIndex, 0);
|
||||
m_presentQueue = m_device->GetQueue(presentableFamilyQueueIndex, 0);
|
||||
m_transferQueue = m_device->GetQueue(transferFamilyQueueIndex, 0);
|
||||
|
||||
std::vector<VkSurfaceFormatKHR> surfaceFormats;
|
||||
if (!vulkanSurface.GetFormats(deviceInfo.physDevice, &surfaceFormats))
|
||||
|
|
@ -204,12 +188,6 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
|
||||
if (!m_graphicsCommandPool.Create(*m_device, m_graphicsQueue.GetQueueFamilyIndex()))
|
||||
{
|
||||
NazaraError("Failed to create graphics command pool: " + TranslateVulkanError(m_graphicsCommandPool.GetLastErrorCode()));
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::size_t MaxConcurrentImage = imageCount;
|
||||
m_concurrentImageData.reserve(MaxConcurrentImage);
|
||||
|
||||
|
|
@ -221,6 +199,27 @@ namespace Nz
|
|||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<CommandPool> VkRenderWindow::CreateCommandPool(QueueType queueType)
|
||||
{
|
||||
UInt32 queueFamilyIndex;
|
||||
switch (queueType)
|
||||
{
|
||||
case QueueType::Compute:
|
||||
queueFamilyIndex = m_device->GetDefaultFamilyIndex(QueueType::Compute);
|
||||
break;
|
||||
|
||||
case QueueType::Graphics:
|
||||
queueFamilyIndex = m_graphicsQueue.GetQueueFamilyIndex();
|
||||
break;
|
||||
|
||||
case QueueType::Transfer:
|
||||
queueFamilyIndex = m_transferQueue.GetQueueFamilyIndex();
|
||||
break;
|
||||
}
|
||||
|
||||
return std::make_unique<VulkanCommandPool>(*m_device, queueFamilyIndex);
|
||||
}
|
||||
|
||||
bool VkRenderWindow::SetupDepthBuffer(const Vector2ui& size)
|
||||
{
|
||||
VkImageCreateInfo imageCreateInfo = {
|
||||
|
|
|
|||
|
|
@ -297,7 +297,7 @@ namespace Nz
|
|||
return CreateDevice(deviceInfo, queuesFamilies.data(), queuesFamilies.size());
|
||||
}
|
||||
|
||||
std::shared_ptr<VulkanDevice> Vulkan::CreateDevice(const Vk::PhysicalDevice& deviceInfo, const Vk::Surface& surface, UInt32* graphicsFamilyIndex, UInt32* presentableFamilyIndex)
|
||||
std::shared_ptr<VulkanDevice> Vulkan::CreateDevice(const Vk::PhysicalDevice& deviceInfo, const Vk::Surface& surface, UInt32* graphicsFamilyIndex, UInt32* presentableFamilyIndex, UInt32* transferFamilyIndex)
|
||||
{
|
||||
Nz::ErrorFlags errFlags(ErrorFlag_ThrowException, true);
|
||||
|
||||
|
|
@ -364,6 +364,7 @@ namespace Nz
|
|||
|
||||
*graphicsFamilyIndex = graphicsQueueNodeIndex;
|
||||
*presentableFamilyIndex = presentQueueNodeIndex;
|
||||
*transferFamilyIndex = transferQueueNodeFamily;
|
||||
|
||||
return CreateDevice(deviceInfo, queuesFamilies.data(), queuesFamilies.size());
|
||||
}
|
||||
|
|
@ -497,7 +498,7 @@ namespace Nz
|
|||
return CreateDevice(deviceInfo);
|
||||
}
|
||||
|
||||
std::shared_ptr<VulkanDevice> Vulkan::SelectDevice(const Vk::PhysicalDevice& deviceInfo, const Vk::Surface& surface, UInt32* graphicsFamilyIndex, UInt32* presentableFamilyIndex)
|
||||
std::shared_ptr<VulkanDevice> Vulkan::SelectDevice(const Vk::PhysicalDevice& deviceInfo, const Vk::Surface& surface, UInt32* graphicsFamilyIndex, UInt32* presentableFamilyIndex, UInt32* transferFamilyIndex)
|
||||
{
|
||||
// First, try to find a device compatible with that surface
|
||||
for (auto it = s_devices.begin(); it != s_devices.end();)
|
||||
|
|
@ -540,6 +541,23 @@ namespace Nz
|
|||
if (presentableQueueFamilyIndex != UINT32_MAX)
|
||||
{
|
||||
*presentableFamilyIndex = presentableQueueFamilyIndex;
|
||||
|
||||
UInt32 transferQueueNodeFamily = UINT32_MAX;
|
||||
// Search for a transfer queue (first one being different to the graphics one)
|
||||
for (const Vk::Device::QueueFamilyInfo& queueInfo : queueFamilyInfo)
|
||||
{
|
||||
// Transfer bit is not mandatory if compute and graphics bits are set (as they implicitly support transfer)
|
||||
if (queueInfo.flags & (VK_QUEUE_COMPUTE_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_TRANSFER_BIT))
|
||||
{
|
||||
transferQueueNodeFamily = queueInfo.familyIndex;
|
||||
if (transferQueueNodeFamily != *graphicsFamilyIndex)
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(transferQueueNodeFamily != UINT32_MAX);
|
||||
|
||||
*transferFamilyIndex = transferQueueNodeFamily;
|
||||
|
||||
return devicePtr;
|
||||
}
|
||||
}
|
||||
|
|
@ -548,7 +566,7 @@ namespace Nz
|
|||
}
|
||||
|
||||
// No device had support for that surface, create one
|
||||
return CreateDevice(deviceInfo, surface, graphicsFamilyIndex, presentableFamilyIndex);
|
||||
return CreateDevice(deviceInfo, surface, graphicsFamilyIndex, presentableFamilyIndex, transferFamilyIndex);
|
||||
}
|
||||
|
||||
void Vulkan::Uninitialize()
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ namespace Nz
|
|||
}
|
||||
else
|
||||
{
|
||||
Vk::AutoCommandBuffer copyCommandBuffer = m_device.AllocateTransferCommandBuffer();
|
||||
Vk::AutoCommandBuffer copyCommandBuffer = m_device.AllocateCommandBuffer(QueueType::Transfer);
|
||||
if (!copyCommandBuffer->Begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT))
|
||||
return false;
|
||||
|
||||
|
|
@ -134,7 +134,7 @@ namespace Nz
|
|||
if (!copyCommandBuffer->End())
|
||||
return false;
|
||||
|
||||
Vk::QueueHandle transferQueue = m_device.GetQueue(m_device.GetTransferQueueFamilyIndex(), 0);
|
||||
Vk::QueueHandle transferQueue = m_device.GetQueue(m_device.GetDefaultFamilyIndex(QueueType::Transfer), 0);
|
||||
if (!transferQueue.Submit(copyCommandBuffer))
|
||||
return false;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Vulkan Renderer"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/VulkanRenderer/VulkanCommandPool.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanCommandBuffer.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanCommandBufferBuilder.hpp>
|
||||
#include <Nazara/VulkanRenderer/Wrapper/CommandBuffer.hpp>
|
||||
#include <Nazara/VulkanRenderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
std::unique_ptr<CommandBuffer> VulkanCommandPool::BuildCommandBuffer(const std::function<void(CommandBufferBuilder& builder)>& callback)
|
||||
{
|
||||
Vk::AutoCommandBuffer commandBuffer = m_commandPool.AllocateCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY);
|
||||
|
||||
if (!commandBuffer->Begin())
|
||||
throw std::runtime_error("failed to begin command buffer: " + TranslateVulkanError(commandBuffer->GetLastErrorCode()));
|
||||
|
||||
VulkanCommandBufferBuilder builder(commandBuffer.Get());
|
||||
callback(builder);
|
||||
|
||||
if (!commandBuffer->End())
|
||||
throw std::runtime_error("failed to build command buffer: " + TranslateVulkanError(commandBuffer->GetLastErrorCode()));
|
||||
|
||||
return std::make_unique<VulkanCommandBuffer>(std::move(commandBuffer));
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/VulkanRenderer/VulkanDevice.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanCommandPool.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanRenderPipeline.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanRenderPipelineLayout.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanShaderStage.hpp>
|
||||
|
|
@ -19,6 +20,11 @@ namespace Nz
|
|||
return std::make_unique<VulkanBuffer>(*this, type);
|
||||
}
|
||||
|
||||
std::unique_ptr<CommandPool> VulkanDevice::InstantiateCommandPool(QueueType queueType)
|
||||
{
|
||||
return std::make_unique<VulkanCommandPool>(*this, queueType);
|
||||
}
|
||||
|
||||
std::unique_ptr<RenderPipeline> VulkanDevice::InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo)
|
||||
{
|
||||
return std::make_unique<VulkanRenderPipeline>(*this, std::move(pipelineInfo));
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ namespace Nz
|
|||
m_inFlightCommandBuffers.clear();
|
||||
}
|
||||
|
||||
void VulkanRenderImage::Execute(const std::function<void(CommandBufferBuilder& builder)>& callback, bool isGraphical)
|
||||
void VulkanRenderImage::Execute(const std::function<void(CommandBufferBuilder& builder)>& callback, QueueTypeFlags queueTypeFlags)
|
||||
{
|
||||
Vk::CommandBuffer* commandBuffer;
|
||||
if (m_currentCommandBuffer >= m_inFlightCommandBuffers.size())
|
||||
|
|
@ -55,7 +55,7 @@ namespace Nz
|
|||
if (!commandBuffer->End())
|
||||
throw std::runtime_error("failed to build command buffer: " + TranslateVulkanError(commandBuffer->GetLastErrorCode()));
|
||||
|
||||
SubmitCommandBuffer(*commandBuffer, isGraphical);
|
||||
SubmitCommandBuffer(*commandBuffer, queueTypeFlags);
|
||||
}
|
||||
|
||||
VulkanUploadPool& VulkanRenderImage::GetUploadPool()
|
||||
|
|
@ -63,16 +63,16 @@ namespace Nz
|
|||
return m_uploadPool;
|
||||
}
|
||||
|
||||
void VulkanRenderImage::SubmitCommandBuffer(CommandBuffer* commandBuffer, bool isGraphical)
|
||||
void VulkanRenderImage::SubmitCommandBuffer(CommandBuffer* commandBuffer, QueueTypeFlags queueTypeFlags)
|
||||
{
|
||||
VulkanCommandBuffer& vkCommandBuffer = *static_cast<VulkanCommandBuffer*>(commandBuffer);
|
||||
|
||||
return SubmitCommandBuffer(vkCommandBuffer.GetCommandBuffer(), isGraphical);
|
||||
return SubmitCommandBuffer(vkCommandBuffer.GetCommandBuffer(), queueTypeFlags);
|
||||
}
|
||||
|
||||
void VulkanRenderImage::SubmitCommandBuffer(VkCommandBuffer commandBuffer, bool isGraphical)
|
||||
void VulkanRenderImage::SubmitCommandBuffer(VkCommandBuffer commandBuffer, QueueTypeFlags queueTypeFlags)
|
||||
{
|
||||
if (isGraphical)
|
||||
if (queueTypeFlags & QueueType::Graphics)
|
||||
m_graphicalCommandsBuffers.push_back(commandBuffer);
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ namespace Nz
|
|||
|
||||
std::memcpy(allocationInfo.pMappedData, ptr, textureSize);
|
||||
|
||||
Vk::AutoCommandBuffer copyCommandBuffer = m_device.AllocateTransferCommandBuffer();
|
||||
Vk::AutoCommandBuffer copyCommandBuffer = m_device.AllocateCommandBuffer(QueueType::Graphics);
|
||||
if (!copyCommandBuffer->Begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT))
|
||||
return false;
|
||||
|
||||
|
|
@ -220,7 +220,7 @@ namespace Nz
|
|||
if (!copyCommandBuffer->End())
|
||||
return false;
|
||||
|
||||
Vk::QueueHandle transferQueue = m_device.GetQueue(m_device.GetTransferQueueFamilyIndex(), 0);
|
||||
Vk::QueueHandle transferQueue = m_device.GetQueue(m_device.GetDefaultFamilyIndex(QueueType::Graphics), 0);
|
||||
if (!transferQueue.Submit(copyCommandBuffer))
|
||||
return false;
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace Nz
|
|||
{
|
||||
struct Device::InternalData
|
||||
{
|
||||
Vk::CommandPool transferCommandPool;
|
||||
std::array<Vk::CommandPool, QueueCount> commandPools;
|
||||
};
|
||||
|
||||
Device::Device(Instance& instance) :
|
||||
|
|
@ -40,9 +40,9 @@ namespace Nz
|
|||
WaitAndDestroyDevice();
|
||||
}
|
||||
|
||||
AutoCommandBuffer Device::AllocateTransferCommandBuffer()
|
||||
AutoCommandBuffer Device::AllocateCommandBuffer(QueueType queueType)
|
||||
{
|
||||
return m_internalData->transferCommandPool.AllocateCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY);
|
||||
return m_internalData->commandPools[UnderlyingCast(queueType)].AllocateCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY);
|
||||
}
|
||||
|
||||
bool Device::Create(const Vk::PhysicalDevice& deviceInfo, const VkDeviceCreateInfo& createInfo, const VkAllocationCallbacks* allocator)
|
||||
|
|
@ -107,8 +107,6 @@ 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)
|
||||
|
|
@ -133,17 +131,6 @@ 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);
|
||||
|
|
@ -151,12 +138,48 @@ namespace Nz
|
|||
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))
|
||||
|
||||
m_defaultQueues.fill(InvalidQueue);
|
||||
for (QueueType queueType : { QueueType::Graphics, QueueType::Compute, QueueType::Transfer })
|
||||
{
|
||||
NazaraError("Failed to create transfer command pool: " + TranslateVulkanError(m_internalData->transferCommandPool.GetLastErrorCode()));
|
||||
return false;
|
||||
auto QueueTypeToFlags = [](QueueType type) -> VkQueueFlags
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case QueueType::Compute: return VK_QUEUE_COMPUTE_BIT;
|
||||
case QueueType::Graphics: return VK_QUEUE_GRAPHICS_BIT;
|
||||
case QueueType::Transfer: return VK_QUEUE_COMPUTE_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_TRANSFER_BIT; //< Compute/graphics imply transfer
|
||||
}
|
||||
|
||||
return 0U;
|
||||
};
|
||||
|
||||
std::size_t queueIndex = static_cast<std::size_t>(queueType);
|
||||
for (const QueueFamilyInfo& familyInfo : m_enabledQueuesInfos)
|
||||
{
|
||||
if (familyInfo.flags & QueueTypeToFlags(queueType) == 0)
|
||||
continue;
|
||||
|
||||
m_defaultQueues[queueIndex] = familyInfo.familyIndex;
|
||||
|
||||
// Break only if queue has not been selected before
|
||||
auto queueBegin = m_defaultQueues.begin();
|
||||
auto queueEnd = queueBegin + queueIndex;
|
||||
|
||||
if (std::find(queueBegin, queueEnd, familyInfo.familyIndex) == queueEnd)
|
||||
break;
|
||||
}
|
||||
|
||||
Vk::CommandPool& commandPool = m_internalData->commandPools[queueIndex];
|
||||
if (!commandPool.Create(*this, m_defaultQueues[queueIndex], VK_COMMAND_POOL_CREATE_TRANSIENT_BIT))
|
||||
{
|
||||
NazaraError("Failed to create command pool: " + TranslateVulkanError(commandPool.GetLastErrorCode()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
assert(GetDefaultFamilyIndex(QueueType::Transfer) != InvalidQueue);
|
||||
|
||||
// Initialize VMA
|
||||
VmaVulkanFunctions vulkanFunctions = {
|
||||
m_instance.vkGetPhysicalDeviceProperties,
|
||||
|
|
|
|||
Loading…
Reference in New Issue