Attempt to add depth buffer

This commit is contained in:
Bailey Harrison 2023-03-13 20:27:47 +00:00
parent 3df5cfbc02
commit 9e7c6e923d
10 changed files with 206 additions and 59 deletions

View File

@ -31,8 +31,8 @@ namespace engine {
const gfx::DescriptorSetLayout* setZeroLayout;
const gfx::DescriptorSet* setZero;
struct SetZeroBuffer {
glm::mat4 view;
glm::mat4 proj;
glm::vec2 myValue;
};
gfx::DescriptorBuffer* setZeroBuffer;
};

View File

@ -2,12 +2,11 @@
layout( push_constant ) uniform Constants {
mat4 model;
mat4 view;
} constants;
layout(set = 0, binding = 0) uniform SetZeroBuffer {
mat4 view;
mat4 proj;
vec2 myValue;
} setZeroBuffer;
layout(location = 0) in vec3 inPosition;
@ -16,7 +15,7 @@ layout(location = 2) in vec2 inUV;
layout(location = 0) out vec2 fragUV;
void main() {
mat4 myView = constants.view;
mat4 myView = setZeroBuffer.view;
myView[3] = vec4(0.0, 0.0, 0.0, 1.0);
vec4 pos = setZeroBuffer.proj * myView * constants.model * vec4(inPosition, 1.0);
gl_Position = pos;

View File

@ -2,12 +2,11 @@
layout( push_constant ) uniform Constants {
mat4 model;
mat4 view;
} constants;
layout(set = 0, binding = 0) uniform SetZeroBuffer {
mat4 view;
mat4 proj;
vec2 myValue;
} setZeroBuffer;
layout(location = 0) in vec3 inPosition;
@ -20,12 +19,12 @@ layout(location = 2) out vec2 fragUV;
layout(location = 3) out vec3 fragLightPos;
void main() {
gl_Position = setZeroBuffer.proj * constants.view * constants.model * vec4(inPosition, 1.0);
gl_Position = setZeroBuffer.proj * setZeroBuffer.view * constants.model * vec4(inPosition, 1.0);
fragPos = vec3(constants.view * constants.model * vec4(inPosition, 1.0));
fragNorm = mat3(transpose(inverse(constants.view * constants.model))) * inNorm;
fragPos = vec3(setZeroBuffer.view * constants.model * vec4(inPosition, 1.0));
fragNorm = mat3(transpose(inverse(setZeroBuffer.view * constants.model))) * inNorm;
fragUV = inUV;
vec3 lightPos = vec3(2000.0, 2000.0, -2000.0);
fragLightPos = vec3(constants.view * vec4(lightPos, 1.0));
fragLightPos = vec3(setZeroBuffer.view * vec4(lightPos, 1.0));
}

View File

@ -78,8 +78,8 @@ namespace engine {
renderData.setZeroLayout = gfx()->createDescriptorSetLayout();
renderData.setZero = gfx()->allocateDescriptorSet(renderData.setZeroLayout);
RenderData::SetZeroBuffer initialData{
.view = glm::mat4{1.0f},
.proj = glm::perspectiveZO(glm::radians(70.0f), 1024.0f / 768.0f, 0.1f, 1000.0f),
.myValue = { 0.0f, 1.0f }
};
renderData.setZeroBuffer = gfx()->createDescriptorBuffer(sizeof(RenderData::SetZeroBuffer), &initialData);
gfx()->updateDescriptor(renderData.setZero, 0, renderData.setZeroBuffer, 0, sizeof(RenderData::SetZeroBuffer));

View File

@ -613,6 +613,7 @@ namespace engine {
pimpl->allocator = createAllocator(pimpl->instance.instance, pimpl->device.device, pimpl->device.physicalDevice);
pimpl->swapchainInfo.device = pimpl->device.device;
pimpl->swapchainInfo.allocator = pimpl->allocator;
pimpl->swapchainInfo.physicalDevice = pimpl->device.physicalDevice;
pimpl->swapchainInfo.surface = pimpl->surface;
pimpl->swapchainInfo.window = pimpl->window;

View File

@ -47,11 +47,10 @@ namespace engine {
const glm::mat4 projMatrix = glm::perspectiveZO(verticalFovRadians, m_viewportAspectRatio, m_camera.clipNear, m_camera.clipFar);
/* update SET 0 */
RenderData::SetZeroBuffer uniform{};
uniform.proj = projMatrix;
uniform.myValue.x = 1.0f;
m_value = glm::mod(m_value + ts, 1.0f);
uniform.myValue.y = m_value;
RenderData::SetZeroBuffer uniform{
.view = viewMatrix,
.proj = projMatrix
};
m_gfx->writeDescriptorBuffer(renderData.setZeroBuffer, 0, sizeof(RenderData::SetZeroBuffer), &uniform);
/* render all renderable entities */
@ -69,11 +68,9 @@ namespace engine {
struct {
glm::mat4 model;
glm::mat4 view;
} pushConsts{};
pushConsts.model = t->worldMatrix;
pushConsts.view = viewMatrix;
m_gfx->cmdBindPipeline(renderData.drawBuffer, r->material->getShader()->getPipeline());
m_gfx->cmdBindDescriptorSet(renderData.drawBuffer, r->material->getShader()->getPipeline(), renderData.setZero, 0);

View File

@ -5,10 +5,21 @@
#include <cstring>
#include <assert.h>
#include "log.hpp"
#include "device.h"
namespace engine {
static bool checkQueueFamilySupportsPresent(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t familyIndex)
{
VkBool32 supportsPresent;
VkResult res;
res = vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, static_cast<uint32_t>(familyIndex), surface, &supportsPresent);
if (res != VK_SUCCESS) throw std::runtime_error("Failed to check for queue family present support!");
return supportsPresent;
}
/* chooses a device, creates it, gets its function pointers, and creates command pools */
Device createDevice(VkInstance instance, DeviceRequirements requirements, VkSurfaceKHR surface)
{
@ -209,22 +220,33 @@ namespace engine {
for (size_t i = 0; i < queueFamilies.size(); i++) {
VkQueueFamilyProperties p = queueFamilies[i];
if (p.queueCount < 2) continue; // need one queue for presenting and one-or-more for rendering
if (p.queueCount < 2) continue; // ideally have one queue for presenting and at least one other for rendering
if (p.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
VkBool32 supportsPresent;
res = vkGetPhysicalDeviceSurfaceSupportKHR(d.physicalDevice, static_cast<uint32_t>(i), surface, &supportsPresent);
if (res != VK_SUCCESS) throw std::runtime_error("Failed to check for queue family present support!");
if (supportsPresent) {
if (checkQueueFamilySupportsPresent(d.physicalDevice, surface, i)) {
graphicsFamily = static_cast<uint32_t>(i);
break;
}
}
}
if (graphicsFamily == UINT32_MAX) throw std::runtime_error("Unable to find a graphics/present queue family!");
if (graphicsFamily == UINT32_MAX) {
for (size_t i = 0; i < queueFamilies.size(); i++) {
VkQueueFamilyProperties p = queueFamilies[i];
if (p.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
if (checkQueueFamilySupportsPresent(d.physicalDevice, surface, i)) {
graphicsFamily = static_cast<uint32_t>(i);
}
}
}
if (graphicsFamily == UINT32_MAX) {
throw std::runtime_error("Failed to find a graphics/present family!");
}
LOG_WARN("Failed to find ideal graphics/present queue family! Falling back to family #{}.", graphicsFamily);
}
// find a transfer queue family (image layout transitions, buffer upload)
uint32_t transferFamily = UINT32_MAX;
// prefer a dedicated transfer queue family
for (size_t i = 0; i < queueFamilies.size(); i++) {
VkQueueFamilyProperties p = queueFamilies[i];
if (((p.queueFlags & VK_QUEUE_TRANSFER_BIT) != 0) &&
@ -234,7 +256,10 @@ namespace engine {
break;
}
}
if (transferFamily == UINT32_MAX) throw std::runtime_error("Unable to find a transfer queue family!");
if (transferFamily == UINT32_MAX) {
transferFamily = graphicsFamily;
LOG_WARN("Failed to find a dedicated transfer queue family! Falling back to graphics family.");
}
// queue priorities
std::vector<float> graphicsQueuePriorities(queueFamilies[graphicsFamily].queueCount);
@ -242,24 +267,26 @@ namespace engine {
std::vector<float> transferQueuePriorities(queueFamilies[transferFamily].queueCount);
std::fill(transferQueuePriorities.begin(), transferQueuePriorities.end(), 1.0f);
std::array<VkDeviceQueueCreateInfo, 2> queueCreateInfos{
VkDeviceQueueCreateInfo{
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.queueFamilyIndex = graphicsFamily,
.queueCount = queueFamilies[graphicsFamily].queueCount,
.pQueuePriorities = graphicsQueuePriorities.data(),
},
VkDeviceQueueCreateInfo{
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos{};
queueCreateInfos.push_back(VkDeviceQueueCreateInfo{
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.queueFamilyIndex = graphicsFamily,
.queueCount = queueFamilies[graphicsFamily].queueCount,
.pQueuePriorities = graphicsQueuePriorities.data()
});
if (transferFamily != graphicsFamily) {
queueCreateInfos.push_back(VkDeviceQueueCreateInfo{
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.queueFamilyIndex = transferFamily,
.queueCount = queueFamilies[transferFamily].queueCount,
.pQueuePriorities = transferQueuePriorities.data(),
}
};
.pQueuePriorities = transferQueuePriorities.data()
});
}
/* create device now */
VkDeviceCreateInfo deviceCreateInfo{
@ -282,14 +309,49 @@ namespace engine {
volkLoadDevice(d.device);
vkGetDeviceQueue(d.device, graphicsFamily, 0, &d.queues.presentQueue);
d.queues.drawQueues.resize(queueFamilies[graphicsFamily].queueCount - 1);
for (uint32_t i = 0; i < d.queues.drawQueues.size(); i++) {
vkGetDeviceQueue(d.device, graphicsFamily, i + 1, &d.queues.drawQueues[i]);
}
d.queues.transferQueues.resize(queueFamilies[transferFamily].queueCount);
for (uint32_t i = 0; i < d.queues.transferQueues.size(); i++) {
vkGetDeviceQueue(d.device, transferFamily, i, &d.queues.transferQueues[i]);
if (transferFamily != graphicsFamily) {
vkGetDeviceQueue(d.device, graphicsFamily, 0, &d.queues.presentQueue);
if (queueFamilies[graphicsFamily].queueCount >= 2) {
d.queues.drawQueues.resize(queueFamilies[graphicsFamily].queueCount - 1);
for (uint32_t i = 0; i < d.queues.drawQueues.size(); i++) {
vkGetDeviceQueue(d.device, graphicsFamily, i + 1, &d.queues.drawQueues[i]);
}
} else {
d.queues.drawQueues.resize(1);
d.queues.drawQueues[0] = d.queues.presentQueue;
}
d.queues.transferQueues.resize(queueFamilies[transferFamily].queueCount);
for (uint32_t i = 0; i < d.queues.transferQueues.size(); i++) {
vkGetDeviceQueue(d.device, transferFamily, i, &d.queues.transferQueues[i]);
}
} else {
// same graphics family for graphics/present and transfer
uint32_t queueCount = queueFamilies[graphicsFamily].queueCount;
vkGetDeviceQueue(d.device, graphicsFamily, 0, &d.queues.presentQueue);
if (queueCount >= 2) {
d.queues.transferQueues.resize(1);
vkGetDeviceQueue(d.device, graphicsFamily, 1, &d.queues.transferQueues[0]);
// use the remaining queues for drawing
if (queueCount >= 3) {
d.queues.drawQueues.resize(queueCount - 2);
for (uint32_t i = 0; i < queueCount - 2; i++) {
vkGetDeviceQueue(d.device, graphicsFamily, i + 2, &d.queues.drawQueues[i]);
}
} else {
// 2 queues available
// present and drawing share a queue
// transfer gets its own queue
d.queues.drawQueues.resize(1);
d.queues.drawQueues[0] = d.queues.presentQueue;
}
} else {
// only 1 queue available :(
d.queues.transferQueues.resize(1);
d.queues.transferQueues[0] = d.queues.presentQueue;
d.queues.drawQueues.resize(1);
d.queues.drawQueues[0] = d.queues.presentQueue;
}
}
d.queues.presentAndDrawQueueFamily = graphicsFamily;

View File

@ -14,6 +14,7 @@ namespace engine {
void createSwapchain(Swapchain* sc, const SwapchainInfo& info)
{
sc->device = info.device;
sc->allocator = info.allocator;
LOG_INFO("Recreating swapchain!\n");
@ -129,6 +130,61 @@ namespace engine {
vkDestroySwapchainKHR(info.device, scInfo.oldSwapchain, nullptr);
}
{ /* create the depth buffer */
sc->depthStencil.format = VK_FORMAT_D32_SFLOAT;
if (sc->depthStencil.image != VK_NULL_HANDLE) {
vkDestroyImageView(info.device, sc->depthStencil.view, nullptr);
vmaDestroyImage(sc->allocator, sc->depthStencil.image, sc->depthStencil.allocation);
}
VkImageCreateInfo imageInfo{};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageInfo.pNext = nullptr;
imageInfo.flags = 0;
imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.format = sc->depthStencil.format;
imageInfo.extent.width = sc->extent.width;
imageInfo.extent.height = sc->extent.height;
imageInfo.mipLevels = 1;
imageInfo.arrayLayers = 1;
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageInfo.queueFamilyIndexCount = 0; // ignored
imageInfo.pQueueFamilyIndices = nullptr; // ignored
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VmaAllocationCreateInfo allocInfo{};
allocInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
allocInfo.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
allocInfo.priority = 1.0f;
res = vmaCreateImage(sc->allocator, &imageInfo, &allocInfo, &sc->depthStencil.image, &sc->depthStencil.allocation, nullptr);
if (res != VK_SUCCESS) throw std::runtime_error("Failed to create depth buffer image! Code: " + std::to_string(res));
VkImageViewCreateInfo viewInfo{};
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewInfo.pNext = nullptr;
viewInfo.flags = 0;
viewInfo.image = sc->depthStencil.image;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = sc->depthStencil.format;
viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
viewInfo.subresourceRange.baseMipLevel = 0;
viewInfo.subresourceRange.levelCount = 1;
viewInfo.subresourceRange.baseArrayLayer = 0;
viewInfo.subresourceRange.layerCount = 1;
res = vkCreateImageView(info.device, &viewInfo, nullptr, &sc->depthStencil.view);
assert(res == VK_SUCCESS);
}
/* create the render pass */
if (sc->renderpass != VK_NULL_HANDLE) {
vkDestroyRenderPass(sc->device, sc->renderpass, nullptr);
@ -144,10 +200,26 @@ namespace engine {
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
};
VkAttachmentDescription depthStencilAttachment{
.flags = 0,
.format = sc->depthStencil.format,
.samples = VK_SAMPLE_COUNT_1_BIT,
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, // the depth buffer is not used after the fragment shader
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, // ignored
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, // ignored
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
};
std::array<VkAttachmentDescription, 2> attachments { colorAttachment, depthStencilAttachment };
VkAttachmentReference colorAttachmentRef{
.attachment = 0,
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
};
VkAttachmentReference depthStencilAttachmentRef{
.attachment = 1,
.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
};
VkSubpassDescription subpass{
.flags = 0,
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
@ -156,25 +228,25 @@ namespace engine {
.colorAttachmentCount = 1,
.pColorAttachments = &colorAttachmentRef,
.pResolveAttachments = nullptr,
.pDepthStencilAttachment = nullptr,
.pDepthStencilAttachment = &depthStencilAttachmentRef,
.preserveAttachmentCount = 0,
.pPreserveAttachments = nullptr,
};
VkSubpassDependency dependency{
.srcSubpass = VK_SUBPASS_EXTERNAL,
.dstSubpass = 0,
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
.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,
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
.dependencyFlags = 0
};
VkRenderPassCreateInfo renderPassInfo{
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.attachmentCount = 1,
.pAttachments = &colorAttachment,
.attachmentCount = attachments.size(),
.pAttachments = attachments.data(),
.subpassCount = 1,
.pSubpasses = &subpass,
.dependencyCount = 1,
@ -194,9 +266,9 @@ namespace engine {
/* create image view and framebuffer for each image */
sc->images.resize(swapchainImageCount);
for (uint32_t i = 0; i < swapchainImageCount; i++) {
auto& [image, view, framebuffer] = sc->images.at(i);
auto& [image, imageView, framebuffer] = sc->images.at(i);
if (view != VK_NULL_HANDLE) vkDestroyImageView(sc->device, view, nullptr);
if (imageView != VK_NULL_HANDLE) vkDestroyImageView(sc->device, imageView, nullptr);
if (framebuffer != VK_NULL_HANDLE) vkDestroyFramebuffer(sc->device, framebuffer, nullptr);
image = swapchainImages[i];
@ -218,16 +290,20 @@ namespace engine {
viewInfo.subresourceRange.levelCount = 1;
viewInfo.subresourceRange.baseArrayLayer = 0;
viewInfo.subresourceRange.layerCount = 1;
VkResult res = vkCreateImageView(sc->device, &viewInfo, nullptr, &view);
VkResult res = vkCreateImageView(sc->device, &viewInfo, nullptr, &imageView);
if (res != VK_SUCCESS) throw std::runtime_error("Failed to create image view from swapchain image!");
std::array<VkImageView, 2> attachments {
imageView, sc->depthStencil.view
};
VkFramebufferCreateInfo fbInfo{};
fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
fbInfo.pNext = nullptr;
fbInfo.flags = 0;
fbInfo.renderPass = sc->renderpass;
fbInfo.attachmentCount = 1;
fbInfo.pAttachments = &view;
fbInfo.attachmentCount = attachments.size();
fbInfo.pAttachments = attachments.data();
fbInfo.width = sc->extent.width;
fbInfo.height = sc->extent.height;
fbInfo.layers = 1;
@ -246,7 +322,9 @@ namespace engine {
vkDestroyImageView(sc.device, view, nullptr);
}
vkDestroyRenderPass(sc.device, sc.renderpass, nullptr);
vkDestroyImageView(sc.device, sc.depthStencil.view, nullptr);
vmaDestroyImage(sc.allocator, sc.depthStencil.image, sc.depthStencil.allocation);
vkDestroySwapchainKHR(sc.device, sc.swapchain, nullptr);
}
}
}

View File

@ -1,22 +1,32 @@
#pragma once
#include <tuple>
#include <vector>
#include <SDL2/SDL_vulkan.h>
#include <volk.h>
#include <vk_mem_alloc.h>
namespace engine {
struct Swapchain {
VkSwapchainKHR swapchain = VK_NULL_HANDLE;
VkDevice device = VK_NULL_HANDLE; // the associated device
VmaAllocator allocator = VK_NULL_HANDLE; // the associated allocator
VkSurfaceFormatKHR surfaceFormat{};
VkSurfaceCapabilitiesKHR surfaceCapabilities{};
VkPresentModeKHR presentMode{};
VkExtent2D extent{};
VkRenderPass renderpass = VK_NULL_HANDLE;
std::vector<std::tuple<VkImage, VkImageView, VkFramebuffer>> images{};
struct DepthStencil {
VkImage image = VK_NULL_HANDLE;
VmaAllocation allocation = VK_NULL_HANDLE;
VkImageView view = VK_NULL_HANDLE;
VkFormat format{};
} depthStencil{};
};
struct SwapchainInfo {
@ -24,6 +34,7 @@ namespace engine {
VkPhysicalDevice physicalDevice;
VkSurfaceKHR surface;
SDL_Window* window;
VmaAllocator allocator;
bool vsync;
bool waitForPresent;
};

View File

@ -107,7 +107,7 @@ void playGame(bool enableFrameLimiter)
/* cube */
{
uint32_t cube = myScene->createEntity("cube");
myScene->getComponent<engine::TransformComponent>(cube)->position = glm::vec3{ -0.5f, -0.5f, -0.5f };
myScene->getComponent<engine::TransformComponent>(cube)->position = glm::vec3{ -0.5f, -0.5f + 5.0f, -0.5f };
auto cubeRenderable = myScene->addComponent<engine::RenderableComponent>(cube);
cubeRenderable->material = std::make_shared<engine::resources::Material>(app.getResource<engine::resources::Shader>("builtin.standard"));
cubeRenderable->mesh = genCuboidMesh(app.gfx(), 1.0f, 1.0f, 1.0f, 1);