diff --git a/include/Nazara/Vulkan/RenderWindow.hpp b/include/Nazara/Vulkan/RenderWindow.hpp index 1651f1b9e..59705cc7b 100644 --- a/include/Nazara/Vulkan/RenderWindow.hpp +++ b/include/Nazara/Vulkan/RenderWindow.hpp @@ -16,7 +16,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -39,13 +41,11 @@ namespace Nz void BuildPreRenderCommands(UInt32 imageIndex, Vk::CommandBuffer& commandBuffer) override; void BuildPostRenderCommands(UInt32 imageIndex, Vk::CommandBuffer& commandBuffer) override; - const Vk::Framebuffer& GetFrameBuffer(UInt32 imageIndex) const override; - - UInt32 GetFramebufferCount() const; - bool Create(VideoMode mode, const String& title, UInt32 style = WindowStyle_Default); bool Create(WindowHandle handle); + const Vk::Framebuffer& GetFrameBuffer(UInt32 imageIndex) const override; + UInt32 GetFramebufferCount() const; const Vk::DeviceHandle& GetDevice() const; UInt32 GetPresentableFamilyQueue() const; const Vk::Surface& GetSurface() const; @@ -55,6 +55,7 @@ namespace Nz bool IsValid() const; + void SetDepthStencilFormats(std::vector pixelFormat); void SetPhysicalDevice(VkPhysicalDevice device); RenderWindow& operator=(const RenderWindow&) = delete; @@ -65,17 +66,21 @@ namespace Nz void OnWindowDestroy() override; void OnWindowResized() override; - bool SetupCommandBuffers(); + bool SetupDepthBuffer(); bool SetupRenderPass(); bool SetupSwapchain(); Clock m_clock; - VkFormat m_colorFormat; - VkFormat m_depthFormat; VkColorSpaceKHR m_colorSpace; + VkFormat m_colorFormat; + VkFormat m_depthStencilFormat; VkPhysicalDevice m_forcedPhysicalDevice; + std::vector m_wantedDepthStencilFormats; std::vector m_frameBuffers; Vk::DeviceHandle m_device; + Vk::DeviceMemory m_depthBufferMemory; + Vk::Image m_depthBuffer; + Vk::ImageView m_depthBufferView; Vk::Queue m_presentQueue; Vk::Surface m_surface; Vk::Swapchain m_swapchain; diff --git a/include/Nazara/Vulkan/VkImage.hpp b/include/Nazara/Vulkan/VkImage.hpp new file mode 100644 index 000000000..0eea6e5d9 --- /dev/null +++ b/include/Nazara/Vulkan/VkImage.hpp @@ -0,0 +1,43 @@ +// Copyright (C) 2016 Jérôme Leclercq +// This file is part of the "Nazara Engine - Vulkan" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_VULKAN_VKIMAGE_HPP +#define NAZARA_VULKAN_VKIMAGE_HPP + +#include +#include + +namespace Nz +{ + namespace Vk + { + class Image : public DeviceObject + { + friend DeviceObject; + + public: + Image() = default; + Image(const Image&) = delete; + Image(Image&&) = default; + ~Image() = default; + + bool BindImageMemory(VkDeviceMemory memory, VkDeviceSize offset = 0); + + VkMemoryRequirements GetMemoryRequirements() const; + + Image& operator=(const Image&) = delete; + Image& operator=(Image&&) = delete; + + private: + static inline VkResult CreateHelper(const DeviceHandle& device, const VkImageCreateInfo* createInfo, const VkAllocationCallbacks* allocator, VkImage* handle); + static inline void DestroyHelper(const DeviceHandle& device, VkImage handle, const VkAllocationCallbacks* allocator); + }; + } +} + +#include + +#endif // NAZARA_VULKAN_VKIMAGE_HPP diff --git a/include/Nazara/Vulkan/VkImage.inl b/include/Nazara/Vulkan/VkImage.inl new file mode 100644 index 000000000..7e04a534f --- /dev/null +++ b/include/Nazara/Vulkan/VkImage.inl @@ -0,0 +1,46 @@ +// Copyright (C) 2016 Jérôme Leclercq +// This file is part of the "Nazara Engine - Vulkan" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + namespace Vk + { + inline bool Image::BindImageMemory(VkDeviceMemory memory, VkDeviceSize offset) + { + m_lastErrorCode = m_device->vkBindImageMemory(*m_device, m_handle, memory, offset); + if (m_lastErrorCode != VK_SUCCESS) + { + NazaraError("Failed to bind buffer memory"); + return false; + } + + return true; + } + + inline VkMemoryRequirements Image::GetMemoryRequirements() const + { + NazaraAssert(IsValid(), "Invalid image"); + + VkMemoryRequirements memoryRequirements; + m_device->vkGetImageMemoryRequirements(*m_device, m_handle, &memoryRequirements); + + return memoryRequirements; + } + + inline VkResult Image::CreateHelper(const DeviceHandle& device, const VkImageCreateInfo* createInfo, const VkAllocationCallbacks* allocator, VkImage* handle) + { + return device->vkCreateImage(*device, createInfo, allocator, handle); + } + + inline void Image::DestroyHelper(const DeviceHandle& device, VkImage handle, const VkAllocationCallbacks* allocator) + { + return device->vkDestroyImage(*device, handle, allocator); + } + } +} + +#include diff --git a/src/Nazara/Vulkan/RenderWindow.cpp b/src/Nazara/Vulkan/RenderWindow.cpp index f9b01672e..ae0833d44 100644 --- a/src/Nazara/Vulkan/RenderWindow.cpp +++ b/src/Nazara/Vulkan/RenderWindow.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -15,7 +16,8 @@ namespace Nz RenderWindow::RenderWindow() : RenderTarget(), Window(), m_surface(Nz::Vulkan::GetInstance()), - m_forcedPhysicalDevice(nullptr) + m_forcedPhysicalDevice(nullptr), + m_depthStencilFormat(VK_FORMAT_MAX_ENUM) { } @@ -53,6 +55,20 @@ namespace Nz 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_depthBufferView != 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) @@ -112,6 +128,11 @@ namespace Nz return m_impl != nullptr; } + void RenderWindow::SetDepthStencilFormats(std::vector pixelFormat) + { + m_wantedDepthStencilFormats = std::move(pixelFormat); + } + void RenderWindow::SetPhysicalDevice(VkPhysicalDevice device) { m_forcedPhysicalDevice = device; @@ -158,7 +179,58 @@ namespace Nz m_colorSpace = surfaceFormats[0].colorSpace; - m_depthFormat = VK_FORMAT_MAX_ENUM; + 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()) { @@ -166,6 +238,12 @@ namespace Nz 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"); @@ -178,7 +256,7 @@ namespace Nz m_frameBuffers.resize(imageCount); for (UInt32 i = 0; i < imageCount; ++i) { - std::array attachments = {m_swapchain.GetBuffer(i).view, VK_NULL_HANDLE}; + std::array attachments = {m_swapchain.GetBuffer(i).view, m_depthBufferView}; VkFramebufferCreateInfo frameBufferCreate = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType; @@ -221,9 +299,74 @@ namespace Nz OnRenderTargetSizeChange(this); } - bool RenderWindow::SetupCommandBuffers() + bool RenderWindow::SetupDepthBuffer() { - return false; + 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() @@ -242,15 +385,15 @@ namespace Nz VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout; }, { - 0, // VkAttachmentDescriptionFlags flags; - m_depthFormat, // 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_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout; - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // 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; }, } }; @@ -266,28 +409,28 @@ namespace Nz }; 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_depthFormat != VK_FORMAT_MAX_ENUM) ? &depthReference : nullptr, // const VkAttachmentReference* pDepthStencilAttachment; - 0U, // uint32_t preserveAttachmentCount; - nullptr // const uint32_t* pPreserveAttachments; + 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; }; VkRenderPassCreateInfo createInfo = { - VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType; - nullptr, // const void* pNext; - 0, // VkRenderPassCreateFlags flags; - (m_depthFormat != VK_FORMAT_MAX_ENUM) ? 2U : 1U, // uint32_t attachmentCount; - attachments.data(), // const VkAttachmentDescription* pAttachments; - 1U, // uint32_t subpassCount; - &subpass, // const VkSubpassDescription* pSubpasses; - 0U, // uint32_t dependencyCount; - nullptr // const VkSubpassDependency* pDependencies; + 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; + 0U, // uint32_t dependencyCount; + nullptr // const VkSubpassDependency* pDependencies; }; return m_renderPass.Create(m_device, createInfo);