From 3057106a138578ec5e6520ba94f2e764ded66e3f Mon Sep 17 00:00:00 2001 From: Jinesi Yelizati Date: Sun, 15 Aug 2021 22:01:10 +0800 Subject: [PATCH] feat(): use pushConstant --- .github/workflows/cmake.yml | 65 +++++++++++++++++++++++++++++++++ .gitignore | 3 +- CMakeLists.txt | 11 +++++- Draw-frag.spv | Bin 376 -> 0 bytes Draw.frag | 23 ++++++++++-- Draw.frag.spv | Bin 0 -> 1468 bytes Draw-vert.spv => Draw.vert.spv | Bin include/VulkanDrawable.h | 2 + include/VulkanRenderer.h | 6 ++- source/VulkanApplication.cpp | 2 +- source/VulkanDrawable.cpp | 40 +++++++++++++++++++- source/VulkanRenderer.cpp | 52 ++++++++++++++++++++++---- 12 files changed, 188 insertions(+), 16 deletions(-) create mode 100644 .github/workflows/cmake.yml delete mode 100644 Draw-frag.spv create mode 100644 Draw.frag.spv rename Draw-vert.spv => Draw.vert.spv (100%) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml new file mode 100644 index 0000000..f6de4c6 --- /dev/null +++ b/.github/workflows/cmake.yml @@ -0,0 +1,65 @@ +name: CMake + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +env: + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + BUILD_TYPE: Release + +jobs: + build: + # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. + # You can convert this to a matrix build if you need cross-platform coverage. + # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix + runs-on: ${{matrix.os}} + + strategy: + matrix: + os: [windows-latest, windows-2019] + cxx_standard: [17, 20] + + steps: + - uses: actions/checkout@v3 + + - name: Install Vulkan SDK + uses: humbletim/install-vulkan-sdk@v1.1.1 + with: + version: latest + cache: true + + - name: Install Ninja + uses: ashutoshvarma/setup-ninja@master + with: + version: 1.11.0 + + - if: runner.os == 'Windows' + uses: TheMrMilchmann/setup-msvc-dev@v1 + with: + arch: x64 + + - name: Configure CMake + if: ${{matrix.os}} + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. + # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_CXX_STANDARD=${{matrix.cxx_standard}} -G "Ninja" + + - name: Build + # Build your program with the given configuration + run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + + - name: Test + working-directory: ${{github.workspace}}/build + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + run: ctest -C ${{env.BUILD_TYPE}} + + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + name: stupid-vulkan + path: | + ${{github.workspace}}\binaries\* diff --git a/.gitignore b/.gitignore index 538f10c..d5188ba 100644 --- a/.gitignore +++ b/.gitignore @@ -78,4 +78,5 @@ out gen -cmake-build-debug +cmake-build-* +binaries diff --git a/CMakeLists.txt b/CMakeLists.txt index 699531e..0a421bb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,6 +87,15 @@ set_property(TARGET ${Recipe_Name} PROPERTY RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBI set_property(TARGET ${Recipe_Name} PROPERTY CXX_STANDARD 20) set_property(TARGET ${Recipe_Name} PROPERTY CXX_STANDARD_REQUIRED ON) -set_property(TARGET ${Recipe_Name} PROPERTY C_STANDARD 99) +set_property(TARGET ${Recipe_Name} PROPERTY C_STANDARD 20) set_property(TARGET ${Recipe_Name} PROPERTY C_STANDARD_REQUIRED ON) +set(resources Draw.vert.spv Draw.frag.spv) +foreach(resource IN LISTS resources) + add_custom_command( + TARGET ${Recipe_Name} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${CMAKE_CURRENT_SOURCE_DIR}/${resource} + ${CMAKE_CURRENT_SOURCE_DIR}/binaries/${resource} + ) +endforeach() \ No newline at end of file diff --git a/Draw-frag.spv b/Draw-frag.spv deleted file mode 100644 index fb3d06763d931ca830dcc27aebadb8b17fac6e13..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 376 zcmYk1&kn(05X6^iOZ|_8n-F(#KqSJ&p_kq~fpC$a3H5@W%0*&+pAuiP-QAhl*{xR` zg=PhdtZa4rytWmEm{l!sIZn38_?8{U)7bao;3yfwOD-VUz%Ph-qBMN A-2eap diff --git a/Draw.frag b/Draw.frag index 80b0eeb..da55e65 100644 --- a/Draw.frag +++ b/Draw.frag @@ -1,8 +1,25 @@ #version 450 layout (location = 0) in vec4 color; -layout(location = 0) out vec4 outColor; +layout (location = 0) out vec4 outColor; -void main(){ - outColor = color; +layout(push_constant) uniform colorBlock { + int constColor; + float mixerValue; +} pushConstantsColorBlock; + +vec4 red = vec4(1.0, 0.0, 0.0, 1.0); +vec4 green = vec4(0.0, 1.0, 0.0, 1.0); +vec4 blue = vec4(0.0, 0.0, 1.0, 1.0); + +void main() +{ + if (pushConstantsColorBlock.constColor == 1) + outColor = red; + else if (pushConstantsColorBlock.constColor == 2) + outColor = green; + else if (pushConstantsColorBlock.constColor == 3) + outColor = blue; + else + outColor = color*pushConstantsColorBlock.mixerValue; } \ No newline at end of file diff --git a/Draw.frag.spv b/Draw.frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..4afe791fabec8cb652c72fa507266bd638960d6d GIT binary patch literal 1468 zcmZ9M+fGwa5Qdl3T@aLmoIGLy&tN?PVvHK$qF!)k;(aNN5=(1(NWAn3d=MYQm-3L9 z_NGwjx-93I@kXcJ>+c)%x1sNUIVf23gXeXX87~4 zSB$CqC*Wpj)eoC8EGw(biM_kd4 zTE2xff;){JoY2AbokqE{1vhxsU8JWubOmuwEBNk5%v@)hM>~VKwe@{3F=vpwhL1IYZ-BN=Y2^vXS{@ne~062R}0LUe^TQ*+Vcm# zv1`aG;{DpzafS+FAKvR8^nb%KU#>aP#~SwOKK#bTqmNtIV(!pB?w~#PVeB??53#m( z^l=y49Yi1c_F=wUbE1#?*r)s0027Zs9$<_4cJ}cQ?XeGIRpc>ZZSCm8KR5RuedybV z`Etz(?iRLhZ(qLq4q{)vfgHc(XNdSWIPQBFF;6`15F5S2yGCbs2m0|Q>c4z(yU0J~ C8DUib literal 0 HcmV?d00001 diff --git a/Draw-vert.spv b/Draw.vert.spv similarity index 100% rename from Draw-vert.spv rename to Draw.vert.spv diff --git a/include/VulkanDrawable.h b/include/VulkanDrawable.h index 51390d6..3aaa121 100644 --- a/include/VulkanDrawable.h +++ b/include/VulkanDrawable.h @@ -26,6 +26,8 @@ class VulkanDrawable : public VulkanDescriptor { void initScissors(VkCommandBuffer *cmd); + void initPushConstant(VkCommandBuffer *cmd); + void setPipeline(VkPipeline *vulkanPipeline) { pipeline = vulkanPipeline; } VkPipeline *getPipeline() { return pipeline; } diff --git a/include/VulkanRenderer.h b/include/VulkanRenderer.h index 9d3d109..7c71cd2 100644 --- a/include/VulkanRenderer.h +++ b/include/VulkanRenderer.h @@ -69,6 +69,8 @@ class VulkanRenderer { void createDescriptors(); + void createPushConstants(); + void destroyCommandBuffer(); void destroyCommandPool(); @@ -108,9 +110,10 @@ class VulkanRenderer { VkImageView view; } Depth; - VkCommandBuffer cmdDepthImage; VkCommandPool cmdPool; + VkCommandBuffer cmdDepthImage; VkCommandBuffer cmdVertexBuffer; + VkCommandBuffer cmdPushConstant; VkRenderPass renderPass; std::vector frameBuffers; // Number of frame Buffers corresponding to each swap chain @@ -123,4 +126,5 @@ class VulkanRenderer { std::vector drawableList; VulkanShader shaderObj; VulkanPipeline pipelineObj; + const bool includeDepth = true; }; diff --git a/source/VulkanApplication.cpp b/source/VulkanApplication.cpp index 0aa2de7..0a52fbc 100644 --- a/source/VulkanApplication.cpp +++ b/source/VulkanApplication.cpp @@ -13,7 +13,7 @@ VulkanApplication::VulkanApplication() { instanceObj.layerExtension.getInstanceLayerProperties(); deviceObj = nullptr; - debugFlag = false; + debugFlag = true; rendererObj = nullptr; isPrepared = false; isResizing = false; diff --git a/source/VulkanDrawable.cpp b/source/VulkanDrawable.cpp index a2c7e26..17e2332 100644 --- a/source/VulkanDrawable.cpp +++ b/source/VulkanDrawable.cpp @@ -294,6 +294,34 @@ void VulkanDrawable::initScissors(VkCommandBuffer *cmd) { vkCmdSetScissor(*cmd, 0, NUMBER_OF_SCISSORS, &scissor); } +void VulkanDrawable::initPushConstant(VkCommandBuffer *cmd){ + enum ColorFlag { + RED = 1, + GREEN = 2, + BLUE = 3, + MIXED_COLOR = 4, + }; + + float mixerValue = 0.3f; + unsigned constColorRGBFlag = MIXED_COLOR; + + // Create push constant data, this contain a constant + // color flag and mixer value for non-const color + unsigned pushConstants[2] = {}; + pushConstants[0] = constColorRGBFlag; + memcpy(&pushConstants[1], &mixerValue, sizeof(float)); + + // Check if number of push constants does not exceed the allowed size + uint32_t maxPushConstantSize = deviceObj->gpuProps.limits.maxPushConstantsSize; + if (sizeof(pushConstants) > maxPushConstantSize) { + assert(0); + printf("Push constant size is greater than expected, max allow size is %d", maxPushConstantSize); + } + + vkCmdPushConstants(*cmd, pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, + sizeof(pushConstants), pushConstants); +} + void VulkanDrawable::destroyVertexBuffer() { vkDestroyBuffer(rendererObj->getDevice()->device, VertexBuffer.buf, nullptr); vkFreeMemory(rendererObj->getDevice()->device, VertexBuffer.mem, nullptr); @@ -343,6 +371,7 @@ void VulkanDrawable::recordCommandBuffer(int currentBuffer, VkCommandBuffer *cmd initViewports(cmdDraw); initScissors(cmdDraw); + initPushConstant(cmdDraw); vkCmdDraw(*cmdDraw, 3 * 2 * 6, 1, 0, 0); // End of render pass instance recording @@ -555,12 +584,19 @@ void VulkanDrawable::createDescriptorSetLayout(bool useTexture) // Creates the pipeline layout to inject into the pipeline void VulkanDrawable::createPipelineLayout() { + // Set up the push constant range + const unsigned pushConstantRangeCount = 1; + VkPushConstantRange pushConstantRanges[pushConstantRangeCount] = {}; + pushConstantRanges[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + pushConstantRanges[0].offset = 0; + pushConstantRanges[0].size = 8; + // Create the pipeline layout with the help of descriptor layout. VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = {}; pPipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pPipelineLayoutCreateInfo.pNext = nullptr; - pPipelineLayoutCreateInfo.pushConstantRangeCount = 0; - pPipelineLayoutCreateInfo.pPushConstantRanges = nullptr; + pPipelineLayoutCreateInfo.pushConstantRangeCount = pushConstantRangeCount; + pPipelineLayoutCreateInfo.pPushConstantRanges = pushConstantRanges; pPipelineLayoutCreateInfo.setLayoutCount = (uint32_t)descLayout.size(); pPipelineLayoutCreateInfo.pSetLayouts = descLayout.data(); diff --git a/source/VulkanRenderer.cpp b/source/VulkanRenderer.cpp index 309b46f..000e260 100644 --- a/source/VulkanRenderer.cpp +++ b/source/VulkanRenderer.cpp @@ -38,8 +38,6 @@ void VulkanRenderer::initialize() { // Build the vertex buffer createVertexBuffer(); - const bool includeDepth = true; - // Create the render pass now.. createRenderPass(includeDepth); @@ -54,6 +52,9 @@ void VulkanRenderer::initialize() { // Manage the pipeline state objects createPipelineStateManagement(); + + // Build the push constants + createPushConstants(); } void VulkanRenderer::prepare() { @@ -358,8 +359,8 @@ void VulkanRenderer::createShaders() { shaderObj.buildShader((const char*)vertShaderCode, (const char*)fragShaderCode); #else - vertShaderCode = readFile("./../Draw-vert.spv", &sizeVert); - fragShaderCode = readFile("./../Draw-frag.spv", &sizeFrag); + vertShaderCode = readFile("Draw.vert.spv", &sizeVert); + fragShaderCode = readFile("Draw.frag.spv", &sizeFrag); shaderObj.buildShaderModuleWithSPV((uint32_t *) vertShaderCode, sizeVert, (uint32_t *) fragShaderCode, sizeFrag); #endif @@ -380,6 +381,44 @@ void VulkanRenderer::createDescriptors() { } +// this is not used +void VulkanRenderer::createPushConstants() { + CommandBufferMgr::allocCommandBuffer(&deviceObj->device, cmdPool, &cmdPushConstant); + CommandBufferMgr::beginCommandBuffer(cmdPushConstant); + + enum ColorFlag { + RED = 1, + GREEN = 2, + BLUE = 3, + MIXED_COLOR = 4, + }; + + float mixerValue = 0.3f; + unsigned constColorRGBFlag = MIXED_COLOR; + + // Create push constant data, this contain a constant + // color flag and mixer value for non-const color + unsigned pushConstants[2] = {}; + pushConstants[0] = constColorRGBFlag; + memcpy(&pushConstants[1], &mixerValue, sizeof(float)); + + // Check if number of push constants does not exceed the allowed size + int maxPushConstantSize = getDevice()->gpuProps.limits.maxPushConstantsSize; + if (sizeof(pushConstants) > maxPushConstantSize) { + assert(0); + printf("Push constant size is greater than expected, max allow size is %d", maxPushConstantSize); + } + + for (auto drawableObj : drawableList) { + vkCmdPushConstants(cmdPushConstant, drawableObj->pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, + sizeof(pushConstants), pushConstants); + } + + CommandBufferMgr::endCommandBuffer(cmdPushConstant); + CommandBufferMgr::submitCommandBuffer(deviceObj->queue, &cmdPushConstant); +} + + void VulkanRenderer::destroyFramebuffers() { for (uint32_t i = 0; i < swapChainObj->scPublicVars.swapchainImageCount; i++) { vkDestroyFramebuffer(deviceObj->device, frameBuffers.at(i), NULL); @@ -411,7 +450,7 @@ void VulkanRenderer::destroyDrawableUniformBuffer() { } void VulkanRenderer::destroyCommandBuffer() { - VkCommandBuffer cmdBufs[] = {cmdDepthImage}; + VkCommandBuffer cmdBufs[] = {cmdDepthImage, cmdVertexBuffer, cmdPushConstant}; vkFreeCommandBuffers(deviceObj->device, cmdPool, sizeof(cmdBufs) / sizeof(VkCommandBuffer), cmdBufs); } @@ -576,10 +615,9 @@ void VulkanRenderer::createPipelineStateManagement() { } pipelineObj.createPipelineCache(); - const bool depthPresent = VkBool32(true); for (VulkanDrawable *drawable : drawableList) { auto *pipeline = (VkPipeline *) malloc(sizeof(VkPipeline)); - if (pipelineObj.createPipeline(drawable, pipeline, &shaderObj, depthPresent)) { + if (pipelineObj.createPipeline(drawable, pipeline, &shaderObj, includeDepth)) { pipelineList.push_back(pipeline); drawable->setPipeline(pipeline); } else {