From bfacea2bd4bdd832d6f2dee6a2922b4e9fcce9fe Mon Sep 17 00:00:00 2001 From: Grayson Riffe Date: Tue, 11 Feb 2025 16:46:18 -0600 Subject: [PATCH] Create shader modules for output pipeline --- NothinFancy/CMakeLists.txt | 23 ++++++++ NothinFancy/res/shaders/output.frag.glsl | 9 ++++ NothinFancy/res/shaders/output.vert.glsl | 20 +++++++ .../src/client/render/RenderEngine.cpp | 53 +++++++++++++------ NothinFancy/src/client/render/RenderEngine.h | 5 +- TestGame/CMakeLists.txt | 6 +++ 6 files changed, 99 insertions(+), 17 deletions(-) create mode 100644 NothinFancy/res/shaders/output.frag.glsl create mode 100644 NothinFancy/res/shaders/output.vert.glsl diff --git a/NothinFancy/CMakeLists.txt b/NothinFancy/CMakeLists.txt index a530e96..60c1d98 100644 --- a/NothinFancy/CMakeLists.txt +++ b/NothinFancy/CMakeLists.txt @@ -19,3 +19,26 @@ find_package(Git) execute_process(COMMAND ${GIT_EXECUTABLE} describe OUTPUT_VARIABLE NFVERSION OUTPUT_STRIP_TRAILING_WHITESPACE) configure_file(src/version.h.in version.h) target_include_directories(NothinFancy PUBLIC "${PROJECT_BINARY_DIR}/NothinFancy") + +# Compile shaders +set(GLSLANG "$ENV{VULKAN_SDK}/Bin/glslang.exe") +set(SHADER_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/NothinFancy/shaders") +file(GLOB_RECURSE SHADER_SOURCES "res/shaders/*.glsl") +foreach(SHADER_SOURCE ${SHADER_SOURCES}) + get_filename_component(FILENAME ${SHADER_SOURCE} NAME) + set(SHADER_BINARY "${SHADER_OUTPUT_DIRECTORY}/${FILENAME}.spv") + add_custom_command( + OUTPUT ${SHADER_BINARY} + COMMAND ${CMAKE_COMMAND} -E make_directory "${SHADER_OUTPUT_DIRECTORY}" + COMMAND ${GLSLANG} -V ${SHADER_SOURCE} -o ${SHADER_BINARY} + DEPENDS ${SHADER_SOURCE} + ) + list(APPEND SHADER_BINARIES ${SHADER_BINARY}) +endforeach(SHADER_SOURCE) + +add_custom_target( + Shaders + DEPENDS ${SHADER_BINARIES} +) + +add_dependencies(NothinFancy Shaders) diff --git a/NothinFancy/res/shaders/output.frag.glsl b/NothinFancy/res/shaders/output.frag.glsl new file mode 100644 index 0000000..7c5b0e7 --- /dev/null +++ b/NothinFancy/res/shaders/output.frag.glsl @@ -0,0 +1,9 @@ +#version 450 + +layout(location = 0) in vec3 fragColor; + +layout(location = 0) out vec4 outColor; + +void main() { + outColor = vec4(fragColor, 1.0); +} diff --git a/NothinFancy/res/shaders/output.vert.glsl b/NothinFancy/res/shaders/output.vert.glsl new file mode 100644 index 0000000..4f7b59f --- /dev/null +++ b/NothinFancy/res/shaders/output.vert.glsl @@ -0,0 +1,20 @@ +#version 450 + +vec2 trianglePositions[3] = vec2[] ( + vec2(0.0, -0.5), + vec2(0.5, 0.5), + vec2(-0.5, 0.5) +); + +vec3 triangleColors[3] = vec3[] ( + vec3(1.0, 0.0, 0.0), + vec3(0.0, 1.0, 0.0), + vec3(0.0, 0.0, 1.0) +); + +layout(location = 0) out vec3 fragColor; + +void main() { + fragColor = triangleColors[gl_VertexIndex]; + gl_Position = vec4(trianglePositions[gl_VertexIndex], 0.0, 1.0); +} diff --git a/NothinFancy/src/client/render/RenderEngine.cpp b/NothinFancy/src/client/render/RenderEngine.cpp index 486ad8c..29f1ce2 100644 --- a/NothinFancy/src/client/render/RenderEngine.cpp +++ b/NothinFancy/src/client/render/RenderEngine.cpp @@ -26,11 +26,12 @@ namespace nf::client::render { m_window->setDisplay(m_display); createInstance(); - createSurface(m_window->getHandle()); + createSurface(); pickPhysicalDevice(); createDevice(); createSwapchain(); - createRenderPass(); + createOutputRenderPass(); + createOutputPipeline(); m_window->show(); } @@ -51,15 +52,15 @@ namespace nf::client::render { instanceCI.enabledExtensionCount = instanceExtNames.size(); if (vkCreateInstance(&instanceCI, nullptr, &m_instance) != VK_SUCCESS) - NFError("Could not create Vulkan instance"); + NFError("Could not create Vulkan instance."); } - void RenderEngine::createSurface(HWND window) { + void RenderEngine::createSurface() { VkWin32SurfaceCreateInfoKHR surfaceCI = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR }; - surfaceCI.hwnd = window; + surfaceCI.hwnd = m_window->getHandle(); if (vkCreateWin32SurfaceKHR(m_instance, &surfaceCI, nullptr, &m_surface) != VK_SUCCESS) - NFError("Could not create Vulkan surface"); + NFError("Could not create Vulkan surface."); } void RenderEngine::pickPhysicalDevice() { @@ -68,7 +69,7 @@ namespace nf::client::render { uint32_t numPhysicalDevices = 0; vkEnumeratePhysicalDevices(m_instance, &numPhysicalDevices, nullptr); if (numPhysicalDevices == 0) - NFError("No Vulkan GPUs found"); + NFError("No Vulkan GPUs found."); std::vector physicalDevices(numPhysicalDevices); vkEnumeratePhysicalDevices(m_instance, &numPhysicalDevices, physicalDevices.data()); @@ -136,7 +137,7 @@ namespace nf::client::render { } if (m_physicalDevice == nullptr) - NFError("No Vulkan GPUs were found to be compatible"); + NFError("No Vulkan GPUs were found to be compatible."); } void RenderEngine::createDevice() { @@ -164,7 +165,7 @@ namespace nf::client::render { deviceCI.ppEnabledExtensionNames = &swapChainExtName; if (vkCreateDevice(m_physicalDevice, &deviceCI, nullptr, &m_device) != VK_SUCCESS) - NFError("Could not create Vulkan device"); + NFError("Could not create Vulkan device."); vkGetDeviceQueue(m_device, m_queueFIGraphics, 0, &m_queueGraphics); vkGetDeviceQueue(m_device, m_queueFIPresent, 0, &m_queuePresent); @@ -177,7 +178,7 @@ namespace nf::client::render { uint32_t numSurfaceFormats = 0; vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &numSurfaceFormats, nullptr); if (numSurfaceFormats == 0) - NFError("No Vulkan surface formats found"); + NFError("No Vulkan surface formats found."); std::vector surfaceFormats(numSurfaceFormats); vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &numSurfaceFormats, surfaceFormats.data()); @@ -189,7 +190,7 @@ namespace nf::client::render { uint32_t numPresentModes = 0; vkGetPhysicalDeviceSurfacePresentModesKHR(m_physicalDevice, m_surface, &numPresentModes, nullptr); if (numPresentModes == 0) - NFError("No Vulkan surface present modes found"); + NFError("No Vulkan surface present modes found."); std::vector presentModes(numPresentModes); vkGetPhysicalDeviceSurfacePresentModesKHR(m_physicalDevice, m_surface, &numPresentModes, presentModes.data()); @@ -228,7 +229,7 @@ namespace nf::client::render { swapchainCI.oldSwapchain = VK_NULL_HANDLE; if (vkCreateSwapchainKHR(m_device, &swapchainCI, nullptr, &m_swapchain) != VK_SUCCESS) - NFError("Could not create Vulkan swapchain"); + NFError("Could not create Vulkan swapchain."); uint32_t numSwapchainImages = 0; vkGetSwapchainImagesKHR(m_device, m_swapchain, &numSwapchainImages, nullptr); @@ -246,11 +247,11 @@ namespace nf::client::render { imageViewCI.subresourceRange.layerCount = 1; if (vkCreateImageView(m_device, &imageViewCI, nullptr, &m_swapchainImageViews[i]) != VK_SUCCESS) - NFError("Could not create Vulkan swapchain image view"); + NFError("Could not create Vulkan swapchain image view."); } } - void RenderEngine::createRenderPass() { + void RenderEngine::createOutputRenderPass() { VkAttachmentDescription outputColorAttachment = {}; outputColorAttachment.format = m_swapchainImageFormat; outputColorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; @@ -277,7 +278,29 @@ namespace nf::client::render { renderPassCI.pSubpasses = &subpassDescription; if (vkCreateRenderPass(m_device, &renderPassCI, nullptr, &m_renderPassOutput) != VK_SUCCESS) - NFError("Could not create Vulkan render pass"); + NFError("Could not create Vulkan output render pass."); + } + + void RenderEngine::createOutputPipeline() { + // First, create shader modules + std::string outputShaderVertex, outputShaderFragment; + if (!util::readFile("shaders/output.vert.glsl.spv", outputShaderVertex) || !util::readFile("shaders/output.frag.glsl.spv", outputShaderFragment)) + NFError("Could not read output shader binaries."); + + VkShaderModule outputShaderVertexModule = VK_NULL_HANDLE, outputShaderFragmentModule = VK_NULL_HANDLE; + VkShaderModuleCreateInfo outputShaderModulesCI = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO }; + outputShaderModulesCI.codeSize = outputShaderVertex.size(); + outputShaderModulesCI.pCode = reinterpret_cast(outputShaderVertex.data()); + vkCreateShaderModule(m_device, &outputShaderModulesCI, nullptr, &outputShaderVertexModule); + outputShaderModulesCI.codeSize = outputShaderFragment.size(); + outputShaderModulesCI.pCode = reinterpret_cast(outputShaderFragment.data()); + vkCreateShaderModule(m_device, &outputShaderModulesCI, nullptr, &outputShaderFragmentModule); + if (!outputShaderVertexModule || !outputShaderFragmentModule) + NFError("Could not create output shader modules."); + + // And cleanup shader modules + vkDestroyShaderModule(m_device, outputShaderVertexModule, nullptr); + vkDestroyShaderModule(m_device, outputShaderFragmentModule, nullptr); } RenderEngine::~RenderEngine() { diff --git a/NothinFancy/src/client/render/RenderEngine.h b/NothinFancy/src/client/render/RenderEngine.h index b986f00..9601765 100644 --- a/NothinFancy/src/client/render/RenderEngine.h +++ b/NothinFancy/src/client/render/RenderEngine.h @@ -12,11 +12,12 @@ namespace nf::client::render { ~RenderEngine(); private: void createInstance(); - void createSurface(HWND window); + void createSurface(); void pickPhysicalDevice(); void createDevice(); void createSwapchain(); - void createRenderPass(); + void createOutputRenderPass(); + void createOutputPipeline(); std::shared_ptr m_window; DisplayConfig m_display; diff --git a/TestGame/CMakeLists.txt b/TestGame/CMakeLists.txt index 852cbbd..607d0f9 100644 --- a/TestGame/CMakeLists.txt +++ b/TestGame/CMakeLists.txt @@ -15,3 +15,9 @@ endif() # Link to NF library target_link_libraries(TestGame NothinFancy) target_include_directories(TestGame PUBLIC "${CMAKE_SOURCE_DIR}/NothinFancy/src/include") + +# Copy shaders to executable directory +add_custom_command(TARGET TestGame POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory "${PROJECT_BINARY_DIR}/TestGame/shaders" + COMMAND ${CMAKE_COMMAND} -E copy_directory "${PROJECT_BINARY_DIR}/NothinFancy/shaders" "${PROJECT_BINARY_DIR}/TestGame/shaders" +)