Add new Renderer architecture (far from complete)
Former-commit-id: 52226793d7a087dfe0523315d3303934daffee49 [formerly 9de1c04df6b371f861a2eee8bba38902ee5041cd] [formerly ecd3099df5498722f6390447f40bd3907b8e40c4 [formerly 3076df585565fc9759ab3e718270f2e5ef620840]] Former-commit-id: 92d52f967d0b088d1271afef26069e08cacd6b0f [formerly 5fe27e2ead104278951c772c2121a7b677f88d4d] Former-commit-id: fb6c2456d8edd3ec022d5d953f79fecdd4f2b8f4
This commit is contained in:
31
src/Nazara/VulkanRenderer/Debug/NewOverload.cpp
Normal file
31
src/Nazara/VulkanRenderer/Debug/NewOverload.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (C) 2014 AUTHORS
|
||||
// This file is part of the "Nazara Engine - Module name"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/VulkanRenderer/Config.hpp>
|
||||
#if NAZARA_VULKANRENDERER_MANAGE_MEMORY
|
||||
|
||||
#include <Nazara/Core/MemoryManager.hpp>
|
||||
#include <new> // Nécessaire ?
|
||||
|
||||
void* operator new(std::size_t size)
|
||||
{
|
||||
return Nz::MemoryManager::Allocate(size, false);
|
||||
}
|
||||
|
||||
void* operator new[](std::size_t size)
|
||||
{
|
||||
return Nz::MemoryManager::Allocate(size, true);
|
||||
}
|
||||
|
||||
void operator delete(void* pointer) noexcept
|
||||
{
|
||||
Nz::MemoryManager::Free(pointer, false);
|
||||
}
|
||||
|
||||
void operator delete[](void* pointer) noexcept
|
||||
{
|
||||
Nz::MemoryManager::Free(pointer, true);
|
||||
}
|
||||
|
||||
#endif // NAZARA_VULKANRENDERER_MANAGE_MEMORY
|
||||
15
src/Nazara/VulkanRenderer/Export.cpp
Normal file
15
src/Nazara/VulkanRenderer/Export.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright (C) 2016 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/Prerequesites.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanRenderer.hpp>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
NAZARA_EXPORT Nz::RendererImpl* NazaraRenderer_Instantiate()
|
||||
{
|
||||
std::unique_ptr<Nz::VulkanRenderer> renderer(new Nz::VulkanRenderer);
|
||||
return renderer.release();
|
||||
}
|
||||
}
|
||||
14
src/Nazara/VulkanRenderer/RenderTarget.cpp
Normal file
14
src/Nazara/VulkanRenderer/RenderTarget.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright (C) 2016 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/RenderTarget.hpp>
|
||||
#include <Nazara/VulkanRenderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
RenderTarget::~RenderTarget()
|
||||
{
|
||||
OnRenderTargetRelease(this);
|
||||
}
|
||||
}
|
||||
530
src/Nazara/VulkanRenderer/RenderWindow.cpp
Normal file
530
src/Nazara/VulkanRenderer/RenderWindow.cpp
Normal file
@@ -0,0 +1,530 @@
|
||||
// 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/VulkanRenderer/RenderWindow.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/Utility/PixelFormat.hpp>
|
||||
#include <Nazara/VulkanRenderer/Vulkan.hpp>
|
||||
#include <array>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/VulkanRenderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
RenderWindow::RenderWindow() :
|
||||
RenderTarget(), Window(),
|
||||
m_surface(Nz::Vulkan::GetInstance()),
|
||||
m_forcedPhysicalDevice(nullptr),
|
||||
m_depthStencilFormat(VK_FORMAT_MAX_ENUM)
|
||||
{
|
||||
}
|
||||
|
||||
RenderWindow::RenderWindow(VideoMode mode, const String& title, UInt32 style) :
|
||||
RenderWindow()
|
||||
{
|
||||
ErrorFlags flags(ErrorFlag_ThrowException, true);
|
||||
Create(mode, title, style);
|
||||
}
|
||||
|
||||
RenderWindow::RenderWindow(WindowHandle handle) :
|
||||
RenderWindow()
|
||||
{
|
||||
ErrorFlags flags(ErrorFlag_ThrowException, true);
|
||||
Create(handle);
|
||||
}
|
||||
|
||||
RenderWindow::~RenderWindow()
|
||||
{
|
||||
// Nécessaire si Window::Destroy est appelé par son destructeur
|
||||
OnWindowDestroy();
|
||||
}
|
||||
|
||||
bool RenderWindow::Acquire(UInt32* imageIndex) const
|
||||
{
|
||||
if (!m_swapchain.AcquireNextImage(std::numeric_limits<UInt64>::max(), m_imageReadySemaphore, VK_NULL_HANDLE, imageIndex))
|
||||
{
|
||||
NazaraError("Failed to acquire next image");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderWindow::BuildPreRenderCommands(UInt32 imageIndex, Vk::CommandBuffer& commandBuffer)
|
||||
{
|
||||
//commandBuffer.SetImageLayout(m_swapchain.GetBuffer(imageIndex).image, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
|
||||
// Temporary
|
||||
if (m_depthStencilFormat != VK_FORMAT_MAX_ENUM)
|
||||
{
|
||||
VkImageSubresourceRange imageRange = {
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageAspectFlags aspectMask
|
||||
0, // uint32_t baseMipLevel
|
||||
1, // uint32_t levelCount
|
||||
0, // uint32_t baseArrayLayer
|
||||
1 // uint32_t layerCount
|
||||
};
|
||||
|
||||
commandBuffer.SetImageLayout(m_depthBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, imageRange);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderWindow::BuildPostRenderCommands(UInt32 imageIndex, Vk::CommandBuffer& commandBuffer)
|
||||
{
|
||||
//commandBuffer.SetImageLayout(m_swapchain.GetBuffer(imageIndex).image, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||
}
|
||||
|
||||
const Vk::Framebuffer& RenderWindow::GetFrameBuffer(UInt32 imageIndex) const
|
||||
{
|
||||
return m_frameBuffers[imageIndex];
|
||||
}
|
||||
|
||||
UInt32 RenderWindow::GetFramebufferCount() const
|
||||
{
|
||||
return static_cast<UInt32>(m_frameBuffers.size());
|
||||
}
|
||||
|
||||
bool RenderWindow::Create(VideoMode mode, const String& title, UInt32 style)
|
||||
{
|
||||
return Window::Create(mode, title, style);
|
||||
}
|
||||
|
||||
bool RenderWindow::Create(WindowHandle handle)
|
||||
{
|
||||
return Window::Create(handle);
|
||||
}
|
||||
|
||||
const Vk::DeviceHandle& RenderWindow::GetDevice() const
|
||||
{
|
||||
return m_device;
|
||||
}
|
||||
|
||||
UInt32 RenderWindow::GetPresentableFamilyQueue() const
|
||||
{
|
||||
return m_presentableFamilyQueue;
|
||||
}
|
||||
|
||||
const Vk::Surface& RenderWindow::GetSurface() const
|
||||
{
|
||||
return m_surface;
|
||||
}
|
||||
|
||||
const Vk::Swapchain& RenderWindow::GetSwapchain() const
|
||||
{
|
||||
return m_swapchain;
|
||||
}
|
||||
|
||||
void RenderWindow::Present(UInt32 imageIndex)
|
||||
{
|
||||
NazaraAssert(imageIndex < m_frameBuffers.size(), "Invalid image index");
|
||||
|
||||
m_presentQueue.Present(m_swapchain, imageIndex);
|
||||
}
|
||||
|
||||
bool RenderWindow::IsValid() const
|
||||
{
|
||||
return m_impl != nullptr;
|
||||
}
|
||||
|
||||
void RenderWindow::SetDepthStencilFormats(std::vector<PixelFormatType> pixelFormat)
|
||||
{
|
||||
m_wantedDepthStencilFormats = std::move(pixelFormat);
|
||||
}
|
||||
|
||||
void RenderWindow::SetPhysicalDevice(VkPhysicalDevice device)
|
||||
{
|
||||
m_forcedPhysicalDevice = device;
|
||||
}
|
||||
|
||||
bool RenderWindow::OnWindowCreated()
|
||||
{
|
||||
OnRenderTargetSizeChange(this);
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
HWND handle = reinterpret_cast<HWND>(GetHandle());
|
||||
HINSTANCE instance = reinterpret_cast<HINSTANCE>(GetWindowLongPtrW(handle, GWLP_HINSTANCE));
|
||||
bool success = m_surface.Create(instance, handle);
|
||||
#else
|
||||
#error This OS is not supported by Vulkan
|
||||
#endif
|
||||
|
||||
if (!success)
|
||||
{
|
||||
NazaraError("Failed to create Vulkan surface");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_device = Vulkan::SelectDevice(m_forcedPhysicalDevice, m_surface, &m_presentableFamilyQueue);
|
||||
if (!m_device)
|
||||
{
|
||||
NazaraError("Failed to get compatible Vulkan device");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_presentQueue = m_device->GetQueue(m_presentableFamilyQueue, 0);
|
||||
|
||||
std::vector<VkSurfaceFormatKHR> surfaceFormats;
|
||||
if (!m_surface.GetFormats(m_forcedPhysicalDevice, &surfaceFormats))
|
||||
{
|
||||
NazaraError("Failed to query supported surface formats");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (surfaceFormats.size() == 1 && surfaceFormats[0].format == VK_FORMAT_UNDEFINED)
|
||||
m_colorFormat = VK_FORMAT_B8G8R8A8_UNORM;
|
||||
else
|
||||
m_colorFormat = surfaceFormats[0].format;
|
||||
|
||||
m_colorSpace = surfaceFormats[0].colorSpace;
|
||||
|
||||
if (!m_wantedDepthStencilFormats.empty())
|
||||
{
|
||||
const Vk::PhysicalDevice& deviceInfo = Vulkan::GetPhysicalDeviceInfo(m_forcedPhysicalDevice);
|
||||
|
||||
for (PixelFormatType format : m_wantedDepthStencilFormats)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case PixelFormatType_Depth16:
|
||||
m_depthStencilFormat = VK_FORMAT_D16_UNORM;
|
||||
break;
|
||||
|
||||
case PixelFormatType_Depth24:
|
||||
case PixelFormatType_Depth24Stencil8:
|
||||
m_depthStencilFormat = VK_FORMAT_D24_UNORM_S8_UINT;
|
||||
break;
|
||||
|
||||
case PixelFormatType_Depth32:
|
||||
m_depthStencilFormat = VK_FORMAT_D32_SFLOAT;
|
||||
break;
|
||||
|
||||
case PixelFormatType_Stencil1:
|
||||
case PixelFormatType_Stencil4:
|
||||
case PixelFormatType_Stencil8:
|
||||
m_depthStencilFormat = VK_FORMAT_S8_UINT;
|
||||
break;
|
||||
|
||||
case PixelFormatType_Stencil16:
|
||||
m_depthStencilFormat = VK_FORMAT_MAX_ENUM;
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
PixelFormatContent formatContent = PixelFormat::GetContent(format);
|
||||
if (formatContent != PixelFormatContent_DepthStencil && formatContent != PixelFormatContent_Stencil)
|
||||
NazaraWarning("Invalid format " + PixelFormat::GetName(format) + " for depth-stencil attachment");
|
||||
|
||||
m_depthStencilFormat = VK_FORMAT_MAX_ENUM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_depthStencilFormat != VK_FORMAT_MAX_ENUM)
|
||||
{
|
||||
VkFormatProperties formatProperties = m_device->GetInstance().GetPhysicalDeviceFormatProperties(m_forcedPhysicalDevice, m_depthStencilFormat);
|
||||
if (formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
|
||||
break; //< Found it
|
||||
|
||||
m_depthStencilFormat = VK_FORMAT_MAX_ENUM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!SetupSwapchain())
|
||||
{
|
||||
NazaraError("Failed to create swapchain");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_depthStencilFormat != VK_FORMAT_MAX_ENUM && !SetupDepthBuffer())
|
||||
{
|
||||
NazaraError("Failed to create depth buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SetupRenderPass())
|
||||
{
|
||||
NazaraError("Failed to create render pass");
|
||||
return false;
|
||||
}
|
||||
|
||||
UInt32 imageCount = m_swapchain.GetBufferCount();
|
||||
|
||||
// Framebuffers
|
||||
m_frameBuffers.resize(imageCount);
|
||||
for (UInt32 i = 0; i < imageCount; ++i)
|
||||
{
|
||||
std::array<VkImageView, 2> attachments = {m_swapchain.GetBuffer(i).view, m_depthBufferView};
|
||||
|
||||
VkFramebufferCreateInfo frameBufferCreate = {
|
||||
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
|
||||
nullptr, // const void* pNext;
|
||||
0, // VkFramebufferCreateFlags flags;
|
||||
m_renderPass, // VkRenderPass renderPass;
|
||||
(attachments[1] != VK_NULL_HANDLE) ? 2U : 1U, // uint32_t attachmentCount;
|
||||
attachments.data(), // const VkImageView* pAttachments;
|
||||
GetWidth(), // uint32_t width;
|
||||
GetHeight(), // uint32_t height;
|
||||
1U // uint32_t layers;
|
||||
};
|
||||
|
||||
if (!m_frameBuffers[i].Create(m_device, frameBufferCreate))
|
||||
{
|
||||
NazaraError("Failed to create framebuffer for image #" + String::Number(i));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_imageReadySemaphore.Create(m_device);
|
||||
|
||||
m_clock.Restart();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderWindow::OnWindowDestroy()
|
||||
{
|
||||
m_device->WaitForIdle();
|
||||
m_frameBuffers.clear();
|
||||
m_renderPass.Destroy();
|
||||
|
||||
m_swapchain.Destroy();
|
||||
m_surface.Destroy();
|
||||
}
|
||||
|
||||
void RenderWindow::OnWindowResized()
|
||||
{
|
||||
OnRenderTargetSizeChange(this);
|
||||
}
|
||||
|
||||
bool RenderWindow::SetupDepthBuffer()
|
||||
{
|
||||
VkImageCreateInfo imageCreateInfo = {
|
||||
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
|
||||
nullptr, // const void* pNext;
|
||||
0U, // VkImageCreateFlags flags;
|
||||
VK_IMAGE_TYPE_2D, // VkImageType imageType;
|
||||
m_depthStencilFormat, // VkFormat format;
|
||||
{GetWidth(), GetHeight(), 1U}, // VkExtent3D extent;
|
||||
1U, // uint32_t mipLevels;
|
||||
1U, // uint32_t arrayLayers;
|
||||
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
|
||||
VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
|
||||
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags usage;
|
||||
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
|
||||
0U, // uint32_t queueFamilyIndexCount;
|
||||
nullptr, // const uint32_t* pQueueFamilyIndices;
|
||||
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
|
||||
};
|
||||
|
||||
if (!m_depthBuffer.Create(m_device, imageCreateInfo))
|
||||
{
|
||||
NazaraError("Failed to create depth buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
VkMemoryRequirements memoryReq = m_depthBuffer.GetMemoryRequirements();
|
||||
if (!m_depthBufferMemory.Create(m_device, memoryReq.size, memoryReq.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT))
|
||||
{
|
||||
NazaraError("Failed to allocate depth buffer memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_depthBuffer.BindImageMemory(m_depthBufferMemory))
|
||||
{
|
||||
NazaraError("Failed to bind depth buffer to buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
VkImageViewCreateInfo imageViewCreateInfo = {
|
||||
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
|
||||
nullptr, // const void* pNext;
|
||||
0, // VkImageViewCreateFlags flags;
|
||||
m_depthBuffer, // VkImage image;
|
||||
VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType;
|
||||
m_depthStencilFormat, // VkFormat format;
|
||||
{ // VkComponentMapping components;
|
||||
VK_COMPONENT_SWIZZLE_R, // VkComponentSwizzle .r;
|
||||
VK_COMPONENT_SWIZZLE_G, // VkComponentSwizzle .g;
|
||||
VK_COMPONENT_SWIZZLE_B, // VkComponentSwizzle .b;
|
||||
VK_COMPONENT_SWIZZLE_A // VkComponentSwizzle .a;
|
||||
},
|
||||
{ // VkImageSubresourceRange subresourceRange;
|
||||
VK_IMAGE_ASPECT_DEPTH_BIT, // VkImageAspectFlags .aspectMask;
|
||||
0, // uint32_t .baseMipLevel;
|
||||
1, // uint32_t .levelCount;
|
||||
0, // uint32_t .baseArrayLayer;
|
||||
1 // uint32_t .layerCount;
|
||||
}
|
||||
};
|
||||
|
||||
if (!m_depthBufferView.Create(m_device, imageViewCreateInfo))
|
||||
{
|
||||
NazaraError("Failed to create depth buffer view");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenderWindow::SetupRenderPass()
|
||||
{
|
||||
std::array<VkAttachmentDescription, 2> attachments = {
|
||||
{
|
||||
{
|
||||
0, // VkAttachmentDescriptionFlags flags;
|
||||
m_colorFormat, // VkFormat format;
|
||||
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
|
||||
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp;
|
||||
VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
|
||||
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
|
||||
VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
|
||||
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
|
||||
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR // VkImageLayout finalLayout;
|
||||
},
|
||||
{
|
||||
0, // VkAttachmentDescriptionFlags flags;
|
||||
m_depthStencilFormat, // VkFormat format;
|
||||
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
|
||||
VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
|
||||
VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp storeOp;
|
||||
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
|
||||
VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout;
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout;
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
VkAttachmentReference colorReference = {
|
||||
0, // uint32_t attachment;
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
|
||||
};
|
||||
|
||||
VkAttachmentReference depthReference = {
|
||||
1, // uint32_t attachment;
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL // VkImageLayout layout;
|
||||
};
|
||||
|
||||
VkSubpassDescription subpass = {
|
||||
0, // VkSubpassDescriptionFlags flags;
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
|
||||
0U, // uint32_t inputAttachmentCount;
|
||||
nullptr, // const VkAttachmentReference* pInputAttachments;
|
||||
1U, // uint32_t colorAttachmentCount;
|
||||
&colorReference, // const VkAttachmentReference* pColorAttachments;
|
||||
nullptr, // const VkAttachmentReference* pResolveAttachments;
|
||||
(m_depthStencilFormat != VK_FORMAT_MAX_ENUM) ? &depthReference : nullptr, // const VkAttachmentReference* pDepthStencilAttachment;
|
||||
0U, // uint32_t preserveAttachmentCount;
|
||||
nullptr // const uint32_t* pPreserveAttachments;
|
||||
};
|
||||
|
||||
std::array<VkSubpassDependency, 2> dependencies;
|
||||
// First dependency at the start of the renderpass
|
||||
// Does the transition from final to initial layout
|
||||
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL; // Producer of the dependency
|
||||
dependencies[0].dstSubpass = 0; // Consumer is our single subpass that will wait for the execution depdendency
|
||||
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
||||
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
|
||||
|
||||
// Second dependency at the end the renderpass
|
||||
// Does the transition from the initial to the final layout
|
||||
dependencies[1].srcSubpass = 0; // Producer of the dependency is our single subpass
|
||||
dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL; // Consumer are all commands outside of the renderpass
|
||||
dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
||||
dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
|
||||
|
||||
VkRenderPassCreateInfo createInfo = {
|
||||
VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
|
||||
nullptr, // const void* pNext;
|
||||
0, // VkRenderPassCreateFlags flags;
|
||||
(m_depthStencilFormat != VK_FORMAT_MAX_ENUM) ? 2U : 1U, // uint32_t attachmentCount;
|
||||
attachments.data(), // const VkAttachmentDescription* pAttachments;
|
||||
1U, // uint32_t subpassCount;
|
||||
&subpass, // const VkSubpassDescription* pSubpasses;
|
||||
dependencies.size(), // uint32_t dependencyCount;
|
||||
dependencies.data() // const VkSubpassDependency* pDependencies;
|
||||
};
|
||||
|
||||
return m_renderPass.Create(m_device, createInfo);
|
||||
}
|
||||
|
||||
bool RenderWindow::SetupSwapchain()
|
||||
{
|
||||
VkSurfaceCapabilitiesKHR surfaceCapabilities;
|
||||
if (!m_surface.GetCapabilities(m_forcedPhysicalDevice, &surfaceCapabilities))
|
||||
{
|
||||
NazaraError("Failed to query surface capabilities");
|
||||
return false;
|
||||
}
|
||||
|
||||
Nz::UInt32 imageCount = surfaceCapabilities.minImageCount + 1;
|
||||
if (surfaceCapabilities.maxImageCount > 0 && imageCount > surfaceCapabilities.maxImageCount)
|
||||
imageCount = surfaceCapabilities.maxImageCount;
|
||||
|
||||
VkExtent2D extent;
|
||||
if (surfaceCapabilities.currentExtent.width == -1)
|
||||
{
|
||||
extent.width = Nz::Clamp<Nz::UInt32>(GetWidth(), surfaceCapabilities.minImageExtent.width, surfaceCapabilities.maxImageExtent.width);
|
||||
extent.height = Nz::Clamp<Nz::UInt32>(GetHeight(), surfaceCapabilities.minImageExtent.height, surfaceCapabilities.maxImageExtent.height);
|
||||
}
|
||||
else
|
||||
extent = surfaceCapabilities.currentExtent;
|
||||
|
||||
std::vector<VkPresentModeKHR> presentModes;
|
||||
if (!m_surface.GetPresentModes(m_forcedPhysicalDevice, &presentModes))
|
||||
{
|
||||
NazaraError("Failed to query supported present modes");
|
||||
return false;
|
||||
}
|
||||
|
||||
VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
|
||||
for (VkPresentModeKHR presentMode : presentModes)
|
||||
{
|
||||
if (presentMode == VK_PRESENT_MODE_MAILBOX_KHR)
|
||||
{
|
||||
swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (presentMode == VK_PRESENT_MODE_IMMEDIATE_KHR)
|
||||
swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||
}
|
||||
|
||||
VkSwapchainCreateInfoKHR swapchainInfo = {
|
||||
VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
|
||||
nullptr,
|
||||
0,
|
||||
m_surface,
|
||||
imageCount,
|
||||
m_colorFormat,
|
||||
m_colorSpace,
|
||||
extent,
|
||||
1,
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
|
||||
VK_SHARING_MODE_EXCLUSIVE,
|
||||
0, nullptr,
|
||||
surfaceCapabilities.currentTransform,
|
||||
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
|
||||
swapchainPresentMode,
|
||||
VK_TRUE,
|
||||
0
|
||||
};
|
||||
|
||||
if (!m_swapchain.Create(m_device, swapchainInfo))
|
||||
{
|
||||
NazaraError("Failed to create swapchain");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
53
src/Nazara/VulkanRenderer/VkCommandPool.cpp
Normal file
53
src/Nazara/VulkanRenderer/VkCommandPool.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright (C) 2016 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/VkCommandPool.hpp>
|
||||
#include <Nazara/VulkanRenderer/VkCommandBuffer.hpp>
|
||||
#include <Nazara/VulkanRenderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace Vk
|
||||
{
|
||||
CommandBuffer CommandPool::AllocateCommandBuffer(VkCommandBufferLevel level)
|
||||
{
|
||||
VkCommandBufferAllocateInfo createInfo =
|
||||
{
|
||||
VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
nullptr,
|
||||
m_handle,
|
||||
level,
|
||||
1U
|
||||
};
|
||||
|
||||
VkCommandBuffer handle = VK_NULL_HANDLE;
|
||||
m_lastErrorCode = m_device->vkAllocateCommandBuffers(*m_device, &createInfo, &handle);
|
||||
|
||||
return CommandBuffer(*this, handle);
|
||||
}
|
||||
|
||||
std::vector<CommandBuffer> CommandPool::AllocateCommandBuffers(UInt32 commandBufferCount, VkCommandBufferLevel level)
|
||||
{
|
||||
VkCommandBufferAllocateInfo createInfo =
|
||||
{
|
||||
VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
nullptr,
|
||||
m_handle,
|
||||
level,
|
||||
commandBufferCount
|
||||
};
|
||||
|
||||
std::vector<VkCommandBuffer> handles(commandBufferCount, VK_NULL_HANDLE);
|
||||
m_lastErrorCode = m_device->vkAllocateCommandBuffers(*m_device, &createInfo, handles.data());
|
||||
if (m_lastErrorCode != VkResult::VK_SUCCESS)
|
||||
return std::vector<CommandBuffer>();
|
||||
|
||||
std::vector<CommandBuffer> commandBuffers;
|
||||
for (UInt32 i = 0; i < commandBufferCount; ++i)
|
||||
commandBuffers.emplace_back(CommandBuffer(*this, handles[i]));
|
||||
|
||||
return commandBuffers;
|
||||
}
|
||||
}
|
||||
}
|
||||
53
src/Nazara/VulkanRenderer/VkDescriptorPool.cpp
Normal file
53
src/Nazara/VulkanRenderer/VkDescriptorPool.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright (C) 2016 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/VkDescriptorPool.hpp>
|
||||
#include <Nazara/VulkanRenderer/VkDescriptorSet.hpp>
|
||||
#include <Nazara/VulkanRenderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace Vk
|
||||
{
|
||||
DescriptorSet DescriptorPool::AllocateDescriptorSet(const VkDescriptorSetLayout& setLayouts)
|
||||
{
|
||||
VkDescriptorSetAllocateInfo createInfo =
|
||||
{
|
||||
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType;
|
||||
nullptr, // const void* pNext;
|
||||
m_handle, // VkDescriptorPool descriptorPool;
|
||||
1U, // uint32_t descriptorSetCount;
|
||||
&setLayouts // const VkDescriptorSetLayout* pSetLayouts;
|
||||
};
|
||||
|
||||
VkDescriptorSet handle = VK_NULL_HANDLE;
|
||||
m_lastErrorCode = m_device->vkAllocateDescriptorSets(*m_device, &createInfo, &handle);
|
||||
|
||||
return DescriptorSet(*this, handle);
|
||||
}
|
||||
|
||||
std::vector<DescriptorSet> DescriptorPool::AllocateDescriptorSets(UInt32 descriptorSetCount, const VkDescriptorSetLayout* setLayouts)
|
||||
{
|
||||
VkDescriptorSetAllocateInfo createInfo =
|
||||
{
|
||||
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType;
|
||||
nullptr, // const void* pNext;
|
||||
m_handle, // VkDescriptorPool descriptorPool;
|
||||
descriptorSetCount, // uint32_t descriptorSetCount;
|
||||
setLayouts // const VkDescriptorSetLayout* pSetLayouts;
|
||||
};
|
||||
|
||||
std::vector<VkDescriptorSet> handles(descriptorSetCount, VK_NULL_HANDLE);
|
||||
m_lastErrorCode = m_device->vkAllocateDescriptorSets(*m_device, &createInfo, handles.data());
|
||||
if (m_lastErrorCode != VkResult::VK_SUCCESS)
|
||||
return std::vector<DescriptorSet>();
|
||||
|
||||
std::vector<DescriptorSet> descriptorSets;
|
||||
for (UInt32 i = 0; i < descriptorSetCount; ++i)
|
||||
descriptorSets.emplace_back(DescriptorSet(*this, handles[i]));
|
||||
|
||||
return descriptorSets;
|
||||
}
|
||||
}
|
||||
}
|
||||
222
src/Nazara/VulkanRenderer/VkDevice.cpp
Normal file
222
src/Nazara/VulkanRenderer/VkDevice.cpp
Normal file
@@ -0,0 +1,222 @@
|
||||
// Copyright (C) 2016 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/VkDevice.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/VulkanRenderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace Vk
|
||||
{
|
||||
bool Device::Create(VkPhysicalDevice device, const VkDeviceCreateInfo& createInfo, const VkAllocationCallbacks* allocator)
|
||||
{
|
||||
std::vector<VkQueueFamilyProperties> queuesProperties;
|
||||
if (!m_instance.GetPhysicalDeviceQueueFamilyProperties(device, &queuesProperties))
|
||||
{
|
||||
NazaraError("Failed to query queue family properties");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_lastErrorCode = m_instance.vkCreateDevice(device, &createInfo, allocator, &m_device);
|
||||
if (m_lastErrorCode != VkResult::VK_SUCCESS)
|
||||
{
|
||||
NazaraError("Failed to create Vulkan device");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_physicalDevice = device;
|
||||
|
||||
// Store the allocator to access them when needed
|
||||
if (allocator)
|
||||
m_allocator = *allocator;
|
||||
else
|
||||
m_allocator.pfnAllocation = nullptr;
|
||||
|
||||
// Parse extensions and layers
|
||||
for (UInt32 i = 0; i < createInfo.enabledExtensionCount; ++i)
|
||||
m_loadedExtensions.insert(createInfo.ppEnabledExtensionNames[i]);
|
||||
|
||||
for (UInt32 i = 0; i < createInfo.enabledLayerCount; ++i)
|
||||
m_loadedLayers.insert(createInfo.ppEnabledLayerNames[i]);
|
||||
|
||||
// Load all device-related functions
|
||||
#define NAZARA_VULKANRENDERER_LOAD_DEVICE(func) func = reinterpret_cast<PFN_##func>(GetProcAddr(#func))
|
||||
|
||||
try
|
||||
{
|
||||
ErrorFlags flags(ErrorFlag_ThrowException, true);
|
||||
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkAllocateCommandBuffers);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkAllocateDescriptorSets);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkAllocateMemory);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkBeginCommandBuffer);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkBindBufferMemory);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkBindImageMemory);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdBeginQuery);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdBeginRenderPass);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdBindDescriptorSets);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdBindIndexBuffer);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdBindPipeline);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdBindVertexBuffers);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdBlitImage);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdClearAttachments);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdClearColorImage);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdClearDepthStencilImage);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdCopyBuffer);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdCopyBufferToImage);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdCopyImage);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdCopyImageToBuffer);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdCopyQueryPoolResults);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdDispatch);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdDispatchIndirect);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdDraw);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdDrawIndexed);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdDrawIndexedIndirect);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdDrawIndirect);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdEndQuery);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdEndRenderPass);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdExecuteCommands);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdFillBuffer);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdNextSubpass);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdPipelineBarrier);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdPushConstants);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdResetEvent);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdResetQueryPool);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdResolveImage);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdSetBlendConstants);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdSetDepthBias);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdSetDepthBounds);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdSetEvent);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdSetLineWidth);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdSetScissor);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdSetStencilCompareMask);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdSetStencilReference);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdSetStencilWriteMask);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdSetViewport);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdUpdateBuffer);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdWaitEvents);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdWriteTimestamp);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateBuffer);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateBufferView);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateCommandPool);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateComputePipelines);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateDescriptorPool);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateDescriptorSetLayout);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateEvent);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateFramebuffer);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateGraphicsPipelines);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateImage);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateImageView);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreatePipelineCache);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreatePipelineLayout);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateRenderPass);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateSampler);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateSemaphore);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateShaderModule);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyBuffer);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyBufferView);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyCommandPool);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyDescriptorPool);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyDescriptorSetLayout);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyDevice);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyEvent);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyFramebuffer);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyImage);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyImageView);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyPipeline);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyPipelineCache);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyPipelineLayout);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyRenderPass);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroySampler);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroySemaphore);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyShaderModule);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDeviceWaitIdle);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkEndCommandBuffer);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkFreeCommandBuffers);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkFreeDescriptorSets);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkFreeMemory);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkFlushMappedMemoryRanges);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkGetBufferMemoryRequirements);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkGetDeviceMemoryCommitment);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkGetDeviceQueue);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkGetEventStatus);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkGetFenceStatus);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkGetImageMemoryRequirements);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkGetImageSparseMemoryRequirements);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkGetImageSubresourceLayout);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkGetRenderAreaGranularity);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkInvalidateMappedMemoryRanges);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkMapMemory);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkMergePipelineCaches);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkQueueSubmit);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkQueueWaitIdle);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkResetCommandBuffer);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkResetCommandPool);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkResetDescriptorPool);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkResetFences);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkResetEvent);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkSetEvent);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkUnmapMemory);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkUpdateDescriptorSets);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkWaitForFences);
|
||||
|
||||
// VK_KHR_display_swapchain
|
||||
if (IsExtensionLoaded("VK_KHR_display_swapchain"))
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateSharedSwapchainsKHR);
|
||||
|
||||
// VK_KHR_swapchain
|
||||
if (IsExtensionLoaded("VK_KHR_swapchain"))
|
||||
{
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkAcquireNextImageKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateSwapchainKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroySwapchainKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkGetSwapchainImagesKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkQueuePresentKHR);
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
NazaraError(String("Failed to query device function: ") + e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
#undef NAZARA_VULKANRENDERER_LOAD_DEVICE
|
||||
|
||||
// And retains informations about queues
|
||||
UInt32 maxFamilyIndex = 0;
|
||||
m_enabledQueuesInfos.resize(createInfo.queueCreateInfoCount);
|
||||
for (UInt32 i = 0; i < createInfo.queueCreateInfoCount; ++i)
|
||||
{
|
||||
const VkDeviceQueueCreateInfo& queueCreateInfo = createInfo.pQueueCreateInfos[i];
|
||||
QueueFamilyInfo& info = m_enabledQueuesInfos[i];
|
||||
|
||||
info.familyIndex = queueCreateInfo.queueFamilyIndex;
|
||||
if (info.familyIndex > maxFamilyIndex)
|
||||
maxFamilyIndex = info.familyIndex;
|
||||
|
||||
const VkQueueFamilyProperties& queueProperties = queuesProperties[info.familyIndex];
|
||||
info.flags = queueProperties.queueFlags;
|
||||
info.minImageTransferGranularity = queueProperties.minImageTransferGranularity;
|
||||
info.timestampValidBits = queueProperties.timestampValidBits;
|
||||
|
||||
info.queues.resize(queueCreateInfo.queueCount);
|
||||
for (UInt32 queueIndex = 0; queueIndex < queueCreateInfo.queueCount; ++queueIndex)
|
||||
{
|
||||
QueueInfo& queueInfo = info.queues[queueIndex];
|
||||
queueInfo.familyInfo = &info;
|
||||
queueInfo.priority = queueCreateInfo.pQueuePriorities[queueIndex];
|
||||
vkGetDeviceQueue(m_device, info.familyIndex, queueIndex, &queueInfo.queue);
|
||||
}
|
||||
}
|
||||
|
||||
m_queuesByFamily.resize(maxFamilyIndex + 1);
|
||||
for (const QueueFamilyInfo& familyInfo : m_enabledQueuesInfos)
|
||||
m_queuesByFamily[familyInfo.familyIndex] = &familyInfo.queues;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
193
src/Nazara/VulkanRenderer/VkInstance.cpp
Normal file
193
src/Nazara/VulkanRenderer/VkInstance.cpp
Normal file
@@ -0,0 +1,193 @@
|
||||
// Copyright (C) 2016 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/VkInstance.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/VulkanRenderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace Vk
|
||||
{
|
||||
bool Instance::Create(const VkInstanceCreateInfo& createInfo, const VkAllocationCallbacks* allocator)
|
||||
{
|
||||
m_lastErrorCode = Loader::vkCreateInstance(&createInfo, allocator, &m_instance);
|
||||
if (m_lastErrorCode != VkResult::VK_SUCCESS)
|
||||
{
|
||||
NazaraError("Failed to create Vulkan instance");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Store the allocator to access them when needed
|
||||
if (allocator)
|
||||
m_allocator = *allocator;
|
||||
else
|
||||
m_allocator.pfnAllocation = nullptr;
|
||||
|
||||
// Parse extensions and layers
|
||||
for (UInt32 i = 0; i < createInfo.enabledExtensionCount; ++i)
|
||||
m_loadedExtensions.insert(createInfo.ppEnabledExtensionNames[i]);
|
||||
|
||||
for (UInt32 i = 0; i < createInfo.enabledLayerCount; ++i)
|
||||
m_loadedLayers.insert(createInfo.ppEnabledLayerNames[i]);
|
||||
|
||||
// And now load everything
|
||||
#define NAZARA_VULKANRENDERER_LOAD_INSTANCE(func) func = reinterpret_cast<PFN_##func>(GetProcAddr(#func))
|
||||
|
||||
try
|
||||
{
|
||||
ErrorFlags flags(ErrorFlag_ThrowException, true);
|
||||
|
||||
// Vulkan core
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkCreateDevice);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkDestroyInstance);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkEnumeratePhysicalDevices);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetDeviceProcAddr);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceFeatures);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceFormatProperties);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceImageFormatProperties);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceMemoryProperties);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceProperties);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceQueueFamilyProperties);
|
||||
|
||||
// VK_KHR_display
|
||||
if (IsExtensionLoaded("VK_KHR_display"))
|
||||
{
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkCreateDisplayModeKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkCreateDisplayPlaneSurfaceKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetDisplayModePropertiesKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetDisplayPlaneCapabilitiesKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetDisplayPlaneSupportedDisplaysKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceDisplayPlanePropertiesKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceDisplayPropertiesKHR);
|
||||
}
|
||||
|
||||
// VK_KHR_surface
|
||||
if (IsExtensionLoaded("VK_KHR_surface"))
|
||||
{
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkDestroySurfaceKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceSurfaceFormatsKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceSurfacePresentModesKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceSurfaceSupportKHR);
|
||||
}
|
||||
|
||||
// VK_EXT_debug_report
|
||||
if (IsExtensionLoaded("VK_EXT_debug_report"))
|
||||
{
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkCreateDebugReportCallbackEXT);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkDestroyDebugReportCallbackEXT);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkDebugReportMessageEXT);
|
||||
}
|
||||
|
||||
#ifdef VK_USE_PLATFORM_ANDROID_KHR
|
||||
// VK_KHR_android_surface
|
||||
if (IsExtensionLoaded("VK_KHR_android_surface"))
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkCreateAndroidSurfaceKHR);
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_MIR_KHR
|
||||
// VK_KHR_mir_surface
|
||||
if (IsExtensionLoaded("VK_KHR_mir_surface"))
|
||||
{
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkCreateMirSurfaceKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceMirPresentationSupportKHR);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_XCB_KHR
|
||||
// VK_KHR_xcb_surface
|
||||
if (IsExtensionLoaded("VK_KHR_xcb_surface"))
|
||||
{
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkCreateXcbSurfaceKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceXcbPresentationSupportKHR);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_XLIB_KHR
|
||||
// VK_KHR_xlib_surface
|
||||
if (IsExtensionLoaded("VK_KHR_xlib_surface"))
|
||||
{
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkCreateXlibSurfaceKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceXlibPresentationSupportKHR);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
|
||||
// VK_KHR_wayland_surface
|
||||
if (IsExtensionLoaded("VK_KHR_wayland_surface"))
|
||||
{
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkCreateWaylandSurfaceKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceWaylandPresentationSupportKHR);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_WIN32_KHR
|
||||
// VK_KHR_win32_surface
|
||||
if (IsExtensionLoaded("VK_KHR_win32_surface"))
|
||||
{
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkCreateWin32SurfaceKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceWin32PresentationSupportKHR);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
NazaraError(String("Failed to query instance function: ") + e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
#undef NAZARA_VULKANRENDERER_LOAD_INSTANCE
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Instance::EnumeratePhysicalDevices(std::vector<VkPhysicalDevice>* devices)
|
||||
{
|
||||
NazaraAssert(devices, "Invalid device vector");
|
||||
|
||||
// First, query physical device count
|
||||
UInt32 deviceCount = 0; // Remember, Nz::UInt32 is a typedef on uint32_t
|
||||
m_lastErrorCode = vkEnumeratePhysicalDevices(m_instance, &deviceCount, nullptr);
|
||||
if (m_lastErrorCode != VkResult::VK_SUCCESS || deviceCount == 0)
|
||||
{
|
||||
NazaraError("Failed to query physical device count");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now we can get the list of the available physical device
|
||||
devices->resize(deviceCount);
|
||||
m_lastErrorCode = vkEnumeratePhysicalDevices(m_instance, &deviceCount, devices->data());
|
||||
if (m_lastErrorCode != VkResult::VK_SUCCESS)
|
||||
{
|
||||
NazaraError("Failed to query physical devices");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Instance::GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice device, std::vector<VkQueueFamilyProperties>* queueFamilyProperties)
|
||||
{
|
||||
NazaraAssert(queueFamilyProperties, "Invalid device vector");
|
||||
|
||||
// First, query physical device count
|
||||
UInt32 queueFamiliesCount = 0; // Remember, Nz::UInt32 is a typedef on uint32_t
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamiliesCount, nullptr);
|
||||
if (queueFamiliesCount == 0)
|
||||
{
|
||||
NazaraError("Failed to query physical device count");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now we can get the list of the available physical device
|
||||
queueFamilyProperties->resize(queueFamiliesCount);
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamiliesCount, queueFamilyProperties->data());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
117
src/Nazara/VulkanRenderer/VkLoader.cpp
Normal file
117
src/Nazara/VulkanRenderer/VkLoader.cpp
Normal file
@@ -0,0 +1,117 @@
|
||||
// Copyright (C) 2016 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/VkLoader.hpp>
|
||||
#include <Nazara/VulkanRenderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace Vk
|
||||
{
|
||||
bool Loader::EnumerateInstanceExtensionProperties(std::vector<VkExtensionProperties>* properties, const char* layerName)
|
||||
{
|
||||
NazaraAssert(properties, "Invalid device vector");
|
||||
|
||||
// First, query physical device count
|
||||
UInt32 propertyCount = 0; // Remember, Nz::UInt32 is a typedef on uint32_t
|
||||
s_lastErrorCode = vkEnumerateInstanceExtensionProperties(layerName, &propertyCount, properties->data());
|
||||
if (s_lastErrorCode != VkResult::VK_SUCCESS)
|
||||
{
|
||||
NazaraError("Failed to get instance extension properties count");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now we can get the list of the available physical device
|
||||
properties->resize(propertyCount);
|
||||
s_lastErrorCode = vkEnumerateInstanceExtensionProperties(layerName, &propertyCount, properties->data());
|
||||
if (s_lastErrorCode != VkResult::VK_SUCCESS)
|
||||
{
|
||||
NazaraError("Failed to enumerate instance extension properties");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Loader::EnumerateInstanceLayerProperties(std::vector<VkLayerProperties>* properties)
|
||||
{
|
||||
NazaraAssert(properties, "Invalid device vector");
|
||||
|
||||
// First, query physical device count
|
||||
UInt32 propertyCount = 0; // Remember, Nz::UInt32 is a typedef on uint32_t
|
||||
s_lastErrorCode = vkEnumerateInstanceLayerProperties(&propertyCount, properties->data());
|
||||
if (s_lastErrorCode != VkResult::VK_SUCCESS)
|
||||
{
|
||||
NazaraError("Failed to get instance layer properties count");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now we can get the list of the available physical device
|
||||
properties->resize(propertyCount);
|
||||
s_lastErrorCode = vkEnumerateInstanceLayerProperties(&propertyCount, properties->data());
|
||||
if (s_lastErrorCode != VkResult::VK_SUCCESS)
|
||||
{
|
||||
NazaraError("Failed to enumerate instance layer properties");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Loader::Initialize()
|
||||
{
|
||||
#ifdef NAZARA_PLATFORM_WINDOWS
|
||||
s_vulkanLib.Load("vulkan-1.dll");
|
||||
#elif defined(NAZARA_PLATFORM_LINUX)
|
||||
s_vulkanLib.Load("libvulkan.so");
|
||||
#else
|
||||
#error Unhandled platform
|
||||
#endif
|
||||
|
||||
if (!s_vulkanLib.IsLoaded())
|
||||
{
|
||||
NazaraError("Failed to open vulkan library: " + s_vulkanLib.GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
// vkGetInstanceProcAddr is the only function that's garantee to be exported
|
||||
vkGetInstanceProcAddr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(s_vulkanLib.GetSymbol("vkGetInstanceProcAddr"));
|
||||
if (!vkGetInstanceProcAddr)
|
||||
{
|
||||
NazaraError("Failed to get symbol \"vkGetInstanceProcAddr\": " + s_vulkanLib.GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
// all other functions should be loaded using vkGetInstanceProcAddr
|
||||
#define NAZARA_VULKANRENDERER_LOAD_GLOBAL(func) func = reinterpret_cast<PFN_##func>(vkGetInstanceProcAddr(nullptr, #func))
|
||||
|
||||
NAZARA_VULKANRENDERER_LOAD_GLOBAL(vkCreateInstance);
|
||||
NAZARA_VULKANRENDERER_LOAD_GLOBAL(vkEnumerateInstanceExtensionProperties);
|
||||
NAZARA_VULKANRENDERER_LOAD_GLOBAL(vkEnumerateInstanceLayerProperties);
|
||||
|
||||
#undef NAZARA_VULKANRENDERER_LOAD_GLOBAL
|
||||
|
||||
s_lastErrorCode = VkResult::VK_SUCCESS;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define NAZARA_VULKANRENDERER_GLOBAL_FUNCTION_IMPL(func) PFN_##func Loader::func = nullptr
|
||||
|
||||
NAZARA_VULKANRENDERER_GLOBAL_FUNCTION_IMPL(vkCreateInstance);
|
||||
NAZARA_VULKANRENDERER_GLOBAL_FUNCTION_IMPL(vkEnumerateInstanceExtensionProperties);
|
||||
NAZARA_VULKANRENDERER_GLOBAL_FUNCTION_IMPL(vkEnumerateInstanceLayerProperties);
|
||||
NAZARA_VULKANRENDERER_GLOBAL_FUNCTION_IMPL(vkGetInstanceProcAddr);
|
||||
|
||||
#undef NAZARA_VULKANRENDERER_GLOBAL_FUNCTION_IMPL
|
||||
|
||||
DynLib Loader::s_vulkanLib;
|
||||
VkResult Loader::s_lastErrorCode;
|
||||
|
||||
void Loader::Uninitialize()
|
||||
{
|
||||
s_vulkanLib.Unload();
|
||||
}
|
||||
}
|
||||
}
|
||||
451
src/Nazara/VulkanRenderer/Vulkan.cpp
Normal file
451
src/Nazara/VulkanRenderer/Vulkan.cpp
Normal file
@@ -0,0 +1,451 @@
|
||||
// Copyright (C) 2016 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/Vulkan.hpp>
|
||||
#include <Nazara/Core/CallOnExit.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/Core/Log.hpp>
|
||||
#include <Nazara/Utility/Utility.hpp>
|
||||
#include <Nazara/VulkanRenderer/Config.hpp>
|
||||
#include <array>
|
||||
#include <Nazara/VulkanRenderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
Vk::Instance& Vulkan::GetInstance()
|
||||
{
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
const std::vector<Vk::PhysicalDevice>& Vulkan::GetPhysicalDevices()
|
||||
{
|
||||
return s_physDevices;
|
||||
}
|
||||
|
||||
const Vk::PhysicalDevice& Vulkan::GetPhysicalDeviceInfo(VkPhysicalDevice physDevice)
|
||||
{
|
||||
for (const Vk::PhysicalDevice& info : s_physDevices)
|
||||
{
|
||||
if (info.device == physDevice)
|
||||
return info;
|
||||
}
|
||||
|
||||
// This cannot happen if physDevice is valid, as we retrieved every physical device
|
||||
NazaraInternalError("Invalid physical device: " + String::Pointer(physDevice));
|
||||
|
||||
static Vk::PhysicalDevice dummy;
|
||||
return dummy;
|
||||
}
|
||||
|
||||
bool Vulkan::Initialize()
|
||||
{
|
||||
if (s_moduleReferenceCounter > 0)
|
||||
{
|
||||
s_moduleReferenceCounter++;
|
||||
return true; // Already initialized
|
||||
}
|
||||
|
||||
// Initialize module dependencies
|
||||
if (!Utility::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize utility module");
|
||||
return false;
|
||||
}
|
||||
|
||||
s_moduleReferenceCounter++;
|
||||
|
||||
CallOnExit onExit(Vulkan::Uninitialize);
|
||||
|
||||
// Initialize module here
|
||||
if (!Vk::Loader::Initialize())
|
||||
{
|
||||
NazaraError("Failed to load Vulkan API, it may be not installed on your system");
|
||||
return false;
|
||||
}
|
||||
|
||||
String appName = "Another application made with Nazara Engine";
|
||||
String engineName = "Nazara Engine - Vulkan Renderer";
|
||||
UInt32 apiVersion = VK_MAKE_VERSION(1, 0, 8);
|
||||
UInt32 appVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||
UInt32 engineVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||
|
||||
s_initializationParameters.GetStringParameter("VkAppInfo_OverrideApplicationName", &appName);
|
||||
s_initializationParameters.GetStringParameter("VkAppInfo_OverrideEngineName", &engineName);
|
||||
|
||||
bool bParam;
|
||||
int iParam;
|
||||
|
||||
if (s_initializationParameters.GetIntegerParameter("VkAppInfo_OverrideAPIVersion", &iParam))
|
||||
apiVersion = iParam;
|
||||
|
||||
if (s_initializationParameters.GetIntegerParameter("VkAppInfo_OverrideApplicationVersion", &iParam))
|
||||
appVersion = iParam;
|
||||
|
||||
if (s_initializationParameters.GetIntegerParameter("VkAppInfo_OverrideEngineVersion", &iParam))
|
||||
engineVersion = iParam;
|
||||
|
||||
VkApplicationInfo appInfo = {
|
||||
VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
||||
nullptr,
|
||||
appName.GetConstBuffer(),
|
||||
appVersion,
|
||||
engineName.GetConstBuffer(),
|
||||
engineVersion,
|
||||
apiVersion
|
||||
};
|
||||
|
||||
VkInstanceCreateFlags createFlags = 0;
|
||||
|
||||
if (s_initializationParameters.GetIntegerParameter("VkInstanceInfo_OverrideCreateFlags", &iParam))
|
||||
createFlags = static_cast<VkInstanceCreateFlags>(iParam);
|
||||
|
||||
std::vector<const char*> enabledLayers;
|
||||
std::vector<const char*> enabledExtensions;
|
||||
|
||||
if (!s_initializationParameters.GetBooleanParameter("VkInstanceInfo_OverrideEnabledLayers", &bParam) || !bParam)
|
||||
{
|
||||
//< Nazara default layers goes here
|
||||
}
|
||||
|
||||
std::vector<String> additionalLayers; // Just to keep the String alive
|
||||
if (s_initializationParameters.GetIntegerParameter("VkInstanceInfo_EnabledLayerCount", &iParam))
|
||||
{
|
||||
additionalLayers.reserve(iParam);
|
||||
for (int i = 0; i < iParam; ++i)
|
||||
{
|
||||
Nz::String parameterName = "VkInstanceInfo_EnabledLayer" + String::Number(i);
|
||||
Nz::String layer;
|
||||
if (s_initializationParameters.GetStringParameter(parameterName, &layer))
|
||||
{
|
||||
additionalLayers.emplace_back(std::move(layer));
|
||||
enabledLayers.push_back(additionalLayers.back().GetConstBuffer());
|
||||
}
|
||||
else
|
||||
NazaraWarning("Parameter " + parameterName + " expected");
|
||||
}
|
||||
}
|
||||
|
||||
if (!s_initializationParameters.GetBooleanParameter("VkInstanceInfo_OverrideEnabledExtensions", &bParam) || !bParam)
|
||||
{
|
||||
enabledExtensions.push_back("VK_KHR_surface");
|
||||
|
||||
#ifdef VK_USE_PLATFORM_ANDROID_KHR
|
||||
enabledExtensions.push_back("VK_KHR_android_surface");
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_MIR_KHR
|
||||
enabledExtensions.push_back("VK_KHR_mir_surface");
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_XCB_KHR
|
||||
enabledExtensions.push_back("VK_KHR_xcb_surface");
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_XLIB_KHR
|
||||
enabledExtensions.push_back("VK_KHR_xlib_surface");
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
|
||||
enabledExtensions.push_back("VK_KHR_wayland_surface");
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_WIN32_KHR
|
||||
enabledExtensions.push_back("VK_KHR_win32_surface");
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<String> additionalExtensions; // Just to keep the String alive
|
||||
if (s_initializationParameters.GetIntegerParameter("VkInstanceInfo_EnabledExtensionCount", &iParam))
|
||||
{
|
||||
additionalExtensions.reserve(iParam);
|
||||
for (int i = 0; i < iParam; ++i)
|
||||
{
|
||||
Nz::String parameterName = "VkInstanceInfo_EnabledExtension" + String::Number(i);
|
||||
Nz::String extension;
|
||||
if (s_initializationParameters.GetStringParameter(parameterName, &extension))
|
||||
{
|
||||
additionalExtensions.emplace_back(std::move(extension));
|
||||
enabledExtensions.push_back(additionalExtensions.back().GetConstBuffer());
|
||||
}
|
||||
else
|
||||
NazaraWarning("Parameter " + parameterName + " expected");
|
||||
}
|
||||
}
|
||||
|
||||
VkInstanceCreateInfo instanceInfo = {
|
||||
VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
||||
nullptr,
|
||||
createFlags,
|
||||
&appInfo,
|
||||
UInt32(enabledLayers.size()),
|
||||
enabledLayers.data(),
|
||||
UInt32(enabledExtensions.size()),
|
||||
enabledExtensions.data()
|
||||
};
|
||||
|
||||
if (!s_instance.Create(instanceInfo))
|
||||
{
|
||||
NazaraError("Failed to create instance");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<VkPhysicalDevice> physDevices;
|
||||
if (!s_instance.EnumeratePhysicalDevices(&physDevices))
|
||||
{
|
||||
NazaraError("Failed to enumerate physical devices");
|
||||
return false;
|
||||
}
|
||||
|
||||
s_physDevices.reserve(physDevices.size());
|
||||
|
||||
for (std::size_t i = 0; i < physDevices.size(); ++i)
|
||||
{
|
||||
VkPhysicalDevice physDevice = physDevices[i];
|
||||
|
||||
Vk::PhysicalDevice deviceInfo;
|
||||
if (!s_instance.GetPhysicalDeviceQueueFamilyProperties(physDevice, &deviceInfo.queues))
|
||||
{
|
||||
NazaraWarning("Failed to query physical device queue family properties");
|
||||
continue;
|
||||
}
|
||||
|
||||
deviceInfo.device = physDevice;
|
||||
|
||||
deviceInfo.features = s_instance.GetPhysicalDeviceFeatures(physDevice);
|
||||
deviceInfo.memoryProperties = s_instance.GetPhysicalDeviceMemoryProperties(physDevice);
|
||||
deviceInfo.properties = s_instance.GetPhysicalDeviceProperties(physDevice);
|
||||
|
||||
s_physDevices.emplace_back(std::move(deviceInfo));
|
||||
}
|
||||
|
||||
if (s_physDevices.empty())
|
||||
{
|
||||
NazaraError("No valid physical device found");
|
||||
return false;
|
||||
}
|
||||
|
||||
onExit.Reset();
|
||||
|
||||
NazaraNotice("Initialized: Vulkan module");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Vulkan::IsInitialized()
|
||||
{
|
||||
return s_moduleReferenceCounter != 0;
|
||||
}
|
||||
|
||||
Vk::DeviceHandle Vulkan::CreateDevice(VkPhysicalDevice gpu, const Vk::Surface& surface, UInt32* presentableFamilyQueue)
|
||||
{
|
||||
Nz::ErrorFlags errFlags(ErrorFlag_ThrowException, true);
|
||||
|
||||
std::vector<VkQueueFamilyProperties> queueFamilies;
|
||||
s_instance.GetPhysicalDeviceQueueFamilyProperties(gpu, &queueFamilies);
|
||||
|
||||
// Find a queue that supports graphics operations
|
||||
UInt32 graphicsQueueNodeIndex = UINT32_MAX;
|
||||
UInt32 presentQueueNodeIndex = UINT32_MAX;
|
||||
UInt32 transfertQueueNodeFamily = UINT32_MAX;
|
||||
for (UInt32 i = 0; i < queueFamilies.size(); i++)
|
||||
{
|
||||
bool supportPresentation = false;
|
||||
if (!surface.GetSupportPresentation(gpu, i, &supportPresentation))
|
||||
NazaraWarning("Failed to get presentation support of queue family #" + String::Number(i));
|
||||
|
||||
if (queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
|
||||
{
|
||||
if (graphicsQueueNodeIndex == UINT32_MAX)
|
||||
graphicsQueueNodeIndex = i;
|
||||
|
||||
if (supportPresentation)
|
||||
{
|
||||
graphicsQueueNodeIndex = i;
|
||||
presentQueueNodeIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (supportPresentation)
|
||||
presentQueueNodeIndex = i;
|
||||
}
|
||||
|
||||
for (UInt32 i = 0; i < queueFamilies.size(); i++)
|
||||
{
|
||||
if (queueFamilies[i].queueFlags & VK_QUEUE_TRANSFER_BIT)
|
||||
{
|
||||
transfertQueueNodeFamily = i;
|
||||
if (transfertQueueNodeFamily != graphicsQueueNodeIndex)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::array<UInt32, 3> usedQueueFamilies = {graphicsQueueNodeIndex, presentQueueNodeIndex, transfertQueueNodeFamily};
|
||||
std::array<float, 3> priorities = {1.f, 1.f, 1.f};
|
||||
|
||||
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
|
||||
for (UInt32 queueFamily : usedQueueFamilies)
|
||||
{
|
||||
auto it = std::find_if(queueCreateInfos.begin(), queueCreateInfos.end(), [queueFamily] (const VkDeviceQueueCreateInfo& createInfo)
|
||||
{
|
||||
return createInfo.queueFamilyIndex == queueFamily;
|
||||
});
|
||||
|
||||
if (it == queueCreateInfos.end())
|
||||
{
|
||||
VkDeviceQueueCreateInfo createInfo = {
|
||||
VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // VkStructureType sType;
|
||||
nullptr, // const void* pNext;
|
||||
0, // VkDeviceQueueCreateFlags flags;
|
||||
queueFamily, // uint32_t queueFamilyIndex;
|
||||
1, // uint32_t queueCount;
|
||||
priorities.data() // const float* pQueuePriorities;
|
||||
};
|
||||
|
||||
queueCreateInfos.emplace_back(createInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::vector<const char*> enabledLayers;
|
||||
std::vector<const char*> enabledExtensions;
|
||||
|
||||
bool bParam;
|
||||
int iParam;
|
||||
|
||||
if (!s_initializationParameters.GetBooleanParameter("VkDeviceInfo_OverrideEnabledLayers", &bParam) || !bParam)
|
||||
{
|
||||
//< Nazara default layers goes here
|
||||
}
|
||||
|
||||
std::vector<String> additionalLayers; // Just to keep the String alive
|
||||
if (s_initializationParameters.GetIntegerParameter("VkDeviceInfo_EnabledLayerCount", &iParam))
|
||||
{
|
||||
additionalLayers.reserve(iParam);
|
||||
for (int i = 0; i < iParam; ++i)
|
||||
{
|
||||
Nz::String parameterName = "VkDeviceInfo_EnabledLayer" + String::Number(i);
|
||||
Nz::String layer;
|
||||
if (s_initializationParameters.GetStringParameter(parameterName, &layer))
|
||||
{
|
||||
additionalLayers.emplace_back(std::move(layer));
|
||||
enabledLayers.push_back(additionalLayers.back().GetConstBuffer());
|
||||
}
|
||||
else
|
||||
NazaraWarning("Parameter " + parameterName + " expected");
|
||||
}
|
||||
}
|
||||
|
||||
if (!s_initializationParameters.GetBooleanParameter("VkDeviceInfo_OverrideEnabledExtensions", &bParam) || !bParam)
|
||||
enabledExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||
|
||||
std::vector<String> additionalExtensions; // Just to keep the String alive
|
||||
if (s_initializationParameters.GetIntegerParameter("VkDeviceInfo_EnabledExtensionCount", &iParam))
|
||||
{
|
||||
for (int i = 0; i < iParam; ++i)
|
||||
{
|
||||
Nz::String parameterName = "VkDeviceInfo_EnabledExtension" + String::Number(i);
|
||||
Nz::String extension;
|
||||
if (s_initializationParameters.GetStringParameter(parameterName, &extension))
|
||||
{
|
||||
additionalExtensions.emplace_back(std::move(extension));
|
||||
enabledExtensions.push_back(additionalExtensions.back().GetConstBuffer());
|
||||
}
|
||||
else
|
||||
NazaraWarning("Parameter " + parameterName + " expected");
|
||||
}
|
||||
}
|
||||
|
||||
VkDeviceCreateInfo createInfo = {
|
||||
VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||
nullptr,
|
||||
0,
|
||||
UInt32(queueCreateInfos.size()),
|
||||
queueCreateInfos.data(),
|
||||
UInt32(enabledLayers.size()),
|
||||
enabledLayers.data(),
|
||||
UInt32(enabledExtensions.size()),
|
||||
enabledExtensions.data(),
|
||||
nullptr
|
||||
};
|
||||
|
||||
///TODO: First create then move
|
||||
s_devices.emplace_back(s_instance);
|
||||
|
||||
Vk::Device& device = s_devices.back();
|
||||
device.Create(gpu, createInfo);
|
||||
|
||||
*presentableFamilyQueue = presentQueueNodeIndex;
|
||||
|
||||
return device.CreateHandle();
|
||||
}
|
||||
|
||||
Vk::DeviceHandle Vulkan::SelectDevice(VkPhysicalDevice gpu, const Vk::Surface& surface, UInt32* presentableFamilyQueue)
|
||||
{
|
||||
// First, try to find a device compatible with that surface
|
||||
for (Vk::Device& device : s_devices)
|
||||
{
|
||||
if (device.GetPhysicalDevice() == gpu)
|
||||
{
|
||||
const std::vector<Vk::Device::QueueFamilyInfo>& queueFamilyInfo = device.GetEnabledQueues();
|
||||
UInt32 presentableQueueFamilyIndex = UINT32_MAX;
|
||||
for (Vk::Device::QueueFamilyInfo queueInfo : queueFamilyInfo)
|
||||
{
|
||||
bool supported = false;
|
||||
if (surface.GetSupportPresentation(gpu, queueInfo.familyIndex, &supported) && supported)
|
||||
{
|
||||
if (presentableQueueFamilyIndex == UINT32_MAX || queueInfo.flags & VK_QUEUE_GRAPHICS_BIT)
|
||||
{
|
||||
presentableQueueFamilyIndex = queueInfo.familyIndex;
|
||||
if (queueInfo.flags & VK_QUEUE_GRAPHICS_BIT)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (presentableQueueFamilyIndex != UINT32_MAX)
|
||||
*presentableFamilyQueue = presentableQueueFamilyIndex;
|
||||
}
|
||||
}
|
||||
|
||||
// No device had support for that surface, create one
|
||||
return CreateDevice(gpu, surface, presentableFamilyQueue);
|
||||
}
|
||||
|
||||
void Vulkan::SetParameters(const ParameterList& parameters)
|
||||
{
|
||||
s_initializationParameters = parameters;
|
||||
}
|
||||
|
||||
void Vulkan::Uninitialize()
|
||||
{
|
||||
if (s_moduleReferenceCounter != 1)
|
||||
{
|
||||
// Either the module is not initialized, either it was initialized multiple times
|
||||
if (s_moduleReferenceCounter > 1)
|
||||
s_moduleReferenceCounter--;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
s_moduleReferenceCounter = 0;
|
||||
|
||||
// Uninitialize module here
|
||||
s_devices.clear();
|
||||
s_instance.Destroy();
|
||||
|
||||
Vk::Loader::Uninitialize();
|
||||
|
||||
NazaraNotice("Uninitialized: Vulkan module");
|
||||
|
||||
// Free module dependencies
|
||||
Utility::Uninitialize();
|
||||
}
|
||||
|
||||
std::list<Vk::Device> Vulkan::s_devices;
|
||||
std::vector<Vk::PhysicalDevice> Vulkan::s_physDevices;
|
||||
Vk::Instance Vulkan::s_instance;
|
||||
ParameterList Vulkan::s_initializationParameters;
|
||||
unsigned int Vulkan::s_moduleReferenceCounter = 0;
|
||||
}
|
||||
|
||||
252
src/Nazara/VulkanRenderer/VulkanRenderer.cpp
Normal file
252
src/Nazara/VulkanRenderer/VulkanRenderer.cpp
Normal file
@@ -0,0 +1,252 @@
|
||||
// Copyright (C) 2016 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/VulkanRenderer.hpp>
|
||||
#include <Nazara/VulkanRenderer/VkLoader.hpp>
|
||||
#include <Nazara/VulkanRenderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
bool VulkanRenderer::IsBetterThan(const RendererImpl* other) const
|
||||
{
|
||||
if (other->QueryAPI() == RenderAPI_Vulkan && QueryAPIVersion() < other->QueryAPIVersion())
|
||||
return false;
|
||||
|
||||
return true; //< Vulkan FTW
|
||||
}
|
||||
|
||||
bool VulkanRenderer::Prepare(const ParameterList& parameters)
|
||||
{
|
||||
if (!Vk::Loader::Initialize())
|
||||
{
|
||||
NazaraError("Failed to load Vulkan API, it may be not installed on your system");
|
||||
return false;
|
||||
}
|
||||
|
||||
String appName = "Another application made with Nazara Engine";
|
||||
String engineName = "Nazara Engine - Vulkan Renderer";
|
||||
|
||||
UInt32 apiVersion = APIVersion;
|
||||
UInt32 appVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||
UInt32 engineVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||
|
||||
parameters.GetStringParameter("VkAppInfo_OverrideApplicationName", &appName);
|
||||
parameters.GetStringParameter("VkAppInfo_OverrideEngineName", &engineName);
|
||||
|
||||
bool bParam;
|
||||
int iParam;
|
||||
|
||||
if (parameters.GetIntegerParameter("VkAppInfo_OverrideAPIVersion", &iParam))
|
||||
apiVersion = iParam;
|
||||
|
||||
if (parameters.GetIntegerParameter("VkAppInfo_OverrideApplicationVersion", &iParam))
|
||||
appVersion = iParam;
|
||||
|
||||
if (parameters.GetIntegerParameter("VkAppInfo_OverrideEngineVersion", &iParam))
|
||||
engineVersion = iParam;
|
||||
|
||||
VkApplicationInfo appInfo = {
|
||||
VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
||||
nullptr,
|
||||
appName.GetConstBuffer(),
|
||||
appVersion,
|
||||
engineName.GetConstBuffer(),
|
||||
engineVersion,
|
||||
apiVersion
|
||||
};
|
||||
|
||||
VkInstanceCreateFlags createFlags = 0;
|
||||
|
||||
if (parameters.GetIntegerParameter("VkInstanceInfo_OverrideCreateFlags", &iParam))
|
||||
createFlags = static_cast<VkInstanceCreateFlags>(iParam);
|
||||
|
||||
std::vector<const char*> enabledLayers;
|
||||
std::vector<const char*> enabledExtensions;
|
||||
|
||||
if (!parameters.GetBooleanParameter("VkInstanceInfo_OverrideEnabledLayers", &bParam) || !bParam)
|
||||
{
|
||||
//< Nazara default layers goes here
|
||||
}
|
||||
|
||||
std::vector<String> additionalLayers; // Just to keep the String alive
|
||||
if (parameters.GetIntegerParameter("VkInstanceInfo_EnabledLayerCount", &iParam))
|
||||
{
|
||||
additionalLayers.reserve(iParam);
|
||||
for (int i = 0; i < iParam; ++i)
|
||||
{
|
||||
Nz::String parameterName = "VkInstanceInfo_EnabledLayer" + String::Number(i);
|
||||
Nz::String layer;
|
||||
if (parameters.GetStringParameter(parameterName, &layer))
|
||||
{
|
||||
additionalLayers.emplace_back(std::move(layer));
|
||||
enabledLayers.push_back(additionalLayers.back().GetConstBuffer());
|
||||
}
|
||||
else
|
||||
NazaraWarning("Parameter " + parameterName + " expected");
|
||||
}
|
||||
}
|
||||
|
||||
if (!parameters.GetBooleanParameter("VkInstanceInfo_OverrideEnabledExtensions", &bParam) || !bParam)
|
||||
{
|
||||
enabledExtensions.push_back("VK_KHR_surface");
|
||||
|
||||
#ifdef VK_USE_PLATFORM_ANDROID_KHR
|
||||
enabledExtensions.push_back("VK_KHR_android_surface");
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_MIR_KHR
|
||||
enabledExtensions.push_back("VK_KHR_mir_surface");
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_XCB_KHR
|
||||
enabledExtensions.push_back("VK_KHR_xcb_surface");
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_XLIB_KHR
|
||||
enabledExtensions.push_back("VK_KHR_xlib_surface");
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
|
||||
enabledExtensions.push_back("VK_KHR_wayland_surface");
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_WIN32_KHR
|
||||
enabledExtensions.push_back("VK_KHR_win32_surface");
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<String> additionalExtensions; // Just to keep the String alive
|
||||
if (parameters.GetIntegerParameter("VkInstanceInfo_EnabledExtensionCount", &iParam))
|
||||
{
|
||||
additionalExtensions.reserve(iParam);
|
||||
for (int i = 0; i < iParam; ++i)
|
||||
{
|
||||
Nz::String parameterName = "VkInstanceInfo_EnabledExtension" + String::Number(i);
|
||||
Nz::String extension;
|
||||
if (parameters.GetStringParameter(parameterName, &extension))
|
||||
{
|
||||
additionalExtensions.emplace_back(std::move(extension));
|
||||
enabledExtensions.push_back(additionalExtensions.back().GetConstBuffer());
|
||||
}
|
||||
else
|
||||
NazaraWarning("Parameter " + parameterName + " expected");
|
||||
}
|
||||
}
|
||||
|
||||
VkInstanceCreateInfo instanceInfo =
|
||||
{
|
||||
VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, // VkStructureType sType;
|
||||
nullptr, // const void* pNext;
|
||||
createFlags, // VkInstanceCreateFlags flags;
|
||||
&appInfo, // const VkApplicationInfo* pApplicationInfo;
|
||||
UInt32(enabledLayers.size()), // uint32_t enabledLayerCount;
|
||||
enabledLayers.data(), // const char* const* ppEnabledLayerNames;
|
||||
UInt32(enabledExtensions.size()), // uint32_t enabledExtensionCount;
|
||||
enabledExtensions.data() // const char* const* ppEnabledExtensionNames;
|
||||
};
|
||||
|
||||
if (!m_instance.Create(instanceInfo))
|
||||
{
|
||||
NazaraError("Failed to create instance");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_apiVersion = apiVersion;
|
||||
|
||||
std::vector<VkPhysicalDevice> physDevices;
|
||||
if (!m_instance.EnumeratePhysicalDevices(&physDevices))
|
||||
{
|
||||
NazaraError("Failed to enumerate physical devices");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_physDevices.reserve(physDevices.size());
|
||||
for (std::size_t i = 0; i < physDevices.size(); ++i)
|
||||
{
|
||||
VkPhysicalDevice physDevice = physDevices[i];
|
||||
|
||||
Vk::PhysicalDevice deviceInfo;
|
||||
if (!m_instance.GetPhysicalDeviceQueueFamilyProperties(physDevice, &deviceInfo.queues))
|
||||
{
|
||||
NazaraWarning("Failed to query physical device queue family properties for " + String(deviceInfo.properties.deviceName) + " (0x" + String::Number(deviceInfo.properties.deviceID, 16) + ')');
|
||||
continue;
|
||||
}
|
||||
|
||||
deviceInfo.device = physDevice;
|
||||
|
||||
deviceInfo.features = m_instance.GetPhysicalDeviceFeatures(physDevice);
|
||||
deviceInfo.memoryProperties = m_instance.GetPhysicalDeviceMemoryProperties(physDevice);
|
||||
deviceInfo.properties = m_instance.GetPhysicalDeviceProperties(physDevice);
|
||||
|
||||
m_physDevices.emplace_back(std::move(deviceInfo));
|
||||
}
|
||||
|
||||
if (m_physDevices.empty())
|
||||
{
|
||||
NazaraError("No valid physical device found");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
RenderAPI VulkanRenderer::QueryAPI() const
|
||||
{
|
||||
return RenderAPI_Vulkan;
|
||||
}
|
||||
|
||||
String VulkanRenderer::QueryAPIString() const
|
||||
{
|
||||
StringStream ss;
|
||||
ss << "Vulkan renderer " << VK_VERSION_MAJOR(m_apiVersion) << '.' << VK_VERSION_MINOR(m_apiVersion) << '.' << VK_VERSION_PATCH(m_apiVersion);
|
||||
|
||||
return ss;
|
||||
}
|
||||
|
||||
UInt32 VulkanRenderer::QueryAPIVersion() const
|
||||
{
|
||||
return m_apiVersion;
|
||||
}
|
||||
|
||||
std::vector<RenderDevice> VulkanRenderer::QueryRenderDevices() const
|
||||
{
|
||||
std::vector<RenderDevice> devices;
|
||||
devices.reserve(m_physDevices.size());
|
||||
|
||||
for (const Vk::PhysicalDevice& physDevice : m_physDevices)
|
||||
{
|
||||
RenderDevice device;
|
||||
device.name = physDevice.properties.deviceName;
|
||||
|
||||
switch (physDevice.properties.deviceType)
|
||||
{
|
||||
case VK_PHYSICAL_DEVICE_TYPE_CPU:
|
||||
device.type = RenderDeviceType_Software;
|
||||
break;
|
||||
|
||||
case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
|
||||
device.type = RenderDeviceType_Dedicated;
|
||||
break;
|
||||
|
||||
case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
|
||||
device.type = RenderDeviceType_Integrated;
|
||||
break;
|
||||
|
||||
case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
|
||||
device.type = RenderDeviceType_Virtual;
|
||||
break;
|
||||
|
||||
default:
|
||||
NazaraWarning("Device " + device.name + " has handled device type (0x" + String::Number(physDevice.properties.deviceType, 16) + ')');
|
||||
case VK_PHYSICAL_DEVICE_TYPE_OTHER:
|
||||
device.type = RenderDeviceType_Unknown;
|
||||
break;
|
||||
}
|
||||
|
||||
devices.emplace_back(device);
|
||||
}
|
||||
|
||||
return devices;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user