diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 2370ea5..1a02591 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -21,6 +21,13 @@
+
+
+
+
+
+
+
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
index 79ee123..7baa83b 100644
--- a/.idea/codeStyles/codeStyleConfig.xml
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -1,5 +1,5 @@
-
+
\ No newline at end of file
diff --git a/.idea/discord.xml b/.idea/discord.xml
index d8e9561..3aef922 100644
--- a/.idea/discord.xml
+++ b/.idea/discord.xml
@@ -3,5 +3,10 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/editor.xml b/.idea/editor.xml
index 3d8fb9d..55267e1 100644
--- a/.idea/editor.xml
+++ b/.idea/editor.xml
@@ -20,6 +20,12 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/engine/AttachmentInfo.h b/src/engine/AttachmentInfo.h
new file mode 100644
index 0000000..2bb17c1
--- /dev/null
+++ b/src/engine/AttachmentInfo.h
@@ -0,0 +1,25 @@
+#pragma once
+
+namespace Vixen {
+ enum class LoadAction;
+
+ enum class StoreAction;
+
+ struct AttachmentInfo {
+ LoadAction loadAction;
+
+ StoreAction storeAction;
+
+ VkImageLayout layout;
+
+ VkImageView loadStoreTarget;
+
+ VkImageView resolveTarget;
+
+ glm::vec4 clearColor;
+
+ float clearDepth;
+
+ uint32_t clearStencil;
+ };
+}
diff --git a/src/engine/CMakeLists.txt b/src/engine/CMakeLists.txt
index 790a024..ce91814 100644
--- a/src/engine/CMakeLists.txt
+++ b/src/engine/CMakeLists.txt
@@ -16,6 +16,10 @@ set(
IndexFormat.h
PrimitiveTopology.h
VertexAttribute.h
+ AttachmentInfo.h
+ LoadAction.h
+ StoreAction.h
+ Rectangle.h
)
add_library(Vixen STATIC ${SOURCES})
diff --git a/src/engine/LoadAction.h b/src/engine/LoadAction.h
new file mode 100644
index 0000000..2525e0d
--- /dev/null
+++ b/src/engine/LoadAction.h
@@ -0,0 +1,9 @@
+#pragma once
+
+namespace Vixen {
+ enum class LoadAction {
+ Load,
+ Clear,
+ DontCare
+ };
+}
diff --git a/src/engine/Rectangle.h b/src/engine/Rectangle.h
new file mode 100644
index 0000000..ad80594
--- /dev/null
+++ b/src/engine/Rectangle.h
@@ -0,0 +1,13 @@
+#pragma once
+
+namespace Vixen {
+ struct Rectangle {
+ float x;
+
+ float y;
+
+ float width;
+
+ float height;
+ };
+}
diff --git a/src/engine/StoreAction.h b/src/engine/StoreAction.h
new file mode 100644
index 0000000..c1e2c77
--- /dev/null
+++ b/src/engine/StoreAction.h
@@ -0,0 +1,10 @@
+#pragma once
+
+namespace Vixen {
+ enum class StoreAction {
+ Store,
+ Resolve,
+ StoreAndResolve,
+ DontCare
+ };
+}
diff --git a/src/engine/vk/CMakeLists.txt b/src/engine/vk/CMakeLists.txt
index 54c83f2..b4d21c1 100644
--- a/src/engine/vk/CMakeLists.txt
+++ b/src/engine/vk/CMakeLists.txt
@@ -37,16 +37,12 @@ add_library(
VkRenderer.h
VkPipelineLayout.cpp
VkPipelineLayout.h
- VkRenderPass.cpp
- VkRenderPass.h
VkCommandBuffer.cpp
VkCommandBuffer.h
VkCommandPool.cpp
VkCommandPool.h
VkFence.cpp
VkFence.h
- VkFramebuffer.cpp
- VkFramebuffer.h
VkImage.cpp
VkImage.h
VkImageView.cpp
diff --git a/src/engine/vk/Device.cpp b/src/engine/vk/Device.cpp
index a1b7090..27d64cc 100644
--- a/src/engine/vk/Device.cpp
+++ b/src/engine/vk/Device.cpp
@@ -39,13 +39,24 @@ namespace Vixen::Vk {
VkPhysicalDeviceFeatures deviceFeatures{};
- VkDeviceCreateInfo deviceInfo{};
- deviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
- deviceInfo.queueCreateInfoCount = queueInfos.size();
- deviceInfo.pQueueCreateInfos = queueInfos.data();
- deviceInfo.pEnabledFeatures = &deviceFeatures;
- deviceInfo.enabledExtensionCount = extensions.size();
- deviceInfo.ppEnabledExtensionNames = extensions.data();
+ VkPhysicalDeviceDynamicRenderingFeatures dynamicRenderingFeatures{
+ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES,
+ .pNext = nullptr,
+ .dynamicRendering = VK_TRUE
+ };
+
+ VkDeviceCreateInfo deviceInfo{
+ .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
+ .pNext = &dynamicRenderingFeatures,
+ .flags = 0,
+ .queueCreateInfoCount = static_cast(queueInfos.size()),
+ .pQueueCreateInfos = queueInfos.data(),
+ .enabledLayerCount = 0,
+ .ppEnabledLayerNames = nullptr,
+ .enabledExtensionCount = static_cast(extensions.size()),
+ .ppEnabledExtensionNames = extensions.data(),
+ .pEnabledFeatures = &deviceFeatures
+ };
spdlog::info(
"Creating new Vulkan device using GPU \"{}\" Vulkan {}",
diff --git a/src/engine/vk/Swapchain.cpp b/src/engine/vk/Swapchain.cpp
index eabaf02..9058f43 100644
--- a/src/engine/vk/Swapchain.cpp
+++ b/src/engine/vk/Swapchain.cpp
@@ -1,12 +1,12 @@
#include "Swapchain.h"
namespace Vixen::Vk {
- Swapchain::Swapchain(const std::shared_ptr &device, uint32_t framesInFlight)
- : device(device),
- currentFrame(0),
- imageCount(framesInFlight),
- format(determineSurfaceFormat(device->getGpu().getSurfaceFormats(device->getSurface()))),
- swapchain(VK_NULL_HANDLE) {
+ Swapchain::Swapchain(const std::shared_ptr& device, uint32_t framesInFlight)
+ : device(device),
+ currentFrame(0),
+ imageCount(framesInFlight),
+ format(determineSurfaceFormat(device->getGpu().getSurfaceFormats(device->getSurface()))),
+ swapchain(VK_NULL_HANDLE) {
create();
}
@@ -14,11 +14,11 @@ namespace Vixen::Vk {
destroy();
}
- VkSurfaceFormatKHR Swapchain::determineSurfaceFormat(const std::vector &available) {
+ VkSurfaceFormatKHR Swapchain::determineSurfaceFormat(const std::vector& available) {
if (available.empty())
throw std::runtime_error("Failed to find suitable surface format");
- for (const auto &format: available) {
+ for (const auto& format : available) {
if (format.format == VK_FORMAT_B8G8R8A8_SRGB &&
format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
return format;
@@ -27,7 +27,7 @@ namespace Vixen::Vk {
return available[0];
}
- VkPresentModeKHR Swapchain::determinePresentMode(const std::vector &available) {
+ VkPresentModeKHR Swapchain::determinePresentMode(const std::vector& available) {
if (available.empty())
throw std::runtime_error("Failed to find suitable present mode");
@@ -43,11 +43,15 @@ namespace Vixen::Vk {
return available[0];
}
- const VkSurfaceFormatKHR &Swapchain::getFormat() const {
+ const VkSurfaceFormatKHR& Swapchain::getColorFormat() const {
return format;
}
- const VkExtent2D &Swapchain::getExtent() const {
+ VkFormat Swapchain::getDepthFormat() const {
+ return depthImages[0]->getFormat();
+ }
+
+ const VkExtent2D& Swapchain::getExtent() const {
return extent;
}
@@ -55,22 +59,26 @@ namespace Vixen::Vk {
return imageCount;
}
- const std::vector<::VkImageView> &Swapchain::getImageViews() const {
- return imageViews;
- }
+ const std::vector>& Swapchain::getColorImages() const { return colorImages; }
+
+ const std::vector& Swapchain::getColorImageViews() const { return colorImageViews; }
+
+ const std::vector>& Swapchain::getDepthImages() const { return depthImages; }
+
+ const std::vector& Swapchain::getDepthImageViews() const { return depthImageViews; }
- void Swapchain::present(uint32_t imageIndex, const std::vector<::VkSemaphore> &waitSemaphores) {
- VkPresentInfoKHR presentInfo{
- .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
+ void Swapchain::present(uint32_t imageIndex, const std::vector<::VkSemaphore>& waitSemaphores) {
+ const VkPresentInfoKHR presentInfo{
+ .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
- .waitSemaphoreCount = static_cast(waitSemaphores.size()),
- .pWaitSemaphores = waitSemaphores.data(),
+ .waitSemaphoreCount = static_cast(waitSemaphores.size()),
+ .pWaitSemaphores = waitSemaphores.data(),
- .swapchainCount = 1,
- .pSwapchains = &swapchain,
+ .swapchainCount = 1,
+ .pSwapchains = &swapchain,
- .pImageIndices = &imageIndex,
- .pResults = nullptr,
+ .pImageIndices = &imageIndex,
+ .pResults = nullptr
};
vkQueuePresentKHR(device->getPresentQueue(), &presentInfo);
@@ -86,7 +94,7 @@ namespace Vixen::Vk {
const auto surface = device->getSurface();
const auto capabilities = device->getGpu().getSurfaceCapabilities(device->getSurface());
- VkPresentModeKHR presentMode = determinePresentMode(device->getGpu().getPresentModes(surface));
+ const VkPresentModeKHR presentMode = determinePresentMode(device->getGpu().getPresentModes(surface));
extent = capabilities.currentExtent;
spdlog::trace("Selected present mode {} and image format {} and color space {}",
@@ -94,24 +102,26 @@ namespace Vixen::Vk {
string_VkFormat(format.format), string_VkColorSpaceKHR(format.colorSpace));
VkSwapchainCreateInfoKHR info{
- .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
- .surface = device->getSurface(),
- .minImageCount = imageCount,
- .imageFormat = format.format,
- .imageColorSpace = format.colorSpace,
- .imageExtent = extent,
- .imageArrayLayers = 1,
- .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
- .preTransform = capabilities.currentTransform,
- .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
- .presentMode = presentMode,
- .clipped = VK_TRUE,
- .oldSwapchain = VK_NULL_HANDLE,
+ .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
+ .surface = device->getSurface(),
+ .minImageCount = imageCount,
+ .imageFormat = format.format,
+ .imageColorSpace = format.colorSpace,
+ .imageExtent = extent,
+ .imageArrayLayers = 1,
+ .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+ .preTransform = capabilities.currentTransform,
+ .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
+ .presentMode = presentMode,
+ .clipped = VK_TRUE,
+ .oldSwapchain = VK_NULL_HANDLE,
};
if (device->getGraphicsQueueFamily().index != device->getPresentQueueFamily().index) {
- std::vector indices = {device->getGraphicsQueueFamily().index,
- device->getPresentQueueFamily().index};
+ const std::vector indices = {
+ device->getGraphicsQueueFamily().index,
+ device->getPresentQueueFamily().index
+ };
info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
info.queueFamilyIndexCount = indices.size();
@@ -123,40 +133,59 @@ namespace Vixen::Vk {
}
checkVulkanResult(
- vkCreateSwapchainKHR(device->getDevice(), &info, nullptr, &swapchain),
- "Failed to create swapchain"
+ vkCreateSwapchainKHR(device->getDevice(), &info, nullptr, &swapchain),
+ "Failed to create swapchain"
);
+ std::vector<::VkImage> swapchainImages;
vkGetSwapchainImagesKHR(device->getDevice(), swapchain, &imageCount, nullptr);
- images.resize(imageCount);
- vkGetSwapchainImagesKHR(device->getDevice(), swapchain, &imageCount, images.data());
-
- imageViews.resize(images.size());
- imageAvailableSemaphores.reserve(images.size());
- for (auto i = 0; i < images.size(); i++) {
- VkImageViewCreateInfo imageViewCreateInfo{
- .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
- .image = images[i],
- .viewType = VK_IMAGE_VIEW_TYPE_2D,
- .format = format.format,
- .components = {
- .r = VK_COMPONENT_SWIZZLE_IDENTITY,
- .g = VK_COMPONENT_SWIZZLE_IDENTITY,
- .b = VK_COMPONENT_SWIZZLE_IDENTITY,
- .a = VK_COMPONENT_SWIZZLE_IDENTITY,
- },
- .subresourceRange = {
- .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
- .baseMipLevel = 0,
- .levelCount = 1,
- .baseArrayLayer = 0,
- .layerCount = 1
- }
- };
+ swapchainImages.resize(imageCount);
+ vkGetSwapchainImagesKHR(device->getDevice(), swapchain, &imageCount, swapchainImages.data());
+
+ colorImages.reserve(imageCount);
+ colorImageViews.reserve(imageCount);
+ depthImages.reserve(imageCount);
+ depthImageViews.reserve(imageCount);
+ imageAvailableSemaphores.reserve(imageCount);
+ for (auto i = 0; i < imageCount; i++) {
+ colorImages.emplace_back(
+ std::make_shared(
+ device,
+ swapchainImages[i],
+ extent.width,
+ extent.height,
+ format.format,
+ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+ 1
+ )
+ );
+ colorImageViews.emplace_back(
+ colorImages[i],
+ VK_IMAGE_ASPECT_COLOR_BIT
+ );
- checkVulkanResult(
- vkCreateImageView(device->getDevice(), &imageViewCreateInfo, nullptr, &imageViews[i]),
- "Failed to create image view"
+ depthImages.push_back(
+ std::make_shared(
+ device,
+ extent.width,
+ extent.height,
+ VK_SAMPLE_COUNT_1_BIT,
+ device->getGpu().pickFormat(
+ {
+ VK_FORMAT_D32_SFLOAT_S8_UINT,
+ VK_FORMAT_D24_UNORM_S8_UINT
+ },
+ VK_IMAGE_TILING_OPTIMAL,
+ VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT
+ ),
+ VK_IMAGE_TILING_OPTIMAL,
+ VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
+ 1
+ )
+ );
+ depthImageViews.emplace_back(
+ depthImages[i],
+ VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT
);
imageAvailableSemaphores.emplace_back(device);
@@ -164,8 +193,11 @@ namespace Vixen::Vk {
}
void Swapchain::destroy() {
- for (auto &imageView: imageViews)
- vkDestroyImageView(device->getDevice(), imageView, nullptr);
+ depthImageViews.clear();
+ depthImages.clear();
+ colorImageViews.clear();
+ colorImages.clear();
+ imageAvailableSemaphores.clear();
vkDestroySwapchainKHR(device->getDevice(), swapchain, nullptr);
}
}
diff --git a/src/engine/vk/Swapchain.h b/src/engine/vk/Swapchain.h
index 212fb19..5c2457a 100644
--- a/src/engine/vk/Swapchain.h
+++ b/src/engine/vk/Swapchain.h
@@ -2,10 +2,42 @@
#include
#include "Device.h"
+#include "VkImage.h"
+#include "VkImageView.h"
#include "VkSemaphore.h"
namespace Vixen::Vk {
class Swapchain {
+ std::shared_ptr device;
+
+ uint32_t currentFrame;
+
+ uint32_t imageCount;
+
+ VkSurfaceFormatKHR format;
+
+ VkSwapchainKHR swapchain;
+
+ std::vector> colorImages;
+
+ std::vector colorImageViews;
+
+ std::vector> depthImages;
+
+ std::vector depthImageViews;
+
+ VkExtent2D extent{};
+
+ std::vector imageAvailableSemaphores;
+
+ static VkSurfaceFormatKHR determineSurfaceFormat(const std::vector& available);
+
+ static VkPresentModeKHR determinePresentMode(const std::vector& available);
+
+ void create();
+
+ void destroy();
+
public:
enum class State {
OK,
@@ -13,7 +45,7 @@ namespace Vixen::Vk {
OUT_OF_DATE
};
- Swapchain(const std::shared_ptr &device, uint32_t framesInFlight);
+ Swapchain(const std::shared_ptr& device, uint32_t framesInFlight);
~Swapchain();
@@ -24,18 +56,18 @@ namespace Vixen::Vk {
* @return Returns true when the swapchain is out-of-date, indicating the need to recreate the swapchain,
* otherwise false.
*/
- template
- State acquireImage(uint64_t timeout, const F &lambda) {
- auto &imageAvailableSemaphore = imageAvailableSemaphores[currentFrame];
+ template
+ State acquireImage(uint64_t timeout, const F& lambda) {
+ auto& imageAvailableSemaphore = imageAvailableSemaphores[currentFrame];
uint32_t imageIndex;
auto result = vkAcquireNextImageKHR(
- device->getDevice(),
- swapchain,
- timeout,
- imageAvailableSemaphore.getSemaphore(),
- VK_NULL_HANDLE,
- &imageIndex
+ device->getDevice(),
+ swapchain,
+ timeout,
+ imageAvailableSemaphore.getSemaphore(),
+ VK_NULL_HANDLE,
+ &imageIndex
);
if (result == VK_ERROR_OUT_OF_DATE_KHR) {
@@ -49,56 +81,37 @@ namespace Vixen::Vk {
switch (result) {
using
- enum State;
-
- case VK_SUCCESS:
- return OK;
- case VK_SUBOPTIMAL_KHR:
- spdlog::warn("Suboptimal swapchain state");
- return SUBOPTIMAL;
- default:
- checkVulkanResult(result, "Failed to acquire swapchain image");
- return OUT_OF_DATE;
+ enum State;
+
+ case VK_SUCCESS:
+ return OK;
+ case VK_SUBOPTIMAL_KHR:
+ spdlog::warn("Suboptimal swapchain state");
+ return SUBOPTIMAL;
+ default:
+ checkVulkanResult(result, "Failed to acquire swapchain image");
+ return OUT_OF_DATE;
}
}
- [[nodiscard]] const VkSurfaceFormatKHR &getFormat() const;
-
- [[nodiscard]] const VkExtent2D &getExtent() const;
-
- [[nodiscard]] uint32_t getImageCount() const;
-
- [[nodiscard]] const std::vector<::VkImageView> &getImageViews() const;
-
- void present(uint32_t imageIndex, const std::vector<::VkSemaphore> &waitSemaphores);
+ [[nodiscard]] const VkSurfaceFormatKHR& getColorFormat() const;
- void invalidate();
-
- private:
- std::shared_ptr device;
+ [[nodiscard]] VkFormat getDepthFormat() const;
- uint32_t currentFrame;
-
- uint32_t imageCount;
+ [[nodiscard]] const VkExtent2D& getExtent() const;
- VkSurfaceFormatKHR format;
-
- VkSwapchainKHR swapchain;
+ [[nodiscard]] uint32_t getImageCount() const;
- std::vector<::VkImage> images;
+ [[nodiscard]] const std::vector>& getColorImages() const;
- std::vector<::VkImageView> imageViews;
+ [[nodiscard]] const std::vector& getColorImageViews() const;
- VkExtent2D extent{};
+ [[nodiscard]] const std::vector>& getDepthImages() const;
- std::vector imageAvailableSemaphores;
+ [[nodiscard]] const std::vector& getDepthImageViews() const;
- static VkSurfaceFormatKHR determineSurfaceFormat(const std::vector &available);
+ void present(uint32_t imageIndex, const std::vector<::VkSemaphore>& waitSemaphores);
- static VkPresentModeKHR determinePresentMode(const std::vector &available);
-
- void create();
-
- void destroy();
+ void invalidate();
};
}
diff --git a/src/engine/vk/VkCommandBuffer.cpp b/src/engine/vk/VkCommandBuffer.cpp
index 9bc1914..2eaea8c 100644
--- a/src/engine/vk/VkCommandBuffer.cpp
+++ b/src/engine/vk/VkCommandBuffer.cpp
@@ -1,6 +1,7 @@
#include "VkCommandBuffer.h"
#include "VkCommandPool.h"
+#include "../IndexFormat.h"
namespace Vixen::Vk {
VkCommandBuffer::VkCommandBuffer(
@@ -104,6 +105,145 @@ namespace Vixen::Vk {
);
}
+ void VkCommandBuffer::beginRenderPass(
+ const uint32_t width,
+ const uint32_t height,
+ const uint8_t samples,
+ const std::vector& attachments,
+ const VkImageView& depthAttachment
+ ) const {
+ std::vector vkAttachments{attachments.size()};
+ for (auto i = 0; i < attachments.size(); i++) {
+ auto [loadAction, storeAction, layout, loadStoreTarget, resolveTarget, clearColor, clearDepth, clearStencil]
+ = attachments[i];
+
+ vkAttachments[i] = {
+ .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
+ .pNext = nullptr,
+ .imageView = loadStoreTarget,
+ .imageLayout = layout,
+ .resolveMode = storeAction == StoreAction::Resolve ||
+ storeAction == StoreAction::StoreAndResolve
+ ? VK_RESOLVE_MODE_AVERAGE_BIT
+ : VK_RESOLVE_MODE_NONE,
+ .resolveImageView = resolveTarget,
+ .resolveImageLayout = layout,
+ .loadOp = toVkLoadAction(loadAction),
+ .storeOp = toVkStoreAction(storeAction),
+ .clearValue = {
+ .color = {
+ clearColor.r,
+ clearColor.g,
+ clearColor.b,
+ clearColor.a
+ },
+ }
+ };
+ }
+
+ VkRenderingAttachmentInfo depthAttachmentInfo{
+ .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
+ .pNext = nullptr,
+ .imageView = depthAttachment,
+ .imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+ .resolveMode = VK_RESOLVE_MODE_NONE,
+ .resolveImageView = nullptr,
+ .resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED,
+ .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
+ .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
+ .clearValue = {
+ .depthStencil = {
+ 1.0f,
+ 0
+ }
+ }
+ };
+
+ const VkRenderingInfo renderingInfo{
+ .sType = VK_STRUCTURE_TYPE_RENDERING_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .renderArea = {
+ .offset = {
+ .x = 0,
+ .y = 0
+ },
+ .extent = {
+ .width = width,
+ .height = height
+ }
+ },
+ .layerCount = 1,
+ .viewMask = 0,
+ .colorAttachmentCount = static_cast(vkAttachments.size()),
+ .pColorAttachments = vkAttachments.data(),
+ .pDepthAttachment = &depthAttachmentInfo,
+ .pStencilAttachment = &depthAttachmentInfo
+ };
+
+ vkCmdBeginRendering(commandBuffer, &renderingInfo);
+ }
+
+ void VkCommandBuffer::endRenderPass() const {
+ vkCmdEndRendering(commandBuffer);
+ }
+
+ void VkCommandBuffer::setViewport(const Rectangle rectangle) const {
+ const VkViewport viewport{
+ .x = rectangle.x,
+ .y = rectangle.y,
+ .width = rectangle.width,
+ .height = rectangle.height,
+ .minDepth = 0.0f,
+ .maxDepth = 1.0f
+ };
+
+ vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
+ }
+
+ void VkCommandBuffer::setScissor(const Rectangle rectangle) const {
+ const VkRect2D rect{
+ .offset = {
+ .x = static_cast(rectangle.x),
+ .y = static_cast(rectangle.y)
+ },
+ .extent = {
+ .width = static_cast(rectangle.width),
+ .height = static_cast(rectangle.height)
+ }
+ };
+
+ vkCmdSetScissor(commandBuffer, 0, 1, &rect);
+ }
+
+ void VkCommandBuffer::drawMesh(const VkMesh& mesh) const {
+ const auto& vertexBuffer = mesh.getVertexBuffer().getBuffer();
+ constexpr std::array offsets{0};
+ vkCmdBindVertexBuffers(
+ commandBuffer,
+ 0,
+ 1,
+ &vertexBuffer,
+ offsets.data()
+ );
+
+ vkCmdBindIndexBuffer(
+ commandBuffer,
+ mesh.getIndexBuffer().getBuffer(),
+ 0,
+ mesh.getIndexFormat() == IndexFormat::UNSIGNED_INT_16 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32
+ );
+
+ vkCmdDrawIndexed(
+ commandBuffer,
+ mesh.getIndexCount(),
+ 1,
+ 0,
+ 0,
+ 0
+ );
+ }
+
void VkCommandBuffer::copyBuffer(const VkBuffer& source, const VkBuffer& destination) const {
const VkBufferCopy region{
.srcOffset = 0,
@@ -153,7 +293,11 @@ namespace Vixen::Vk {
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image.getImage(),
.subresourceRange = {
- .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .aspectMask = static_cast(
+ isDepthFormat(image.getFormat())
+ ? VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT
+ : VK_IMAGE_ASPECT_COLOR_BIT
+ ),
.baseMipLevel = 0,
.levelCount = image.getMipLevels(),
.baseArrayLayer = 0,
@@ -171,18 +315,33 @@ namespace Vixen::Vk {
sourceFlags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
destinationFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
- }
- else if (image.getLayout() == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL &&
+ } else if (image.getLayout() == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL &&
layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
sourceFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
destinationFlags = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
- }
- else {
+ } else if (layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
+ barrier.srcAccessMask = 0;
+ barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+
+ sourceFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ destinationFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ } else if (layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {
+ barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+ barrier.dstAccessMask = 0;
+
+ sourceFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ destinationFlags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
+ } else if (layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
+ barrier.srcAccessMask = 0;
+ barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
+
+ sourceFlags = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
+ destinationFlags = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
+ } else
throw std::runtime_error("Unsupported transition layout");
- }
vkCmdPipelineBarrier(
commandBuffer,
diff --git a/src/engine/vk/VkCommandBuffer.h b/src/engine/vk/VkCommandBuffer.h
index 0c96716..3253829 100644
--- a/src/engine/vk/VkCommandBuffer.h
+++ b/src/engine/vk/VkCommandBuffer.h
@@ -3,7 +3,10 @@
#include "VkBuffer.h"
#include "VkFence.h"
#include "VkImage.h"
+#include "VkMesh.h"
+#include "../AttachmentInfo.h"
#include "../CommandBuffer.h"
+#include "../Rectangle.h"
namespace Vixen::Vk {
class VkCommandPool;
@@ -29,16 +32,8 @@ namespace Vixen::Vk {
~VkCommandBuffer();
template
- VkCommandBuffer& record(CommandBufferUsage usage, F commands) {
- reset();
-
- begin(usage);
-
+ void record(F commands) const {
commands(commandBuffer);
-
- end();
-
- return *this;
}
void wait() const;
@@ -56,6 +51,22 @@ namespace Vixen::Vk {
const std::vector<::VkSemaphore>& signalSemaphores
) const;
+ void beginRenderPass(
+ uint32_t width,
+ uint32_t height,
+ uint8_t samples,
+ const std::vector& attachments,
+ const VkImageView &depthAttachment
+ ) const;
+
+ void endRenderPass() const;
+
+ void setViewport(Rectangle rectangle) const;
+
+ void setScissor(Rectangle rectangle) const;
+
+ void drawMesh(const VkMesh& mesh) const;
+
void copyBuffer(const VkBuffer& source, const VkBuffer& destination) const;
void copyImage(const VkImage& source, const VkImage& destination) const;
diff --git a/src/engine/vk/VkFramebuffer.cpp b/src/engine/vk/VkFramebuffer.cpp
deleted file mode 100644
index b27e0ff..0000000
--- a/src/engine/vk/VkFramebuffer.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-#include "VkFramebuffer.h"
-
-namespace Vixen::Vk {
- VkFramebuffer::VkFramebuffer(
- const std::shared_ptr& device,
- const VkRenderPass& renderPass,
- uint32_t width,
- uint32_t height
- ) : device(device),
- framebuffer(VK_NULL_HANDLE) {
- const auto& attachments = renderPass.getAttachments();
- images.reserve(attachments.size());
- imageViews.reserve(attachments.size());
-
- for (size_t i = 0; i < attachments.size(); i++) {
- const auto& [flags, format, samples, loadOp, storeOp, stencilLoadOp, stencilStoreOp, initialLayout,
- finalLayout] = attachments[i];
-
- images.push_back(
- std::make_shared(
- device,
- width,
- height,
- VK_SAMPLE_COUNT_1_BIT,
- format,
- VK_IMAGE_TILING_OPTIMAL,
- VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
- 1
- )
- );
-
- imageViews.emplace_back(
- std::make_unique(
- images[i],
- VK_IMAGE_ASPECT_DEPTH_BIT
- )
- );
- }
-
- std::vector<::VkImageView> views{imageViews.size()};
- std::ranges::transform(imageViews, views.data(), [](const auto& imageView) {
- return imageView->getImageView();
- });
- const VkFramebufferCreateInfo info{
- .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
- .renderPass = renderPass.getRenderPass(),
- .attachmentCount = static_cast(views.size()),
- .pAttachments = views.data(),
- .width = width,
- .height = height,
- .layers = 0
- };
-
- checkVulkanResult(
- vkCreateFramebuffer(
- device->getDevice(),
- &info,
- nullptr,
- &framebuffer
- ),
- "Failed to create framebuffer"
- );
- }
-
- VkFramebuffer::VkFramebuffer(
- const std::shared_ptr& device,
- const VkRenderPass& renderPass,
- uint32_t width,
- uint32_t height,
- std::vector<::VkImageView> imageViews
- ) : device(device),
- framebuffer(VK_NULL_HANDLE) {
- VkFramebufferCreateInfo info{
- .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
- .renderPass = renderPass.getRenderPass(),
- .attachmentCount = static_cast(imageViews.size()),
- .pAttachments = imageViews.data(),
- .width = width,
- .height = height,
- .layers = 1
- };
-
- checkVulkanResult(
- vkCreateFramebuffer(
- device->getDevice(),
- &info,
- nullptr,
- &framebuffer
- ),
- "Failed to create framebuffer"
- );
- }
-
- VkFramebuffer::VkFramebuffer(VkFramebuffer&& o) noexcept
- : device(std::move(o.device)),
- images(std::exchange(o.images, {})),
- imageViews(std::exchange(o.imageViews, {})),
- framebuffer(std::exchange(o.framebuffer, nullptr)) {}
-
- VkFramebuffer::~VkFramebuffer() {
- vkDestroyFramebuffer(device->getDevice(), framebuffer, nullptr);
- }
-
- ::VkFramebuffer VkFramebuffer::getFramebuffer() const {
- return framebuffer;
- }
-}
diff --git a/src/engine/vk/VkFramebuffer.h b/src/engine/vk/VkFramebuffer.h
deleted file mode 100644
index 67d803a..0000000
--- a/src/engine/vk/VkFramebuffer.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#pragma once
-
-#include "Device.h"
-#include "VkRenderPass.h"
-#include "VkImageView.h"
-
-namespace Vixen::Vk {
- class VkFramebuffer {
- std::shared_ptr device;
-
- std::vector> images;
-
- std::vector> imageViews;
-
- ::VkFramebuffer framebuffer;
-
- public:
- VkFramebuffer(
- const std::shared_ptr &device,
- const VkRenderPass &renderPass,
- uint32_t width,
- uint32_t height
- );
-
- VkFramebuffer(
- const std::shared_ptr &device,
- const VkRenderPass &renderPass,
- uint32_t width,
- uint32_t height,
- std::vector<::VkImageView> imageViews
- );
-
- VkFramebuffer(const VkFramebuffer &) = delete;
-
- VkFramebuffer(VkFramebuffer &&o) noexcept;
-
- VkFramebuffer &operator=(const VkFramebuffer &) = delete;
-
- ~VkFramebuffer();
-
- [[nodiscard]] ::VkFramebuffer getFramebuffer() const;
- };
-}
diff --git a/src/engine/vk/VkImage.cpp b/src/engine/vk/VkImage.cpp
index 35a4163..47db132 100644
--- a/src/engine/vk/VkImage.cpp
+++ b/src/engine/vk/VkImage.cpp
@@ -44,6 +44,11 @@ namespace Vixen::Vk {
constexpr VmaAllocationCreateInfo allocationCreateInfo = {
.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT,
.usage = VMA_MEMORY_USAGE_AUTO,
+ .requiredFlags = 0,
+ .preferredFlags = 0,
+ .memoryTypeBits = 0,
+ .pool = nullptr,
+ .pUserData = nullptr,
.priority = 1.0f
};
@@ -60,6 +65,24 @@ namespace Vixen::Vk {
);
}
+ VkImage::VkImage(
+ const std::shared_ptr& device,
+ ::VkImage image,
+ const uint32_t width,
+ const uint32_t height,
+ const VkFormat format,
+ const VkImageUsageFlags usageFlags,
+ const uint8_t mipLevels
+ ) : device(device),
+ image(image),
+ allocation(VK_NULL_HANDLE),
+ width(width),
+ height(height),
+ layout(VK_IMAGE_LAYOUT_UNDEFINED),
+ format(format),
+ usageFlags(usageFlags),
+ mipLevels(mipLevels) {}
+
VkImage::VkImage(VkImage&& other) noexcept
: device(std::exchange(other.device, nullptr)),
allocation(std::exchange(other.allocation, VK_NULL_HANDLE)),
@@ -113,7 +136,9 @@ namespace Vixen::Vk {
const auto& format = FreeImage_GetFileType(path.c_str(), static_cast(path.length()));
if (format == FIF_UNKNOWN) {
- error(R"(Failed to determine image format for file "{}", is the relative path correct? Possibly unsupported format?)", path);
+ error(
+ R"(Failed to determine image format for file "{}", is the relative path correct? Possibly unsupported format?)",
+ path);
throw std::runtime_error("Failed to determine image format for file");
}
diff --git a/src/engine/vk/VkImage.h b/src/engine/vk/VkImage.h
index 5b21f8e..a4d6752 100644
--- a/src/engine/vk/VkImage.h
+++ b/src/engine/vk/VkImage.h
@@ -38,6 +38,16 @@ namespace Vixen::Vk {
uint8_t mipLevels
);
+ VkImage(
+ const std::shared_ptr& device,
+ ::VkImage image,
+ uint32_t width,
+ uint32_t height,
+ VkFormat format,
+ VkImageUsageFlags usageFlags,
+ uint8_t mipLevels
+ );
+
VkImage(VkImage& other) = delete;
VkImage& operator=(const VkImage& other) = delete;
diff --git a/src/engine/vk/VkImageView.cpp b/src/engine/vk/VkImageView.cpp
index a47121a..f5d959e 100644
--- a/src/engine/vk/VkImageView.cpp
+++ b/src/engine/vk/VkImageView.cpp
@@ -21,9 +21,16 @@ namespace Vixen::Vk {
);
}
- // VkImageView::VkImageView(VkImageView &&o) noexcept
- // : image(o.image),
- // imageView(std::exchange(o.imageView, VK_NULL_HANDLE)) {}
+ VkImageView::VkImageView(VkImageView&& o) noexcept
+ : image(std::exchange(o.image, nullptr)),
+ imageView(std::exchange(o.imageView, nullptr)) {}
+
+ VkImageView& VkImageView::operator=(VkImageView&& o) noexcept {
+ std::swap(image, o.image);
+ std::swap(imageView, o.imageView);
+
+ return *this;
+ }
VkImageView::~VkImageView() {
vkDestroyImageView(
diff --git a/src/engine/vk/VkImageView.h b/src/engine/vk/VkImageView.h
index 09cb700..d0aedeb 100644
--- a/src/engine/vk/VkImageView.h
+++ b/src/engine/vk/VkImageView.h
@@ -9,13 +9,15 @@ namespace Vixen::Vk {
::VkImageView imageView;
public:
- VkImageView(const std::shared_ptr &image, VkImageAspectFlags aspectFlags);
+ VkImageView(const std::shared_ptr& image, VkImageAspectFlags aspectFlags);
- VkImageView(const VkImageView &) = delete;
+ VkImageView(const VkImageView&) = delete;
-// VkImageView(VkImageView &&o) noexcept;
+ VkImageView& operator=(const VkImageView&) = delete;
- VkImageView &operator=(const VkImageView &) = delete;
+ VkImageView(VkImageView&& o) noexcept;
+
+ VkImageView& operator=(VkImageView&& o) noexcept;
~VkImageView();
diff --git a/src/engine/vk/VkPipeline.cpp b/src/engine/vk/VkPipeline.cpp
index 7025893..ceb131e 100644
--- a/src/engine/vk/VkPipeline.cpp
+++ b/src/engine/vk/VkPipeline.cpp
@@ -8,7 +8,6 @@ namespace Vixen::Vk {
) : device(device),
program(program),
config(config),
- renderPass(device, config.format),
pipelineLayout(device, program) {
std::vector stages;
stages.emplace_back(program.getVertex()->createInfo());
@@ -108,8 +107,19 @@ namespace Vixen::Vk {
}
};
- const VkGraphicsPipelineCreateInfo pipelineInfo{
+ const VkPipelineRenderingCreateInfo renderingCreateInfo{
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
+ .pNext = nullptr,
+ .viewMask = 0,
+ .colorAttachmentCount = 1,
+ .pColorAttachmentFormats = &config.colorFormat,
+ .depthAttachmentFormat = config.depthFormat,
+ .stencilAttachmentFormat = config.depthFormat
+ };
+
+ const VkGraphicsPipelineCreateInfo pipelineCreateInfo{
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
+ .pNext = &renderingCreateInfo,
.stageCount = static_cast(stages.size()),
.pStages = stages.data(),
.pVertexInputState = &vertexInputInfo,
@@ -122,15 +132,15 @@ namespace Vixen::Vk {
.pDynamicState = &dynamicStateInfo,
.layout = pipelineLayout.getLayout(),
- .renderPass = renderPass.getRenderPass(),
+ .renderPass = VK_NULL_HANDLE,
.subpass = config.subpass,
.basePipelineHandle = VK_NULL_HANDLE,
- .basePipelineIndex = -1,
+ .basePipelineIndex = -1
};
checkVulkanResult(
- vkCreateGraphicsPipelines(device->getDevice(), VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline),
+ vkCreateGraphicsPipelines(device->getDevice(), VK_NULL_HANDLE, 1, &pipelineCreateInfo, nullptr, &pipeline),
"Failed to create Vulkan pipeline"
);
}
@@ -139,15 +149,13 @@ namespace Vixen::Vk {
: device(std::move(other.device)),
program(std::move(other.program)),
config(other.config),
- renderPass(std::move(other.renderPass)),
pipelineLayout(std::move(other.pipelineLayout)),
pipeline(std::exchange(other.pipeline, nullptr)) {}
- VkPipeline const& VkPipeline::operator=(VkPipeline&& other) noexcept {
+ VkPipeline& VkPipeline::operator=(VkPipeline&& other) noexcept {
std::swap(device, other.device);
std::swap(program, other.program);
std::swap(config, other.config);
- std::swap(renderPass, other.renderPass);
std::swap(pipelineLayout, other.pipelineLayout);
std::swap(pipeline, other.pipeline);
@@ -176,8 +184,6 @@ namespace Vixen::Vk {
const VkShaderProgram& VkPipeline::getProgram() const { return program; }
- const VkRenderPass& VkPipeline::getRenderPass() const { return renderPass; }
-
const VkPipeline::Config& VkPipeline::getConfig() const { return config; }
std::shared_ptr VkPipeline::getDevice() const { return device; }
diff --git a/src/engine/vk/VkPipeline.h b/src/engine/vk/VkPipeline.h
index 738f418..4b07fb1 100644
--- a/src/engine/vk/VkPipeline.h
+++ b/src/engine/vk/VkPipeline.h
@@ -3,7 +3,6 @@
#include "Device.h"
#include "VkShaderProgram.h"
#include "VkPipelineLayout.h"
-#include "VkRenderPass.h"
// TODO: This should really be abstracted so that we can later more easily create different pipelines
namespace Vixen::Vk {
@@ -18,7 +17,8 @@ namespace Vixen::Vk {
VkPipelineColorBlendAttachmentState colorBlendAttachment{};
VkPipelineDepthStencilStateCreateInfo depthStencilInfo{};
uint32_t subpass = 0;
- VkFormat format = VK_FORMAT_UNDEFINED;
+ VkFormat colorFormat = VK_FORMAT_UNDEFINED;
+ VkFormat depthFormat = VK_FORMAT_UNDEFINED;
};
protected:
@@ -28,8 +28,6 @@ namespace Vixen::Vk {
Config config;
- VkRenderPass renderPass;
-
VkPipelineLayout pipelineLayout;
::VkPipeline pipeline = VK_NULL_HANDLE;
@@ -47,7 +45,7 @@ namespace Vixen::Vk {
VkPipeline(VkPipeline&& other) noexcept;
- VkPipeline const& operator=(VkPipeline&& other) noexcept;
+ VkPipeline& operator=(VkPipeline&& other) noexcept;
~VkPipeline();
@@ -61,8 +59,6 @@ namespace Vixen::Vk {
[[nodiscard]] const VkShaderProgram& getProgram() const;
- [[nodiscard]] const VkRenderPass& getRenderPass() const;
-
[[nodiscard]] const Config& getConfig() const;
[[nodiscard]] std::shared_ptr getDevice() const;
@@ -148,33 +144,38 @@ namespace Vixen::Vk {
return *this;
}
- Builder& setInputAssembly(VkPipelineInputAssemblyStateCreateInfo info) {
+ Builder& setInputAssembly(const VkPipelineInputAssemblyStateCreateInfo& info) {
config.inputAssemblyInfo = info;
return *this;
}
- Builder& setRasterization(VkPipelineRasterizationStateCreateInfo info) {
+ Builder& setRasterization(const VkPipelineRasterizationStateCreateInfo& info) {
config.rasterizationInfo = info;
return *this;
}
- Builder& setMultisample(VkPipelineMultisampleStateCreateInfo info) {
+ Builder& setMultisample(const VkPipelineMultisampleStateCreateInfo& info) {
config.multisampleInfo = info;
return *this;
}
- Builder& setColorBlend(VkPipelineColorBlendAttachmentState info) {
+ Builder& setColorBlend(const VkPipelineColorBlendAttachmentState& info) {
config.colorBlendAttachment = info;
return *this;
}
- Builder& setDepthStencil(VkPipelineDepthStencilStateCreateInfo info) {
+ Builder& setDepthStencil(const VkPipelineDepthStencilStateCreateInfo& info) {
config.depthStencilInfo = info;
return *this;
}
- Builder& setFormat(const VkFormat format) {
- config.format = format;
+ Builder& setColorFormat(const VkFormat &format) {
+ config.colorFormat = format;
+ return *this;
+ }
+
+ Builder& setDepthFormat(const VkFormat &format) {
+ config.depthFormat = format;
return *this;
}
diff --git a/src/engine/vk/VkRenderPass.cpp b/src/engine/vk/VkRenderPass.cpp
deleted file mode 100644
index 96a1ed9..0000000
--- a/src/engine/vk/VkRenderPass.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
-#include "VkRenderPass.h"
-
-namespace Vixen::Vk {
- VkRenderPass::VkRenderPass(
- const std::shared_ptr& device,
- const VkFormat format
- ) : device(device),
- renderPass(VK_NULL_HANDLE) {
- attachments.emplace_back(VkAttachmentDescription{
- .format = format,
- .samples = VK_SAMPLE_COUNT_1_BIT,
- .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
- .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
- .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
- .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
- .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
- .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
- });
-
- VkAttachmentReference colorAttachmentRef{
- .attachment = 0,
- .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
- };
-
- attachments.emplace_back(VkAttachmentDescription{
- .format = device->getGpu().pickFormat(
- {
- VK_FORMAT_D32_SFLOAT,
- VK_FORMAT_D32_SFLOAT_S8_UINT,
- VK_FORMAT_D24_UNORM_S8_UINT
- },
- VK_IMAGE_TILING_OPTIMAL,
- VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT
- ),
- .samples = VK_SAMPLE_COUNT_1_BIT,
- .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
- .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
- .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
- .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
- .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
- .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
- });
-
- VkAttachmentReference depthAttachmentRef{
- .attachment = 1,
- .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
- };
-
- VkSubpassDescription subpass{
- .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
- .colorAttachmentCount = 1,
- .pColorAttachments = &colorAttachmentRef,
- .pDepthStencilAttachment = &depthAttachmentRef
- };
-
- VkSubpassDependency dependency{
- .srcSubpass = VK_SUBPASS_EXTERNAL,
- .dstSubpass = 0,
- .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
- VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
- .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
- VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
- .srcAccessMask = 0,
- .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
- VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
- };
-
- VkRenderPassCreateInfo info{
- .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
- .attachmentCount = static_cast(attachments.size()),
- .pAttachments = attachments.data(),
- .subpassCount = 1,
- .pSubpasses = &subpass,
- .dependencyCount = 1,
- .pDependencies = &dependency
- };
-
- checkVulkanResult(
- vkCreateRenderPass(device->getDevice(), &info, nullptr, &renderPass),
- "Failed to create render pass"
- );
- }
-
- VkRenderPass::VkRenderPass(VkRenderPass&& other) noexcept
- : device(std::move(other.device)),
- renderPass(std::exchange(other.renderPass, nullptr)),
- attachments(std::move(other.attachments)),
- references(std::move(other.references)) {}
-
- VkRenderPass const& VkRenderPass::operator=(VkRenderPass&& other) noexcept {
- std::swap(device, other.device);
- std::swap(renderPass, other.renderPass);
- std::swap(attachments, other.attachments);
- std::swap(references, other.references);
-
- return *this;
- }
-
- VkRenderPass::~VkRenderPass() {
- vkDestroyRenderPass(device->getDevice(), renderPass, nullptr);
- }
-
- ::VkRenderPass VkRenderPass::getRenderPass() const {
- return renderPass;
- }
-
- std::vector VkRenderPass::getAttachments() const {
- return attachments;
- }
-}
diff --git a/src/engine/vk/VkRenderPass.h b/src/engine/vk/VkRenderPass.h
deleted file mode 100644
index 36c7d03..0000000
--- a/src/engine/vk/VkRenderPass.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#pragma once
-
-#include "Device.h"
-#include "Swapchain.h"
-#include "VkShaderProgram.h"
-
-namespace Vixen::Vk {
- class VkRenderPass {
- std::shared_ptr device;
-
- ::VkRenderPass renderPass;
-
- std::vector attachments;
-
- std::vector references;
-
- public:
- VkRenderPass(
- const std::shared_ptr &device,
- VkFormat format
- );
-
- VkRenderPass(VkRenderPass& other) = delete;
-
- VkRenderPass& operator=(const VkRenderPass& other) = delete;
-
- VkRenderPass(VkRenderPass&& other) noexcept;
-
- VkRenderPass const& operator=(VkRenderPass&& other) noexcept;
-
- ~VkRenderPass();
-
- [[nodiscard]] ::VkRenderPass getRenderPass() const;
-
- [[nodiscard]] std::vector getAttachments() const;
- };
-}
diff --git a/src/engine/vk/VkRenderer.cpp b/src/engine/vk/VkRenderer.cpp
index 6be0b48..c49f430 100644
--- a/src/engine/vk/VkRenderer.cpp
+++ b/src/engine/vk/VkRenderer.cpp
@@ -1,6 +1,6 @@
#include "VkRenderer.h"
-#include "../IndexFormat.h"
+#include "Swapchain.h"
namespace Vixen::Vk {
VkRenderer::VkRenderer(
@@ -26,8 +26,6 @@ namespace Vixen::Vk {
renderFinishedSemaphores.reserve(imageCount);
for (size_t i = 0; i < imageCount; i++)
renderFinishedSemaphores.emplace_back(device);
-
- createFramebuffers();
}
VkRenderer::~VkRenderer() {
@@ -47,7 +45,7 @@ namespace Vixen::Vk {
) {
auto& commandBuffer = renderCommandBuffers[currentFrame];
- prepare(commandBuffer, framebuffers[imageIndex], mesh, descriptorSets);
+ prepare(imageIndex, commandBuffer, mesh, descriptorSets);
std::vector<::VkSemaphore> signalSemaphores = {renderFinishedSemaphores[currentFrame].getSemaphore()};
@@ -63,153 +61,85 @@ namespace Vixen::Vk {
); state == Swapchain::State::OUT_OF_DATE) {
device->waitIdle();
- framebuffers.clear();
- depthImageViews.clear();
- depthImages.clear();
-
swapchain->invalidate();
-
- createFramebuffers();
}
}
void VkRenderer::prepare(
- VkCommandBuffer& commandBuffer,
- VkFramebuffer& framebuffer,
+ const uint32_t imageIndex,
+ const VkCommandBuffer& commandBuffer,
const VkMesh& mesh,
const std::vector<::VkDescriptorSet>& descriptorSets
) const {
- commandBuffer.record(
- CommandBufferUsage::SIMULTANEOUS,
- [this, &framebuffer, &mesh, &descriptorSets](::VkCommandBuffer commandBuffer) {
- std::vector clearValues{
- {
- .color = {
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f
- }
- },
- {
- .depthStencil = {
- 1.0f,
- 0
- }
- }
- };
-
- const VkRenderPassBeginInfo renderPassInfo{
- .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
- .renderPass = pipeline->getRenderPass().getRenderPass(),
- .framebuffer = framebuffer.getFramebuffer(),
- .renderArea = {
- .offset = {
- .x = 0,
- .y = 0
- },
- .extent = swapchain->getExtent(),
- },
- .clearValueCount = static_cast(clearValues.size()),
- .pClearValues = clearValues.data()
- };
-
- vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
-
- pipeline->bindGraphics(commandBuffer);
-
- const VkViewport viewport{
- .x = 0.0f,
- .y = 0.0f,
- .width = static_cast(swapchain->getExtent().width),
- .height = static_cast(swapchain->getExtent().height),
- .minDepth = 0.0f,
- .maxDepth = 1.0f,
- };
- vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
-
- const VkRect2D scissor{
- .offset = {0, 0},
- .extent = swapchain->getExtent(),
- };
- vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
-
- const ::VkBuffer vertexBuffers[1]{mesh.getVertexBuffer().getBuffer()};
- // TODO: Hardcoded buffer offset should probably automatically be determined somehow
- constexpr VkDeviceSize offsets[] = {0};
-
- vkCmdBindVertexBuffers(
- commandBuffer,
- 0,
- 1,
- vertexBuffers,
- offsets
- );
+ const auto& [width, height] = swapchain->getExtent();
- vkCmdBindIndexBuffer(
- commandBuffer,
- mesh.getIndexBuffer().getBuffer(),
- // TODO: Remove hardcoded offset
- 0,
- mesh.getIndexFormat() == IndexFormat::UNSIGNED_INT_16 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32
- );
+ commandBuffer.wait();
+ commandBuffer.reset();
- vkCmdBindDescriptorSets(
- commandBuffer,
- VK_PIPELINE_BIND_POINT_GRAPHICS,
- pipelineLayout->getLayout(),
- 0,
- descriptorSets.size(),
- descriptorSets.data(),
- 0,
- nullptr
- );
+ commandBuffer.begin(CommandBufferUsage::SIMULTANEOUS);
- // TODO: Hardcoded buffer offset should probably automatically be determined somehow
- vkCmdDrawIndexed(commandBuffer, mesh.getIndexCount(), 1, 0, 0, 0);
+ commandBuffer.transitionImage(
+ *swapchain->getColorImages()[imageIndex],
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
+ );
+ commandBuffer.transitionImage(
+ *swapchain->getDepthImages()[imageIndex],
+ VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
+ );
- vkCmdEndRenderPass(commandBuffer);
- }
+ commandBuffer.beginRenderPass(
+ width,
+ height,
+ 1,
+ {
+ {
+ .loadAction = LoadAction::Clear,
+ .storeAction = StoreAction::Store,
+ .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ .loadStoreTarget = swapchain->getColorImageViews()[imageIndex].getImageView(),
+ .resolveTarget = nullptr,
+ .clearColor = {0.0f, 0.0f, 0.0f, 0.0f},
+ .clearDepth = 0.0f,
+ .clearStencil = 0
+ }
+ },
+ swapchain->getDepthImageViews()[imageIndex].getImageView()
);
- }
- void VkRenderer::createFramebuffers() {
- const auto& imageCount = swapchain->getImageCount();
-
- depthImages.reserve(imageCount);
- depthImageViews.reserve(imageCount);
- framebuffers.reserve(imageCount);
- for (size_t i = 0; i < imageCount; i++) {
- depthImages.push_back(
- std::make_shared(
- device,
- swapchain->getExtent().width,
- swapchain->getExtent().height,
- VK_SAMPLE_COUNT_1_BIT,
- VK_FORMAT_D32_SFLOAT,
- VK_IMAGE_TILING_OPTIMAL,
- VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
- 1
- )
+ // TODO: Make material system, which will automatically bind the pipeline and descriptor sets
+ commandBuffer.record([&descriptorSets, this](const auto& cmd) {
+ pipeline->bindGraphics(cmd);
+
+ vkCmdBindDescriptorSets(
+ cmd,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ pipelineLayout->getLayout(),
+ 0,
+ descriptorSets.size(),
+ descriptorSets.data(),
+ 0,
+ nullptr
);
+ });
- depthImageViews.emplace_back(
- std::make_unique(
- depthImages[i],
- VK_IMAGE_ASPECT_DEPTH_BIT
- )
- );
+ const Rectangle& rectangle{
+ .x = 0,
+ .y = 0,
+ .width = static_cast(width),
+ .height = static_cast(height)
+ };
+ commandBuffer.setViewport(rectangle);
+ commandBuffer.setScissor(rectangle);
- framebuffers.emplace_back(
- device,
- pipeline->getRenderPass(),
- swapchain->getExtent().width,
- swapchain->getExtent().height,
- std::vector{
- swapchain->getImageViews()[i],
- depthImageViews[i]->getImageView()
- }
- );
- }
+ commandBuffer.drawMesh(mesh);
+
+ commandBuffer.endRenderPass();
+
+ commandBuffer.transitionImage(
+ *swapchain->getColorImages()[imageIndex],
+ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
+ );
+
+ commandBuffer.end();
}
}
diff --git a/src/engine/vk/VkRenderer.h b/src/engine/vk/VkRenderer.h
index 422bc70..c70d4b2 100644
--- a/src/engine/vk/VkRenderer.h
+++ b/src/engine/vk/VkRenderer.h
@@ -1,15 +1,15 @@
#pragma once
#include "Device.h"
-#include "VkBuffer.h"
#include "VkCommandPool.h"
-#include "VkFramebuffer.h"
#include "VkMesh.h"
#include "VkPipeline.h"
#include "VkPipelineLayout.h"
#include "VkSemaphore.h"
namespace Vixen::Vk {
+ class Swapchain;
+
class VkRenderer {
std::shared_ptr device;
@@ -23,12 +23,6 @@ namespace Vixen::Vk {
std::vector renderCommandBuffers;
- std::vector> depthImages;
-
- std::vector> depthImageViews;
-
- std::vector framebuffers;
-
std::vector renderFinishedSemaphores;
public:
@@ -44,17 +38,15 @@ namespace Vixen::Vk {
~VkRenderer();
void render(
- const VkMesh &mesh,
+ const VkMesh& mesh,
const std::vector<::VkDescriptorSet>& descriptorSets
);
private:
- void createFramebuffers();
-
void prepare(
- VkCommandBuffer& commandBuffer,
- VkFramebuffer& framebuffer,
- const VkMesh &mesh,
+ uint32_t imageIndex,
+ const VkCommandBuffer& commandBuffer,
+ const VkMesh& mesh,
const std::vector<::VkDescriptorSet>& descriptorSets
) const;
};
diff --git a/src/engine/vk/Vulkan.h b/src/engine/vk/Vulkan.h
index f4e6527..c83701e 100644
--- a/src/engine/vk/Vulkan.h
+++ b/src/engine/vk/Vulkan.h
@@ -4,8 +4,11 @@
#include
#include
#include
+
+#include "../LoadAction.h"
#include "../Util.h"
#include "../ShaderModule.h"
+#include "../StoreAction.h"
#ifdef DEBUG
@@ -15,8 +18,54 @@
#endif
namespace Vixen::Vk {
- template
- static void checkVulkanResult(VkResult result, const std::string &message) {
+ static bool isDepthFormat(const VkFormat format) {
+ switch (format) {
+ case VK_FORMAT_D32_SFLOAT:
+ case VK_FORMAT_D32_SFLOAT_S8_UINT:
+ case VK_FORMAT_D24_UNORM_S8_UINT:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ static VkAttachmentLoadOp toVkLoadAction(const LoadAction loadAction) {
+ switch (loadAction) {
+ case LoadAction::Load:
+ return VK_ATTACHMENT_LOAD_OP_LOAD;
+ break;
+ case LoadAction::Clear:
+ return VK_ATTACHMENT_LOAD_OP_CLEAR;
+ break;
+ case LoadAction::DontCare:
+ return VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ break;
+ }
+
+ return VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ }
+
+ static VkAttachmentStoreOp toVkStoreAction(const StoreAction storeAction) {
+ switch (storeAction) {
+ case StoreAction::Store:
+ return VK_ATTACHMENT_STORE_OP_STORE;
+ break;
+ case StoreAction::Resolve:
+ return VK_ATTACHMENT_STORE_OP_NONE;
+ break;
+ case StoreAction::StoreAndResolve:
+ return VK_ATTACHMENT_STORE_OP_STORE;
+ break;
+ case StoreAction::DontCare:
+ return VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ break;
+ }
+
+ return VK_ATTACHMENT_STORE_OP_NONE;
+ }
+
+ template
+ static void checkVulkanResult(VkResult result, const std::string& message) {
if (result != VK_SUCCESS)
error("{} ({})", message, string_VkResult(result));
}
@@ -26,15 +75,16 @@ namespace Vixen::Vk {
}
static std::string getVersionString(const uint32_t version) {
- return fmt::format("{}.{}.{}", VK_API_VERSION_MAJOR(version), VK_API_VERSION_MINOR(version), VK_API_VERSION_PATCH(version));
+ return fmt::format("{}.{}.{}", VK_API_VERSION_MAJOR(version), VK_API_VERSION_MINOR(version),
+ VK_API_VERSION_PATCH(version));
}
static VkShaderStageFlagBits getVulkanShaderStage(const ShaderModule::Stage stage) {
switch (stage) {
- case ShaderModule::Stage::VERTEX:
- return VK_SHADER_STAGE_VERTEX_BIT;
- case ShaderModule::Stage::FRAGMENT:
- return VK_SHADER_STAGE_FRAGMENT_BIT;
+ case ShaderModule::Stage::VERTEX:
+ return VK_SHADER_STAGE_VERTEX_BIT;
+ case ShaderModule::Stage::FRAGMENT:
+ return VK_SHADER_STAGE_FRAGMENT_BIT;
}
return VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM;
@@ -44,52 +94,52 @@ namespace Vixen::Vk {
static VkBool32 VKAPI_CALL vkDebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType,
- const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData,
- [[maybe_unused]] void *pUserData) {
+ const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
+ [[maybe_unused]] void* pUserData) {
spdlog::level::level_enum level;
switch (messageSeverity) {
- case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
- level = spdlog::level::trace;
- break;
- case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
- level = spdlog::level::info;
- break;
- case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
- level = spdlog::level::warn;
- break;
- case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
- level = spdlog::level::err;
- break;
- default:
- level = spdlog::level::warn;
- spdlog::warn("Unknown level flag in vkDebugCallback");
- break;
+ case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
+ level = spdlog::level::trace;
+ break;
+ case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
+ level = spdlog::level::info;
+ break;
+ case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
+ level = spdlog::level::warn;
+ break;
+ case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
+ level = spdlog::level::err;
+ break;
+ default:
+ level = spdlog::level::warn;
+ spdlog::warn("Unknown level flag in vkDebugCallback");
+ break;
}
std::string source;
switch (messageType) {
- case VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT:
- source = "Performance";
- break;
- case VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT:
- source = "Validation";
- break;
- case VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT:
- source = "General";
- break;
- default:
- source = string_VkDebugUtilsMessageTypeFlagsEXT(messageType);
- break;
+ case VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT:
+ source = "Performance";
+ break;
+ case VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT:
+ source = "Validation";
+ break;
+ case VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT:
+ source = "General";
+ break;
+ default:
+ source = string_VkDebugUtilsMessageTypeFlagsEXT(messageType);
+ break;
}
auto vkDebugLogger = spdlog::get("Vulkan");
if (vkDebugLogger == nullptr)
vkDebugLogger = spdlog::stdout_color_mt("Vulkan");
vkDebugLogger->log(
- level,
- "[{}] {}",
- fmt::format(fmt::fg(fmt::terminal_color::magenta), source),
- pCallbackData->pMessage
+ level,
+ "[{}] {}",
+ fmt::format(fmt::fg(fmt::terminal_color::magenta), source),
+ pCallbackData->pMessage
);
return VK_FALSE;
}
diff --git a/src/engine/vk/test/main.cpp b/src/engine/vk/test/main.cpp
index a95bb94..7110dc7 100644
--- a/src/engine/vk/test/main.cpp
+++ b/src/engine/vk/test/main.cpp
@@ -21,7 +21,9 @@
struct UniformBufferObject {
glm::mat4 model;
+
glm::mat4 view;
+
glm::mat4 projection;
};
@@ -72,12 +74,13 @@ int main() {
auto pipeline = Vixen::Vk::VkPipeline::Builder()
.setWidth(width)
.setHeight(height)
- .setFormat(vixen.getSwapchain()->getFormat().format)
+ .setColorFormat(vixen.getSwapchain()->getColorFormat().format)
+ .setDepthFormat(vixen.getSwapchain()->getDepthFormat())
.build(vixen.getDevice(), program);
auto renderer = std::make_unique(pipeline, vixen.getSwapchain());
- const std::string& file = "../../src/engine/vk/test/vikingroom.glb";
+ const std::string& file = "../../src/engine/vk/test/NewSponza_Main_glTF_002.gltf";
const std::string& path = std::filesystem::path(file).remove_filename().string();
Assimp::Importer importer;
@@ -130,8 +133,7 @@ int main() {
path + imagePath.C_Str()
)
);
- }
- else {
+ } else {
image = std::make_shared(
Vixen::Vk::VkImage::from(
vixen.getDevice(),
@@ -172,9 +174,7 @@ int main() {
camera.perspective(static_cast(width) / static_cast(height))
};
ubo.model = translate(ubo.model, {0.0f, -0.5f, -1.5f});
- //ubo.model = rotate(ubo.model, glm::radians(45.0f), {1.0f, 0.0f, 1.0f});
ubo.model = rotate(ubo.model, glm::radians(225.0f), {0.0f, 1.0f, 0.0f});
- //ubo.model = rotate(ubo.model, glm::radians(45.0f), {0.0f, 0.0f, 1.0f});
auto descriptorPool = std::make_shared(vixen.getDevice(), sizes, 1);
auto mvp = Vixen::Vk::VkDescriptorSet(vixen.getDevice(), descriptorPool, *program.getDescriptorSetLayout());