diff --git a/CMakePresets.json b/CMakePresets.json index 703d9d8..97e9e13 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -1,27 +1,27 @@ { - "version": 2, - "configurePresets": [ - { - "name": "default", - "generator": "Ninja", - "binaryDir": "${sourceDir}/build", - "cacheVariables": { - "CMAKE_EXPORT_COMPILE_COMMANDS": true, - "CMAKE_MAKE_PROGRAM": "ninja", - "CMAKE_C_COMPILER": "/usr/bin/clang", - "CMAKE_CXX_COMPILER": "/usr/bin/clang++", - "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/vcpkg/scripts/buildsystems/vcpkg.cmake" - } - }, - { - "name": "windows", - "generator": "Ninja", - "binaryDir": "${sourceDir}/build", - "cacheVariables": { - "CMAKE_EXPORT_COMPILE_COMMANDS": true, - "CMAKE_MAKE_PROGRAM": "ninja", - "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/vcpkg/scripts/buildsystems/vcpkg.cmake" - } - } - ] + "version": 2, + "configurePresets": [ + { + "name": "linux", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build", + "cacheVariables": { + "CMAKE_EXPORT_COMPILE_COMMANDS": true, + "CMAKE_MAKE_PROGRAM": "ninja", + "CMAKE_C_COMPILER": "/usr/bin/clang", + "CMAKE_CXX_COMPILER": "/usr/bin/clang++", + "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/vcpkg/scripts/buildsystems/vcpkg.cmake" + } + }, + { + "name": "windows", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build", + "cacheVariables": { + "CMAKE_EXPORT_COMPILE_COMMANDS": true, + "CMAKE_MAKE_PROGRAM": "ninja", + "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/vcpkg/scripts/buildsystems/vcpkg.cmake" + } + } + ] } diff --git a/aster/config.h b/aster/config.h index 54a022d..1c37123 100644 --- a/aster/config.h +++ b/aster/config.h @@ -12,6 +12,7 @@ #define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1 #define VULKAN_HPP_NO_STRUCT_CONSTRUCTORS #define VULKAN_HPP_DISABLE_ENHANCED_MODE 1 +#define VULKAN_HPP_NO_EXCEPTIONS 1 #define VMA_STATIC_VULKAN_FUNCTIONS 0 #define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 diff --git a/aster/pipeline.cpp b/aster/pipeline.cpp index a6ca175..c9c9a89 100644 --- a/aster/pipeline.cpp +++ b/aster/pipeline.cpp @@ -7,15 +7,22 @@ #include "device.h" -Pipeline::Pipeline(const Device *device, vk::PipelineLayout layout, vk::Pipeline pipeline) +Pipeline::Pipeline(const Device *device, vk::PipelineLayout layout, vk::Pipeline pipeline, + eastl::vector &&setLayouts) : m_Device(device) , m_Layout(layout) , m_Pipeline(pipeline) + , m_SetLayouts(std::move(setLayouts)) { } Pipeline::~Pipeline() { + for (const auto setLayout : m_SetLayouts) + { + m_Device->m_Device.destroy(setLayout, nullptr); + } + m_SetLayouts.clear(); m_Device->m_Device.destroy(m_Pipeline, nullptr); m_Device->m_Device.destroy(m_Layout, nullptr); } \ No newline at end of file diff --git a/aster/pipeline.h b/aster/pipeline.h index 4376ed8..d887f47 100644 --- a/aster/pipeline.h +++ b/aster/pipeline.h @@ -7,6 +7,8 @@ #include "global.h" +#include + struct Device; struct Pipeline @@ -14,7 +16,9 @@ struct Pipeline const Device *m_Device; vk::PipelineLayout m_Layout; vk::Pipeline m_Pipeline; + eastl::vector m_SetLayouts; - Pipeline(const Device *device, vk::PipelineLayout layout, vk::Pipeline pipeline); + Pipeline(const Device *device, vk::PipelineLayout layout, vk::Pipeline pipeline, + eastl::vector &&setLayouts); ~Pipeline(); }; \ No newline at end of file diff --git a/samples/00_util/helpers.h b/samples/00_util/helpers.h index 99c12db..1b21bf3 100644 --- a/samples/00_util/helpers.h +++ b/samples/00_util/helpers.h @@ -9,6 +9,7 @@ #include "queue_allocation.h" #include +#include struct PhysicalDevice; class PhysicalDevices; diff --git a/samples/01_triangle/triangle.cpp b/samples/01_triangle/triangle.cpp index e0d348c..53798db 100644 --- a/samples/01_triangle/triangle.cpp +++ b/samples/01_triangle/triangle.cpp @@ -27,8 +27,8 @@ Pipeline CreatePipeline(const Device *device, const Swapchain *swapchain); struct Vertex { - float m_Position[4]; - float m_Color[4]; + vec3 m_Position; + vec3 m_Color; constexpr static vk::VertexInputBindingDescription GetBinding(const u32 binding) @@ -43,13 +43,13 @@ struct Vertex vk::VertexInputAttributeDescription{ .location = 0, .binding = binding, - .format = vk::Format::eR32G32B32A32Sfloat, + .format = vk::Format::eR32G32B32Sfloat, .offset = offsetof(Vertex, m_Position), }, vk::VertexInputAttributeDescription{ .location = 1, .binding = binding, - .format = vk::Format::eR32G32B32A32Sfloat, + .format = vk::Format::eR32G32B32Sfloat, .offset = offsetof(Vertex, m_Color), }, }; @@ -60,14 +60,13 @@ struct Frame { const Device *m_Device; vk::CommandPool m_Pool; + vk::CommandBuffer m_CommandBuffer; vk::Fence m_FrameAvailableFence; vk::Semaphore m_ImageAcquireSem; vk::Semaphore m_RenderFinishSem; Frame(const Device *device, u32 queueFamilyIndex, u32 frameCount); ~Frame(); - - [[nodiscard]] vk::CommandBuffer AllocateCommandBuffer() const; }; int @@ -86,11 +85,8 @@ main(int, char **) Features enabledDeviceFeatures = {.m_Vulkan13Features = {.dynamicRendering = true}}; QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse); Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"}; - vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0); - Swapchain swapchain = {&window, &device, "Primary Chain"}; - Pipeline pipeline = CreatePipeline(&device, &swapchain); vk::CommandPool copyPool; @@ -113,9 +109,9 @@ main(int, char **) // eastl::array vertices{}; eastl::array vertices = { - Vertex{.m_Position = {-0.5f, -0.5f, 0.0f, 1.0f}, .m_Color = {1.0f, 0.0f, 0.0f, 1.0f}}, - Vertex{.m_Position = {0.5f, -0.5f, 0.0f, 1.0f}, .m_Color = {0.0f, 1.0f, 0.0f, 1.0f}}, - Vertex{.m_Position = {0.0f, 0.5f, 0.0f, 1.0f}, .m_Color = {0.0f, 0.0f, 1.0f, 1.0f}}, + Vertex{.m_Position = {-0.5f, -0.5f, 0.0f}, .m_Color = {1.0f, 0.0f, 0.0f}}, + Vertex{.m_Position = {0.5f, -0.5f, 0.0f}, .m_Color = {0.0f, 1.0f, 0.0f}}, + Vertex{.m_Position = {0.0f, 0.5f, 0.0f}, .m_Color = {0.0f, 0.0f, 1.0f}}, }; VertexBuffer vbo; vbo.Init(&device, vertices.size() * sizeof vertices[0], "VBO"); @@ -243,7 +239,7 @@ main(int, char **) vk::ImageView currentImageView = swapchain.m_ImageViews[imageIndex]; vk::Image currentImage = swapchain.m_Images[imageIndex]; - vk::CommandBuffer cmd = currentFrame->AllocateCommandBuffer(); + vk::CommandBuffer cmd = currentFrame->m_CommandBuffer; topOfThePipeBarrier.image = currentImage; renderToPresentBarrier.image = currentImage; @@ -369,21 +365,14 @@ Frame::Frame(const Device *device, const u32 queueFamilyIndex, const u32 frameCo ERROR_IF(Failed(result), "Could not create RF semaphore for frame {}. Cause: {}", frameCount, result) THEN_ABORT(result); - DEBUG("Frame {} created successfully.", frameCount); -} - -vk::CommandBuffer -Frame::AllocateCommandBuffer() const -{ const vk::CommandBufferAllocateInfo allocateInfo = { .commandPool = m_Pool, .level = vk::CommandBufferLevel::ePrimary, .commandBufferCount = 1}; - vk::CommandBuffer commandBuffer; - vk::Result result = m_Device->m_Device.allocateCommandBuffers(&allocateInfo, &commandBuffer); + result = m_Device->m_Device.allocateCommandBuffers(&allocateInfo, &m_CommandBuffer); ERROR_IF(Failed(result), "Command buffer allocation failed. Cause: {}", result) THEN_ABORT(result); - return commandBuffer; + DEBUG("Frame {} created successfully.", frameCount); } Pipeline @@ -509,7 +498,7 @@ CreatePipeline(const Device *device, const Swapchain *swapchain) device->m_Device.destroy(vertexShaderModule, nullptr); device->m_Device.destroy(fragmentShaderModule, nullptr); - return {device, pipelineLayout, pipeline}; + return {device, pipelineLayout, pipeline, {}}; } vk::ShaderModule diff --git a/samples/02_box/CMakeLists.txt b/samples/02_box/CMakeLists.txt new file mode 100644 index 0000000..442b741 --- /dev/null +++ b/samples/02_box/CMakeLists.txt @@ -0,0 +1,12 @@ +# CMakeList.txt ; CMake project for box + +cmake_minimum_required(VERSION 3.13) + +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fsanitize=address") + +add_executable(box box.cpp) +add_shader(box shader/box.vert.glsl) +add_shader(box shader/box.frag.glsl) + +target_link_libraries(box PRIVATE aster_core) +target_link_libraries(box PRIVATE util_helper) diff --git a/samples/02_box/box.cpp b/samples/02_box/box.cpp new file mode 100644 index 0000000..16e2623 --- /dev/null +++ b/samples/02_box/box.cpp @@ -0,0 +1,604 @@ +// ============================================= +// Aster: box.cpp +// Copyright (c) 2020-2024 Anish Bhobe +// ============================================= + +#include "buffer.h" +#include "constants.h" +#include "context.h" +#include "device.h" +#include "physical_device.h" +#include "window.h" + +#include "global.h" +#include "pipeline.h" +#include "swapchain.h" + +#include "helpers.h" + +#include + +constexpr u32 MAX_FRAMES_IN_FLIGHT = 3; +constexpr auto VERTEX_SHADER_FILE = "shader/box.vert.glsl.spv"; +constexpr auto FRAGMENT_SHADER_FILE = "shader/box.frag.glsl.spv"; + +#define AbortIfFailed(RESULT) \ + do \ + { \ + vk::Result _checkResultValue_; \ + ERROR_IF(Failed(_checkResultValue_ = Cast(RESULT)), "Cause: {}", _checkResultValue_) \ + THEN_ABORT(_checkResultValue_); \ + } while (false) + +#define AbortIfFailedMV(RESULT, MSG, EXTRA) \ + do \ + { \ + vk::Result _checkResultValue_; \ + ERROR_IF(Failed(_checkResultValue_ = Cast(RESULT)), MSG " Cause: {}", EXTRA, _checkResultValue_) \ + THEN_ABORT(_checkResultValue_); \ + } while (false) + +#define AbortIfFailedM(RESULT, MSG) \ + do \ + { \ + auto _checkResultValue_ = Cast(RESULT); \ + ERROR_IF(Failed(_checkResultValue_), MSG " Cause: {}", _checkResultValue_) THEN_ABORT(_checkResultValue_); \ + } while (false) + +vk::ShaderModule CreateShader(const Device *device, cstr shaderFile); +Pipeline CreatePipeline(const Device *device, const Swapchain *swapchain); + +struct Vertex +{ + vec3 m_Position; + vec3 m_Color; + + constexpr static vk::VertexInputBindingDescription + GetBinding(const u32 binding) + { + return {.binding = binding, .stride = sizeof(Vertex), .inputRate = vk::VertexInputRate::eVertex}; + } + + constexpr static eastl::array + GetAttributes(const u32 binding) + { + return { + vk::VertexInputAttributeDescription{ + .location = 0, + .binding = binding, + .format = vk::Format::eR32G32B32Sfloat, + .offset = offsetof(Vertex, m_Position), + }, + vk::VertexInputAttributeDescription{ + .location = 1, + .binding = binding, + .format = vk::Format::eR32G32B32Sfloat, + .offset = offsetof(Vertex, m_Color), + }, + }; + } +}; + +struct Camera +{ + mat4 m_Model; + mat4 m_View; + mat4 m_Perspective; +}; + +struct Frame +{ + const Device *m_Device; + vk::CommandPool m_Pool; + vk::CommandBuffer m_CommandBuffer; + vk::Fence m_FrameAvailableFence; + vk::Semaphore m_ImageAcquireSem; + vk::Semaphore m_RenderFinishSem; + + Frame(const Device *device, u32 queueFamilyIndex, u32 frameCount); + ~Frame(); +}; + +int +main(int, char **) +{ + MIN_LOG_LEVEL(Logger::LogType::eInfo); + + Context context = {"Box", VERSION}; + Window window = {"Box (Aster)", &context, {640, 480}}; + + PhysicalDevices physicalDevices = {&window, &context}; + PhysicalDevice deviceToUse = FindSuitableDevice(physicalDevices); + + INFO("Using {} as the primary device.", deviceToUse.m_DeviceProperties.deviceName.data()); + + Features enabledDeviceFeatures = {.m_Vulkan13Features = {.dynamicRendering = true}}; + QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse); + Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"}; + vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0); + Swapchain swapchain = {&window, &device, "Primary Chain"}; + Pipeline pipeline = CreatePipeline(&device, &swapchain); + + Camera camera = { + .m_Model = {1.0f}, + .m_View = glm::lookAt(vec3(-1.0f, 0.0f, 1.0f), vec3(0.0f), vec3(0.0f, 1.0f, 0.0f)), + .m_Perspective = glm::perspective( + 70_deg, Cast(swapchain.m_Extent.width) / Cast(swapchain.m_Extent.height), 0.1f, 100.0f), + }; + + vk::DescriptorPool descriptorPool; + vk::DescriptorSet descriptorSet; + { + vk::DescriptorSetLayout descriptorSetLayout = pipeline.m_SetLayouts.front(); + vk::DescriptorPoolSize poolSize = { + .type = vk::DescriptorType::eUniformBuffer, + .descriptorCount = 1, + }; + vk::DescriptorPoolCreateInfo descriptorPoolCreateInfo = { + .maxSets = 1, .poolSizeCount = 1, .pPoolSizes = &poolSize}; + AbortIfFailed(device.m_Device.createDescriptorPool(&descriptorPoolCreateInfo, nullptr, &descriptorPool)); + + vk::DescriptorSetAllocateInfo descriptorSetAllocateInfo = { + .descriptorPool = descriptorPool, + .descriptorSetCount = 1, + .pSetLayouts = &descriptorSetLayout, + }; + AbortIfFailed(device.m_Device.allocateDescriptorSets(&descriptorSetAllocateInfo, &descriptorSet)); + } + + vk::CommandPool copyPool; + vk::CommandBuffer copyBuffer; + { + vk::CommandPoolCreateInfo poolCreateInfo = { + .flags = vk::CommandPoolCreateFlagBits::eTransient, + .queueFamilyIndex = queueAllocation.m_Family, + }; + AbortIfFailedM(device.m_Device.createCommandPool(&poolCreateInfo, nullptr, ©Pool), + "Copy command pool creation failed."); + vk::CommandBufferAllocateInfo bufferAllocateInfo = { + .commandPool = copyPool, + .level = vk::CommandBufferLevel::ePrimary, + .commandBufferCount = 1, + }; + AbortIfFailedM(device.m_Device.allocateCommandBuffers(&bufferAllocateInfo, ©Buffer), + "Copy command buffer allocation failed."); + } + + // eastl::array vertices{}; + eastl::array vertices = { + Vertex{.m_Position = {-0.5f, -0.5f, 0.0f}, .m_Color = {1.0f, 0.0f, 0.0f}}, + Vertex{.m_Position = {0.5f, -0.5f, 0.0f}, .m_Color = {0.0f, 1.0f, 0.0f}}, + Vertex{.m_Position = {0.0f, 0.5f, 0.0f}, .m_Color = {0.0f, 0.0f, 1.0f}}, + }; + VertexBuffer vbo; + vbo.Init(&device, vertices.size() * sizeof vertices[0], "VBO"); + { + StagingBuffer staging; + staging.Init(&device, vertices.size() * sizeof vertices[0], "Staging"); + staging.Write(&device, 0, vertices.size() * sizeof vertices[0], vertices.data()); + + vk::Fence fence; + vk::FenceCreateInfo fenceCreateInfo = {}; + AbortIfFailed(device.m_Device.createFence(&fenceCreateInfo, nullptr, &fence)); + + vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit}; + AbortIfFailed(copyBuffer.begin(&beginInfo)); + + vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0, .size = staging.GetSize()}; + copyBuffer.copyBuffer(staging.m_Buffer, vbo.m_Buffer, 1, &bufferCopy); + + AbortIfFailed(copyBuffer.end()); + + vk::SubmitInfo submitInfo = { + .commandBufferCount = 1, + .pCommandBuffers = ©Buffer, + }; + + AbortIfFailed(commandQueue.submit(1, &submitInfo, fence)); + INFO("Submit copy"); + + AbortIfFailed(device.m_Device.waitForFences(1, &fence, true, MaxValue)); + INFO("Fence wait"); + + AbortIfFailedM(device.m_Device.resetCommandPool(copyPool, {}), "Couldn't reset command pool."); + + device.m_Device.destroy(fence, nullptr); + staging.Destroy(&device); + } + + UniformBuffer ubo; + ubo.Init(&device, sizeof camera, "Camera UBO"); + ubo.Write(&device, 0, sizeof camera, &camera); + vk::DescriptorBufferInfo descriptorBufferInfo = { + .buffer = ubo.m_Buffer, + .offset = 0, + .range = ubo.GetSize(), + }; + vk::WriteDescriptorSet writeDescriptors = { + .dstSet = descriptorSet, + .dstBinding = 0, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = vk::DescriptorType::eUniformBuffer, + .pBufferInfo = &descriptorBufferInfo, + }; + device.m_Device.updateDescriptorSets(1, &writeDescriptors, 0, nullptr); + + // Persistent variables + vk::Viewport viewport = { + .x = 0, + .y = Cast(swapchain.m_Extent.height), + .width = Cast(swapchain.m_Extent.width), + .height = -Cast(swapchain.m_Extent.height), + .minDepth = 0.0, + .maxDepth = 1.0, + }; + + vk::Rect2D scissor = { + .offset = {0, 0}, + .extent = swapchain.m_Extent, + }; + + vk::ImageSubresourceRange subresourceRange = { + .aspectMask = vk::ImageAspectFlagBits::eColor, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }; + vk::ImageMemoryBarrier topOfThePipeBarrier = { + .oldLayout = vk::ImageLayout::eUndefined, + .newLayout = vk::ImageLayout::eColorAttachmentOptimal, + .srcQueueFamilyIndex = queueAllocation.m_Family, + .dstQueueFamilyIndex = queueAllocation.m_Family, + .subresourceRange = subresourceRange, + }; + vk::ImageMemoryBarrier renderToPresentBarrier = { + .oldLayout = vk::ImageLayout::eColorAttachmentOptimal, + .newLayout = vk::ImageLayout::ePresentSrcKHR, + .srcQueueFamilyIndex = queueAllocation.m_Family, + .dstQueueFamilyIndex = queueAllocation.m_Family, + .subresourceRange = subresourceRange, + }; + + // Frames + eastl::fixed_vector frames; + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) + { + frames.emplace_back(&device, queueAllocation.m_Family, i); + } + + Time::Init(); + + INFO("Starting loop"); + u32 frameIndex = 0; + while (window.Poll()) + { + Frame *currentFrame = &frames[frameIndex]; + Time::Update(); + + camera.m_Model *= rotate(mat4{1.0f}, Cast(45.0_deg * Time::m_Delta), vec3(0.0f, 1.0f, 0.0f)); + ubo.Write(&device, 0, sizeof camera, &camera); + + AbortIfFailedMV(device.m_Device.waitForFences(1, ¤tFrame->m_FrameAvailableFence, true, MaxValue), + "Waiting for fence {} failed.", frameIndex); + + u32 imageIndex; + auto result = device.m_Device.acquireNextImageKHR(swapchain.m_Swapchain, MaxValue, + currentFrame->m_ImageAcquireSem, nullptr, &imageIndex); + if (Failed(result)) + { + switch (result) + { + case vk::Result::eErrorOutOfDateKHR: + case vk::Result::eSuboptimalKHR: + INFO("Recreating Swapchain. Cause: {}", result); + swapchain.Create(&window); + viewport.y = Cast(swapchain.m_Extent.height); + viewport.width = Cast(swapchain.m_Extent.width); + viewport.height = -Cast(swapchain.m_Extent.height); + scissor.extent = swapchain.m_Extent; + continue; // Image acquire has failed. We move to the next frame. + default: + AbortIfFailedMV(result, "Waiting for swapchain image {} failed.", frameIndex); + } + } + // Reset fences here. In case swapchain was out of date, we leave the fences signalled. + AbortIfFailedMV(device.m_Device.resetFences(1, ¤tFrame->m_FrameAvailableFence), "Fence {} reset failed.", + frameIndex); + + AbortIfFailedMV(device.m_Device.resetCommandPool(currentFrame->m_Pool, {}), "Command pool {} reset failed.", + frameIndex); + + vk::ImageView currentImageView = swapchain.m_ImageViews[imageIndex]; + vk::Image currentImage = swapchain.m_Images[imageIndex]; + vk::CommandBuffer cmd = currentFrame->m_CommandBuffer; + + topOfThePipeBarrier.image = currentImage; + renderToPresentBarrier.image = currentImage; + + vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit}; + AbortIfFailed(cmd.begin(&beginInfo)); + + cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eColorAttachmentOutput, + {}, 0, nullptr, 0, nullptr, 1, &topOfThePipeBarrier); + + // Render + vk::RenderingAttachmentInfo attachmentInfo = { + .imageView = currentImageView, + .imageLayout = vk::ImageLayout::eColorAttachmentOptimal, + .resolveMode = vk::ResolveModeFlagBits::eNone, + .loadOp = vk::AttachmentLoadOp::eClear, + .storeOp = vk::AttachmentStoreOp::eStore, + .clearValue = vk::ClearColorValue{0.0f, 0.0f, 0.0f, 1.0f}, + }; + + vk::RenderingInfo renderingInfo = { + .renderArea = {.extent = swapchain.m_Extent}, + .layerCount = 1, + .colorAttachmentCount = 1, + .pColorAttachments = &attachmentInfo, + }; + + cmd.beginRendering(&renderingInfo); + + cmd.setViewport(0, 1, &viewport); + cmd.setScissor(0, 1, &scissor); + cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.m_Pipeline); + cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 0, 1, &descriptorSet, 0, nullptr); + usize offsets = 0; + cmd.bindVertexBuffers(0, 1, &vbo.m_Buffer, &offsets); + cmd.draw(3, 1, 0, 0); + + cmd.endRendering(); + + cmd.pipelineBarrier(vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eBottomOfPipe, + {}, 0, nullptr, 0, nullptr, 1, &renderToPresentBarrier); + + AbortIfFailed(cmd.end()); + + vk::PipelineStageFlags waitDstStage = vk::PipelineStageFlagBits::eColorAttachmentOutput; + vk::SubmitInfo submitInfo = { + .waitSemaphoreCount = 1, + .pWaitSemaphores = ¤tFrame->m_ImageAcquireSem, + .pWaitDstStageMask = &waitDstStage, + .commandBufferCount = 1, + .pCommandBuffers = &cmd, + .signalSemaphoreCount = 1, + .pSignalSemaphores = ¤tFrame->m_RenderFinishSem, + }; + AbortIfFailed(commandQueue.submit(1, &submitInfo, currentFrame->m_FrameAvailableFence)); + + vk::PresentInfoKHR presentInfo = { + .waitSemaphoreCount = 1, + .pWaitSemaphores = ¤tFrame->m_RenderFinishSem, + .swapchainCount = 1, + .pSwapchains = &swapchain.m_Swapchain, + .pImageIndices = &imageIndex, + .pResults = nullptr, + }; + result = commandQueue.presentKHR(&presentInfo); + if (Failed(result)) + { + switch (result) + { + case vk::Result::eErrorOutOfDateKHR: + case vk::Result::eSuboptimalKHR: + INFO("Recreating Swapchain. Cause: {}", result); + swapchain.Create(&window); + viewport.y = Cast(swapchain.m_Extent.height); + viewport.width = Cast(swapchain.m_Extent.width); + viewport.height = -Cast(swapchain.m_Extent.height); + scissor.extent = swapchain.m_Extent; + break; // Present failed. We redo the frame. + default: + AbortIfFailedM(result, "Swapchain Present failed."); + } + } + frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; + } + + AbortIfFailed(device.m_Device.waitIdle()); + + ubo.Destroy(&device); + device.m_Device.destroy(descriptorPool, nullptr); + device.m_Device.destroy(copyPool, nullptr); + vbo.Destroy(&device); + + return 0; +} + +Frame::Frame(const Device *device, const u32 queueFamilyIndex, const u32 frameCount) +{ + m_Device = device; + + const vk::CommandPoolCreateInfo commandPoolCreateInfo = { + .flags = vk::CommandPoolCreateFlagBits::eTransient, + .queueFamilyIndex = queueFamilyIndex, + }; + AbortIfFailedMV(device->m_Device.createCommandPool(&commandPoolCreateInfo, nullptr, &m_Pool), + "Could not command pool for frame {}", frameCount); + + constexpr vk::FenceCreateInfo fenceCreateInfo = {.flags = vk::FenceCreateFlagBits::eSignaled}; + AbortIfFailedMV(device->m_Device.createFence(&fenceCreateInfo, nullptr, &m_FrameAvailableFence), + "Could not create a fence for frame {}", frameCount); + + constexpr vk::SemaphoreCreateInfo semaphoreCreateInfo = {}; + AbortIfFailedMV(device->m_Device.createSemaphore(&semaphoreCreateInfo, nullptr, &m_ImageAcquireSem), + "Could not create IA semaphore for frame {}.", frameCount); + AbortIfFailedMV(device->m_Device.createSemaphore(&semaphoreCreateInfo, nullptr, &m_RenderFinishSem), + "Could not create RF semaphore for frame {}.", frameCount); + + const vk::CommandBufferAllocateInfo allocateInfo = { + .commandPool = m_Pool, + .level = vk::CommandBufferLevel::ePrimary, + .commandBufferCount = 1, + }; + + AbortIfFailed(m_Device->m_Device.allocateCommandBuffers(&allocateInfo, &m_CommandBuffer)); + + DEBUG("Frame {} created successfully.", frameCount); +} + +Pipeline +CreatePipeline(const Device *device, const Swapchain *swapchain) +{ + // Pipeline Setup + auto vertexShaderModule = CreateShader(device, VERTEX_SHADER_FILE); + auto fragmentShaderModule = CreateShader(device, FRAGMENT_SHADER_FILE); + + eastl::array shaderStages = {{ + { + .stage = vk::ShaderStageFlagBits::eVertex, + .module = vertexShaderModule, + .pName = "main", + }, + { + .stage = vk::ShaderStageFlagBits::eFragment, + .module = fragmentShaderModule, + .pName = "main", + }, + }}; + + vk::DescriptorSetLayoutBinding descriptorSetLayoutBinding = { + .binding = 0, + .descriptorType = vk::DescriptorType::eUniformBuffer, + .descriptorCount = 1, + .stageFlags = vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment, + }; + vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = { + .bindingCount = 1, + .pBindings = &descriptorSetLayoutBinding, + }; + vk::DescriptorSetLayout descriptorSetLayout; + AbortIfFailed( + device->m_Device.createDescriptorSetLayout(&descriptorSetLayoutCreateInfo, nullptr, &descriptorSetLayout)); + + vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = { + .setLayoutCount = 1, + .pSetLayouts = &descriptorSetLayout, + .pushConstantRangeCount = 0, + .pPushConstantRanges = nullptr, + }; + vk::PipelineLayout pipelineLayout; + AbortIfFailed(device->m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &pipelineLayout)); + device->SetName(pipelineLayout, "Box Layout"); + + vk::VertexInputBindingDescription inputBindingDescription = Vertex::GetBinding(0); + auto inputAttributeDescription = Vertex::GetAttributes(0); + + vk::PipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = { + .vertexBindingDescriptionCount = 1, + .pVertexBindingDescriptions = &inputBindingDescription, + .vertexAttributeDescriptionCount = Cast(inputAttributeDescription.size()), + .pVertexAttributeDescriptions = inputAttributeDescription.data(), + }; + vk::PipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = { + .topology = vk::PrimitiveTopology::eTriangleList, + .primitiveRestartEnable = false, + }; + + vk::PipelineViewportStateCreateInfo viewportStateCreateInfo = { + .viewportCount = 1, + .scissorCount = 1, + }; + + vk::PipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = { + .depthClampEnable = false, + .rasterizerDiscardEnable = false, + .polygonMode = vk::PolygonMode::eFill, + .cullMode = vk::CullModeFlagBits::eNone, + .frontFace = vk::FrontFace::eCounterClockwise, + .depthBiasEnable = false, + .lineWidth = 1.0, + }; + vk::PipelineMultisampleStateCreateInfo multisampleStateCreateInfo = { + .rasterizationSamples = vk::SampleCountFlagBits::e1, + .sampleShadingEnable = false, + }; + vk::PipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo = { + .depthTestEnable = false, + .depthWriteEnable = false, + }; + vk::PipelineColorBlendAttachmentState colorBlendAttachmentState = { + .blendEnable = false, + .srcColorBlendFactor = vk::BlendFactor::eSrcColor, + .dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcColor, + .colorBlendOp = vk::BlendOp::eAdd, + .srcAlphaBlendFactor = vk::BlendFactor::eSrcAlpha, + .dstAlphaBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha, + .alphaBlendOp = vk::BlendOp::eAdd, + .colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | + vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA, + }; + vk::PipelineColorBlendStateCreateInfo colorBlendStateCreateInfo = { + .logicOpEnable = false, + .attachmentCount = 1, + .pAttachments = &colorBlendAttachmentState, + }; + + eastl::array dynamicStates = { + vk::DynamicState::eScissor, + vk::DynamicState::eViewport, + }; + + vk::PipelineDynamicStateCreateInfo dynamicStateCreateInfo = { + .dynamicStateCount = Cast(dynamicStates.size()), + .pDynamicStates = dynamicStates.data(), + }; + + vk::PipelineRenderingCreateInfo renderingCreateInfo = { + .viewMask = 0, + .colorAttachmentCount = 1, + .pColorAttachmentFormats = &swapchain->m_Format, + }; + + vk::GraphicsPipelineCreateInfo pipelineCreateInfo = { + .pNext = &renderingCreateInfo, + .stageCount = Cast(shaderStages.size()), + .pStages = shaderStages.data(), + .pVertexInputState = &vertexInputStateCreateInfo, + .pInputAssemblyState = &inputAssemblyStateCreateInfo, + .pViewportState = &viewportStateCreateInfo, + .pRasterizationState = &rasterizationStateCreateInfo, + .pMultisampleState = &multisampleStateCreateInfo, + .pDepthStencilState = &depthStencilStateCreateInfo, + .pColorBlendState = &colorBlendStateCreateInfo, + .pDynamicState = &dynamicStateCreateInfo, + .layout = pipelineLayout, + }; + vk::Pipeline pipeline; + AbortIfFailed(device->m_Device.createGraphicsPipelines(nullptr, 1, &pipelineCreateInfo, nullptr, &pipeline)); + device->SetName(pipeline, "Box Pipeline"); + + device->m_Device.destroy(vertexShaderModule, nullptr); + device->m_Device.destroy(fragmentShaderModule, nullptr); + + return {device, pipelineLayout, pipeline, {descriptorSetLayout}}; +} + +vk::ShaderModule +CreateShader(const Device *device, cstr shaderFile) +{ + eastl::vector shaderCode = ReadFile(shaderFile); + + const vk::ShaderModuleCreateInfo shaderModuleCreateInfo = { + .codeSize = shaderCode.size() * sizeof(u32), + .pCode = shaderCode.data(), + }; + vk::ShaderModule shaderModule; + + AbortIfFailedMV(device->m_Device.createShaderModule(&shaderModuleCreateInfo, nullptr, &shaderModule), + "Shader {} could not be created.", shaderFile); + return shaderModule; +} + +Frame::~Frame() +{ + m_Device->m_Device.destroy(m_RenderFinishSem, nullptr); + m_Device->m_Device.destroy(m_ImageAcquireSem, nullptr); + m_Device->m_Device.destroy(m_FrameAvailableFence, nullptr); + m_Device->m_Device.destroy(m_Pool, nullptr); + + DEBUG("Destoryed Frame"); +} \ No newline at end of file diff --git a/samples/02_box/shader/box.frag.glsl b/samples/02_box/shader/box.frag.glsl new file mode 100644 index 0000000..f85d053 --- /dev/null +++ b/samples/02_box/shader/box.frag.glsl @@ -0,0 +1,9 @@ +#version 450 +#pragma shader_stage(fragment) + +layout (location = 0) in vec3 inColor; +layout (location = 0) out vec4 outColor; + +void main() { + outColor = vec4(inColor, 1.0); +} \ No newline at end of file diff --git a/samples/02_box/shader/box.vert.glsl b/samples/02_box/shader/box.vert.glsl new file mode 100644 index 0000000..ff21bbd --- /dev/null +++ b/samples/02_box/shader/box.vert.glsl @@ -0,0 +1,18 @@ +#version 450 +#pragma shader_stage(vertex) + +layout(location=0) in vec4 position; +layout(location=1) in vec4 color; + +layout(location=0) out vec3 outColor; + +layout(binding=0) uniform Camera { + mat4 model; + mat4 view; + mat4 proj; +} ubo; + +void main() { + gl_Position = ubo.proj * ubo.view * ubo.model * vec4(position.xyz, 1.0f); + outColor = vec3(color.rgb); +} \ No newline at end of file diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index a3e353a..0b584b7 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -2,7 +2,6 @@ cmake_minimum_required(VERSION 3.13) -add_subdirectory("01_triangle") add_subdirectory("00_util") - - +add_subdirectory("01_triangle") +add_subdirectory("02_box")