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:
Lynix
2016-08-23 12:52:34 +02:00
parent d7a10031d7
commit bdedd05032
132 changed files with 6300 additions and 12587 deletions

View 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

View 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();
}
}

View 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);
}
}

View 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;
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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();
}
}
}

View 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;
}

View 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;
}
}