From eaf4556bad55d2c49ca5cfee26143241fd060416 Mon Sep 17 00:00:00 2001 From: Anish Bhobe Date: Mon, 1 Jul 2024 18:37:08 +0200 Subject: [PATCH] Triangle rendered to screen. --- CMakeLists.txt | 5 +- add_shader.cmake | 33 ++++ aster/device.cpp | 2 + aster/device.h | 19 +++ aster/global.h | 2 + aster/swapchain.cpp | 16 +- aster/swapchain.h | 1 + triangle/CMakeLists.txt | 3 + triangle/shader/triangle.vs.hlsl | 28 ++++ triangle/shader/white.frag.glsl | 9 + triangle/triangle.cpp | 277 +++++++++++++++++++++++++++---- 11 files changed, 352 insertions(+), 43 deletions(-) create mode 100644 add_shader.cmake create mode 100644 triangle/shader/triangle.vs.hlsl create mode 100644 triangle/shader/white.frag.glsl diff --git a/CMakeLists.txt b/CMakeLists.txt index 67ccac6..d79aeb8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,10 +10,13 @@ set(CMAKE_CXX_EXTENSIONS OFF) if (MSVC) set(CMAKE_CXX_FLAGS "/W4 /GR- /Zi") - add_compile_definitions(_NO_EXCEPTIONS=1) + add_compile_definitions(_HAS_EXCEPTIONS=1) + add_compile_definitions(_CRT_SECURE_NO_WARNINGS) else () set(CMAKE_CXX_FLAGS "-Wall -fno-rtti -fno-exceptions") endif () +include(add_shader.cmake) + add_subdirectory("aster") add_subdirectory("triangle") diff --git a/add_shader.cmake b/add_shader.cmake new file mode 100644 index 0000000..4084d8c --- /dev/null +++ b/add_shader.cmake @@ -0,0 +1,33 @@ +function(add_shader TARGET SHADER) + find_package(Vulkan REQUIRED COMPONENTS dxc) + + get_filename_component(shader-ext ${SHADER} LAST_EXT) + + set(current-shader-path ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER}) + set(current-output-path ${CMAKE_CURRENT_BINARY_DIR}/${SHADER}.spv) + + get_filename_component(current-output-dir ${current-output-path} DIRECTORY) + file(MAKE_DIRECTORY ${current-output-dir}) + + if (Vulkan_dxc_exe_FOUND AND ${shader-ext} STREQUAL ".hlsl") + message("Marked as hlsl file. ${current-output-path}") + add_custom_command( + OUTPUT ${current-output-path} + COMMAND Vulkan::dxc_exe -spirv -T vs_6_0 -E main ${current-shader-path} -Fo ${current-output-path} + DEPENDS ${current-shader-path} + IMPLICIT_DEPENDS CXX ${current-shader-path} + VERBATIM) + elseif (Vulkan_glslc_FOUND AND ${shader-ext} STREQUAL ".glsl") + message("Marked as glsl file. ${current-output-path}") + add_custom_command( + OUTPUT ${current-output-path} + COMMAND Vulkan::glslc -o ${current-output-path} ${current-shader-path} + DEPENDS ${current-shader-path} + IMPLICIT_DEPENDS CXX ${current-shader-path} + VERBATIM) + endif () + + # Make sure our build depends on this output. + set_source_files_properties(${current-output-path} PROPERTIES GENERATED TRUE) + target_sources(${TARGET} PRIVATE ${current-output-path}) +endfunction(add_shader) \ No newline at end of file diff --git a/aster/device.cpp b/aster/device.cpp index 6ad11f9..1f4e916 100644 --- a/aster/device.cpp +++ b/aster/device.cpp @@ -64,6 +64,8 @@ Device::Device(const Context *context, PhysicalDevice *physicalDevice, Features THEN_ABORT(result) ELSE_DEBUG("{} ({}) Initialized.", m_Name, physicalDevice->m_DeviceProperties.deviceName.data()); + SetName(m_Device, m_Name.data()); + VmaVulkanFunctions vmaVulkanFunctions = { .vkGetInstanceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetInstanceProcAddr, .vkGetDeviceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetDeviceProcAddr, diff --git a/aster/device.h b/aster/device.h index 32b7353..b757935 100644 --- a/aster/device.h +++ b/aster/device.h @@ -37,5 +37,24 @@ struct Device final const eastl::vector &queueAllocations, NameString &&name); ~Device(); + template + requires vk::isVulkanHandleType::value + void SetName(const T &object, cstr name) const; [[nodiscard]] vk::Queue GetQueue(u32 familyIndex, u32 queueIndex) const; }; + +template + requires vk::isVulkanHandleType::value +void +Device::SetName(const T &object, cstr name) const +{ + auto handle = Recast(Cast(object)); + const vk::DebugUtilsObjectNameInfoEXT objectNameInfo = { + .objectType = object.objectType, + .objectHandle = handle, + .pObjectName = name, + }; + vk::Result result = m_Device.setDebugUtilsObjectNameEXT(&objectNameInfo); + WARN_IF(Failed(result), "Could not name {:x}: {} as {}. Cause: {}", handle, to_string(object.objectType), name, + result); +} diff --git a/aster/global.h b/aster/global.h index ec16c06..218ef27 100644 --- a/aster/global.h +++ b/aster/global.h @@ -34,6 +34,8 @@ constexpr u32 ASTER_API_VERSION = vk::ApiVersion13; #define CODE_LOC " @ " __FILE__ ":" VULKAN_HPP_STRINGIFY(__LINE__) +#define FORCE_TODO static_assert(false) + [[nodiscard]] inline bool Failed(const vk::Result result) { diff --git a/aster/swapchain.cpp b/aster/swapchain.cpp index 350c92b..5c97f99 100644 --- a/aster/swapchain.cpp +++ b/aster/swapchain.cpp @@ -18,7 +18,7 @@ Swapchain::Swapchain(const Window *window, const Device *device, NameString &&na Swapchain::~Swapchain() { - Cleanup(); + this->Cleanup(); } void @@ -28,21 +28,21 @@ Swapchain::Create(const Window *window) auto surfaceFormats = GetSurfaceFormats(m_Device->m_PhysicalDevice, window->m_Surface); auto presentModes = GetSurfacePresentModes(m_Device->m_PhysicalDevice, window->m_Surface); - vk::Format swapchainFormat = vk::Format::eUndefined; + m_Format = vk::Format::eUndefined; vk::ColorSpaceKHR swapchainColorSpace = vk::ColorSpaceKHR::eSrgbNonlinear; for (auto [format, colorSpace] : surfaceFormats) { if (format == vk::Format::eB8G8R8A8Srgb && colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) { - swapchainFormat = format; + m_Format = format; swapchainColorSpace = colorSpace; } } - if (swapchainFormat == vk::Format::eUndefined) + if (m_Format == vk::Format::eUndefined) { WARN("Preferred Swapchain format not found. Falling back."); auto [format, colorSpace] = surfaceFormats.front(); - swapchainFormat = format; + m_Format = format; swapchainColorSpace = colorSpace; } @@ -82,7 +82,7 @@ Swapchain::Create(const Window *window) const vk::SwapchainCreateInfoKHR swapchainCreateInfo = { .surface = window->m_Surface, .minImageCount = swapchainImageCount, - .imageFormat = swapchainFormat, + .imageFormat = m_Format, .imageColorSpace = swapchainColorSpace, .imageExtent = m_Extent, .imageArrayLayers = 1, @@ -108,6 +108,8 @@ Swapchain::Create(const Window *window) m_Swapchain = swapchain; + m_Device->SetName(m_Swapchain, m_Name.data()); + result = device.getSwapchainImagesKHR(m_Swapchain, &swapchainImageCount, nullptr); ERROR_IF(Failed(result), "Failed getting swapchain {}'s images. Cause {}", m_Name, result) THEN_ABORT(result); @@ -120,7 +122,7 @@ Swapchain::Create(const Window *window) vk::ImageViewCreateInfo viewCreateInfo = { .viewType = vk::ImageViewType::e2D, - .format = swapchainFormat, + .format = m_Format, .components = {.r = vk::ComponentSwizzle::eIdentity, .g = vk::ComponentSwizzle::eIdentity, .b = vk::ComponentSwizzle::eIdentity, diff --git a/aster/swapchain.h b/aster/swapchain.h index 904bfb6..e22a176 100644 --- a/aster/swapchain.h +++ b/aster/swapchain.h @@ -19,6 +19,7 @@ struct Swapchain final vk::SwapchainKHR m_Swapchain; NameString m_Name; vk::Extent2D m_Extent; + vk::Format m_Format; eastl::fixed_vector m_Images; eastl::fixed_vector m_ImageViews; diff --git a/triangle/CMakeLists.txt b/triangle/CMakeLists.txt index 10b097e..17d44cf 100644 --- a/triangle/CMakeLists.txt +++ b/triangle/CMakeLists.txt @@ -5,4 +5,7 @@ cmake_minimum_required(VERSION 3.13) add_executable(triangle "triangle.cpp") add_dependencies(triangle aster_core) +add_shader(triangle shader/triangle.vs.hlsl) +add_shader(triangle shader/white.frag.glsl) + target_link_libraries(triangle PRIVATE aster_core) diff --git a/triangle/shader/triangle.vs.hlsl b/triangle/shader/triangle.vs.hlsl new file mode 100644 index 0000000..a2c7905 --- /dev/null +++ b/triangle/shader/triangle.vs.hlsl @@ -0,0 +1,28 @@ +struct VSIn { + int idx : SV_VERTEXID; +}; + +struct VSOut +{ + float4 Pos : SV_POSITION; + [[vk::location(0)]] float3 Color : COLOR0; +}; + +VSOut main(VSIn input) { + float3 points[] = { + float3(-0.5f, -0.5f, 0.0f), + float3(0.5f, -0.5f, 0.0f), + float3(0.0f, 0.5f, 0.0f) + }; + float3 colors[] = { + float3( 1.0f, 0.0f, 0.0f ), + float3( 0.0f, 1.0f, 0.0f ), + float3( 0.0f, 0.0f, 1.0f ), + }; + + VSOut output; + output.Pos = float4(points[input.idx], 1.0f); + output.Color = colors[input.idx]; + + return output; +} \ No newline at end of file diff --git a/triangle/shader/white.frag.glsl b/triangle/shader/white.frag.glsl new file mode 100644 index 0000000..f85d053 --- /dev/null +++ b/triangle/shader/white.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/triangle/triangle.cpp b/triangle/triangle.cpp index 3e97565..555c7cd 100644 --- a/triangle/triangle.cpp +++ b/triangle/triangle.cpp @@ -9,14 +9,15 @@ #include "aster/swapchain.h" #include +#include constexpr u32 MAX_FRAMES_IN_FLIGHT = 3; bool IsSuitableDevice(const PhysicalDevice *physicalDevice); - PhysicalDevice FindSuitableDevice(const PhysicalDevices &physicalDevices); - QueueAllocation FindAppropriateQueueAllocation(const PhysicalDevice *physicalDevice); +eastl::optional> ReadFile(cstr fileName); +vk::ShaderModule CreateShader(const Device *device, cstr shaderFile); struct Frame { @@ -29,14 +30,19 @@ struct Frame Frame(const Device *device, u32 queueFamilyIndex, u32 frameCount); ~Frame(); - u32 BeginFrame(const Swapchain *swapchain, u32 frameIndex) const; [[nodiscard]] vk::CommandBuffer AllocateCommandBuffer() const; }; +struct Shader +{ + vk::ShaderModule m_ShaderModule; + vk::ShaderStageFlags m_Stage; +}; + int main(int, char **) { - MIN_LOG_LEVEL(Logger::LogType::eInfo); + MIN_LOG_LEVEL(Logger::LogType::eVerbose); GlfwContext glfwContext = {}; Context context = {"Aster", VERSION}; @@ -55,17 +61,177 @@ main(int, char **) Swapchain swapchain = {&window, &device, "Primary Chain"}; + auto vertexShaderModule = CreateShader(&device, "shader/triangle.vs.hlsl.spv"); + auto fragmentShaderModule = CreateShader(&device, "shader/white.frag.glsl.spv"); + + eastl::array shaderStages = {{ + { + .stage = vk::ShaderStageFlagBits::eVertex, + .module = vertexShaderModule, + .pName = "main", + }, + { + .stage = vk::ShaderStageFlagBits::eFragment, + .module = fragmentShaderModule, + .pName = "main", + }, + }}; + + vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = { + .setLayoutCount = 0, + .pSetLayouts = nullptr, + .pushConstantRangeCount = 0, + .pPushConstantRanges = nullptr, + }; + vk::PipelineLayout pipelineLayout; + vk::Result result = device.m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &pipelineLayout); + ERROR_IF(Failed(result), "Could not create a pipeline layout. Cause: {}", result) THEN_ABORT(result); + device.SetName(pipelineLayout, "Triangle Layout"); + + vk::PipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = { + .vertexBindingDescriptionCount = 0, + .pVertexBindingDescriptions = nullptr, + .vertexAttributeDescriptionCount = 0, + .pVertexAttributeDescriptions = nullptr, + }; + vk::PipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = { + .topology = vk::PrimitiveTopology::eTriangleList, + .primitiveRestartEnable = vk::False, + }; + + vk::PipelineViewportStateCreateInfo viewportStateCreateInfo = { + .viewportCount = 1, + .scissorCount = 1, + }; + + vk::PipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = { + .depthClampEnable = vk::False, + .rasterizerDiscardEnable = vk::False, + .polygonMode = vk::PolygonMode::eFill, + .cullMode = vk::CullModeFlagBits::eNone, + .frontFace = vk::FrontFace::eCounterClockwise, + .depthBiasEnable = vk::False, + .lineWidth = 1.0, + }; + vk::PipelineMultisampleStateCreateInfo multisampleStateCreateInfo = { + .rasterizationSamples = vk::SampleCountFlagBits::e1, + .sampleShadingEnable = vk::False, + }; + vk::PipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo = { + .depthTestEnable = vk::False, + .depthWriteEnable = vk::False, + }; + vk::PipelineColorBlendAttachmentState colorBlendAttachmentState = { + .blendEnable = vk::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 = vk::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; + result = device.m_Device.createGraphicsPipelines(nullptr, 1, &pipelineCreateInfo, nullptr, &pipeline); + ERROR_IF(Failed(result), "Could not create a graphics pipeline. Cause: {}", result) THEN_ABORT(result); + device.SetName(pipelineLayout, "Triangle Pipeline"); + + // Frames eastl::fixed_vector frames; for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { frames.emplace_back(&device, queueAllocation.m_Family, i); } + 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, + }; + u32 frameIndex = 0; while (window.Poll()) { Frame *currentFrame = &frames[frameIndex]; - u32 imageIndex = currentFrame->BeginFrame(&swapchain, frameIndex); + + result = device.m_Device.waitForFences(1, ¤tFrame->m_FrameAvailableFence, vk::True, MaxValue); + ERROR_IF(Failed(result), "Waiting for fence {} failed. Cause: {}", frameIndex, result) + THEN_ABORT(result); + + u32 imageIndex; + 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; + break; + default: + ERROR("Waiting for swapchain image {} failed. Cause: {}", frameIndex, result) + THEN_ABORT(result); + } + } + + result = device.m_Device.resetFences(1, ¤tFrame->m_FrameAvailableFence); + ERROR_IF(Failed(result), "Fence {} reset failed. Cause: {}", frameIndex, result) + THEN_ABORT(result); + + result = device.m_Device.resetCommandPool(currentFrame->m_Pool, {}); + ERROR_IF(Failed(result), "Command pool {} reset failed. Cause: {}", frameIndex, result) + THEN_ABORT(result); vk::ImageView currentImageView = swapchain.m_ImageViews[imageIndex]; vk::Image currentImage = swapchain.m_Images[imageIndex]; @@ -103,7 +269,7 @@ main(int, char **) }; vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit}; - vk::Result result = cmd.begin(&beginInfo); + result = cmd.begin(&beginInfo); ERROR_IF(Failed(result), "Command buffer begin failed. Cause: {}", result) THEN_ABORT(result); @@ -115,13 +281,13 @@ main(int, char **) .imageView = currentImageView, .imageLayout = vk::ImageLayout::eColorAttachmentOptimal, .resolveMode = vk::ResolveModeFlagBits::eNone, - .loadOp = vk::AttachmentLoadOp::eLoad, + .loadOp = vk::AttachmentLoadOp::eClear, .storeOp = vk::AttachmentStoreOp::eStore, .clearValue = vk::ClearColorValue{0.0f, 0.0f, 0.0f, 1.0f}, }; vk::RenderingInfo renderingInfo = { - .renderArea = {.offset = {0, 0}, .extent = swapchain.m_Extent}, + .renderArea = {.extent = swapchain.m_Extent}, .layerCount = 1, .colorAttachmentCount = 1, .pColorAttachments = &attachmentInfo, @@ -129,6 +295,11 @@ main(int, char **) cmd.beginRendering(&renderingInfo); + cmd.setViewport(0, 1, &viewport); + cmd.setScissor(0, 1, &scissor); + cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline); + cmd.draw(3, 1, 0, 0); + cmd.endRendering(); cmd.pipelineBarrier(vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eBottomOfPipe, @@ -169,6 +340,10 @@ main(int, char **) 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; default: ERROR("Command queue present failed. Cause: {}", result) @@ -178,6 +353,14 @@ main(int, char **) frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; } + result = device.m_Device.waitIdle(); + ERROR_IF(Failed(result), "Wait idle failed. Cause: {}", result); + + device.m_Device.destroy(pipeline, nullptr); + device.m_Device.destroy(pipelineLayout, nullptr); + device.m_Device.destroy(vertexShaderModule, nullptr); + device.m_Device.destroy(fragmentShaderModule, nullptr); + return 0; } @@ -216,6 +399,32 @@ FindAppropriateQueueAllocation(const PhysicalDevice *physicalDevice) ERROR("No suitable queue family on the GPU.") THEN_ABORT(vk::Result::eErrorUnknown); } +eastl::optional> +ReadFile(cstr fileName) +{ + FILE *filePtr = fopen(fileName, "rb"); + + if (!filePtr) + { + ERROR("Invalid read of {}", fileName); + return eastl::nullopt; + } + + eastl::vector outputVec; + eastl::array buffer{}; + usize totalRead = 0; + usize readCount; + do + { + readCount = fread(buffer.data(), sizeof(u32), buffer.size(), filePtr); + const auto nextSize = totalRead + readCount; + outputVec.resize(nextSize); + memcpy(outputVec.data() + totalRead, buffer.data(), readCount * sizeof *buffer.data()); + totalRead = nextSize; + } while (readCount == 1024); + + return outputVec; +} Frame::Frame(const Device *device, const u32 queueFamilyIndex, const u32 frameCount) { @@ -245,31 +454,6 @@ Frame::Frame(const Device *device, const u32 queueFamilyIndex, const u32 frameCo DEBUG("Frame {} created successfully.", frameCount); } -u32 -Frame::BeginFrame(const Swapchain *swapchain, u32 frameIndex) const -{ - const auto device = m_Device->m_Device; - - vk::Result result = device.waitForFences(1, &m_FrameAvailableFence, VK_TRUE, MaxValue); - ERROR_IF(Failed(result), "Waiting for fence {} failed. Cause: {}", frameIndex, result) - THEN_ABORT(result); - - u32 imageIndex; - result = device.acquireNextImageKHR(swapchain->m_Swapchain, MaxValue, m_ImageAcquireSem, nullptr, &imageIndex); - ERROR_IF(Failed(result), "Waiting for swapchain image {} failed. Cause: {}", frameIndex, result) - THEN_ABORT(result); - // TODO: Deliberate failure on recreation. Will recreate later. - - result = device.resetFences(1, &m_FrameAvailableFence); - ERROR_IF(Failed(result), "Fence {} reset failed. Cause: {}", frameIndex, result) - THEN_ABORT(result); - - result = device.resetCommandPool(m_Pool, {}); - ERROR_IF(Failed(result), "Command pool {} reset failed. Cause: {}", frameIndex, result) - THEN_ABORT(result); - - return imageIndex; -} vk::CommandBuffer Frame::AllocateCommandBuffer() const { @@ -284,10 +468,33 @@ Frame::AllocateCommandBuffer() const return commandBuffer; } +vk::ShaderModule +CreateShader(const Device *device, cstr shaderFile) +{ + eastl::vector shaderCode; + if (auto res = ReadFile(shaderFile)) + { + shaderCode = res.value(); + } + else + { + ERROR("Could not open {}.", shaderFile) THEN_ABORT(-1); + } + + const vk::ShaderModuleCreateInfo shaderModuleCreateInfo = { + .codeSize = shaderCode.size() * sizeof(u32), + .pCode = shaderCode.data(), + }; + vk::ShaderModule shaderModule; + + vk::Result result = device->m_Device.createShaderModule(&shaderModuleCreateInfo, nullptr, &shaderModule); + ERROR_IF(Failed(result), "Shader {} could not be created. Cause: {}", shaderFile, result) + THEN_ABORT(result); + return shaderModule; +} + Frame::~Frame() { - auto result = m_Device->m_Device.waitIdle(); - ERROR_IF(Failed(result), "Wait idle failed. Cause: {}", result); m_Device->m_Device.destroy(m_RenderFinishSem, nullptr); m_Device->m_Device.destroy(m_ImageAcquireSem, nullptr); m_Device->m_Device.destroy(m_FrameAvailableFence, nullptr);