From 162252e38d983f02b6ac2d7c0e37f979aed04961 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Mon, 15 Oct 2018 19:52:16 -0400 Subject: [PATCH] Add triangle rendering --- CMakeLists.txt | 19 +++++++- include/renderer.h | 14 ++++++ include/worldpass.h | 20 +++++++++ shaders/triangle.frag | 7 +++ shaders/triangle.vert | 11 +++++ src/renderer.cpp | 41 ++++++++++++++++- src/worldpass.cpp | 101 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 211 insertions(+), 2 deletions(-) create mode 100644 include/worldpass.h create mode 100644 shaders/triangle.frag create mode 100644 shaders/triangle.vert create mode 100644 src/worldpass.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 030e6d1..0da6831 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,23 @@ endif() add_executable(Graph src/main.cpp - src/renderer.cpp) + src/renderer.cpp + src/worldpass.cpp) target_link_libraries(Graph PUBLIC SDL2::SDL2 SDL2::SDL2main ${Vulkan_LIBRARY}) target_include_directories(Graph PUBLIC include ${Vulkan_INCLUDE_DIRS}) + +macro(compile_shader src) + add_custom_command( + OUTPUT ${src}.spv + COMMAND glslangValidator -V ${CMAKE_CURRENT_SOURCE_DIR}/shaders/${src} -o ${CMAKE_CURRENT_SOURCE_DIR}/build/${src}.spv + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/shaders/${src} + ) + + list(APPEND SPV_FILES ${src}.spv) +endmacro() + +compile_shader(triangle.vert) +compile_shader(triangle.frag) + +add_custom_target(BuildShaders DEPENDS ${SPV_FILES}) +add_dependencies(Graph BuildShaders) diff --git a/include/renderer.h b/include/renderer.h index 299e5a5..99e25d2 100644 --- a/include/renderer.h +++ b/include/renderer.h @@ -2,6 +2,8 @@ #include +#include "worldpass.h" + struct RenderTarget { VkSurfaceKHR surface = nullptr; VkSwapchainKHR swapchain = nullptr; @@ -30,10 +32,20 @@ public: RenderTarget* createSurfaceRenderTarget(VkSurfaceKHR surface, RenderTarget* oldRenderTarget = nullptr); void destroyRenderTarget(RenderTarget* target); + VkShaderModule createShader(const char* path); + VkInstance getInstance() const { return instance_; } + VkDevice getDevice() const { + return device_; + } + + VkRenderPass getRenderPass() const { + return presentationRenderPass_; + } + private: void createInstance(); #ifdef DEBUG @@ -66,4 +78,6 @@ private: VkCommandPool commandPool_ = nullptr; VkRenderPass presentationRenderPass_ = nullptr; + + WorldPass* worldPass_ = nullptr; }; diff --git a/include/worldpass.h b/include/worldpass.h new file mode 100644 index 0000000..c1c3092 --- /dev/null +++ b/include/worldpass.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +class Renderer; + +class WorldPass { +public: + WorldPass(Renderer& renderer); + + void render(VkCommandBuffer commandBuffer); + +private: + void createPipeline(); + + VkPipelineLayout pipelineLayout_ = nullptr; + VkPipeline pipeline_ = nullptr; + + Renderer& renderer_; +}; diff --git a/shaders/triangle.frag b/shaders/triangle.frag new file mode 100644 index 0000000..de2fc6a --- /dev/null +++ b/shaders/triangle.frag @@ -0,0 +1,7 @@ +#version 460 core + +layout(location = 0) out vec4 outColor; + +void main() { + outColor = vec4(1.0); +} diff --git a/shaders/triangle.vert b/shaders/triangle.vert new file mode 100644 index 0000000..87946fc --- /dev/null +++ b/shaders/triangle.vert @@ -0,0 +1,11 @@ +#version 460 core + +vec2 positions[3] = vec2[]( + vec2(0.0, -0.5), + vec2(0.5, 0.5), + vec2(-0.5, 0.5) +); + +void main() { + gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); +} diff --git a/src/renderer.cpp b/src/renderer.cpp index 88754c8..78029f1 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -17,11 +18,15 @@ Renderer::Renderer() { createLogicalDevice(); createCommandPool(); createPresentationRenderPass(); + + worldPass_ = new WorldPass(*this); } Renderer::~Renderer() { vkDeviceWaitIdle(device_); + delete worldPass_; + vkDestroyRenderPass(device_, presentationRenderPass_, nullptr); vkDestroyCommandPool(device_, commandPool_, nullptr); @@ -49,6 +54,18 @@ void Renderer::render(RenderTarget* target) { vkBeginCommandBuffer(commandBuffer, &beginInfo); + VkViewport viewport = {}; + viewport.width = target->extent.width; + viewport.height = target->extent.height; + viewport.maxDepth = 1.0f; + + vkCmdSetViewport(commandBuffer, 0, 1, &viewport); + + VkRect2D scissor = {}; + scissor.extent = target->extent; + + vkCmdSetScissor(commandBuffer, 0, 1, &scissor); + VkClearValue clearColor = {}; clearColor.color.float32[0] = sin((platform::getTime() / 500.0f) * 0.2f) * 0.5f + 0.5f; clearColor.color.float32[1] = sin((platform::getTime() / 500.0f) * 0.4f) * 0.5f + 0.5f; @@ -63,7 +80,9 @@ void Renderer::render(RenderTarget* target) { renderPassBeginInfo.pClearValues = &clearColor; vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - + + worldPass_->render(commandBuffer); + vkCmdEndRenderPass(commandBuffer); vkEndCommandBuffer(commandBuffer); @@ -238,6 +257,26 @@ void Renderer::destroyRenderTarget(RenderTarget* target) { delete target; } +VkShaderModule Renderer::createShader(const char* path) { + std::ifstream file(path, std::ios::ate | std::ios::binary); + + size_t fileSize = (size_t) file.tellg(); + std::vector buffer(fileSize); + file.seekg(0); + file.read(buffer.data(), fileSize); + file.close(); + + VkShaderModuleCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + createInfo.codeSize = buffer.size(); + createInfo.pCode = reinterpret_cast(buffer.data()); + + VkShaderModule shaderModule; + vkCreateShaderModule(device_, &createInfo, nullptr, &shaderModule); + + return shaderModule; +} + void Renderer::createInstance() { uint32_t layerCount = 0; vkEnumerateInstanceLayerProperties(&layerCount, nullptr); diff --git a/src/worldpass.cpp b/src/worldpass.cpp new file mode 100644 index 0000000..ba9f888 --- /dev/null +++ b/src/worldpass.cpp @@ -0,0 +1,101 @@ +#include "worldpass.h" + +#include + +#include "renderer.h" + +WorldPass::WorldPass(Renderer& renderer) : renderer_(renderer) { + createPipeline(); +} + +void WorldPass::render(VkCommandBuffer commandBuffer) { + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_); + vkCmdDraw(commandBuffer, 3, 1, 0, 0); +} + +void WorldPass::createPipeline() { + VkShaderModule vertShaderModule = renderer_.createShader("triangle.vert.spv"); + VkShaderModule fragShaderModule = renderer_.createShader("triangle.frag.spv"); + + VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; + vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; + vertShaderStageInfo.module = vertShaderModule; + vertShaderStageInfo.pName = "main"; + + VkPipelineShaderStageCreateInfo fragShaderStageInfo = {}; + fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + fragShaderStageInfo.module = fragShaderModule; + fragShaderStageInfo.pName = "main"; + + const std::array shaderStages = {vertShaderStageInfo, fragShaderStageInfo}; + + VkPipelineVertexInputStateCreateInfo vertexInputInfo = {}; + vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertexInputInfo.vertexBindingDescriptionCount = 0; + vertexInputInfo.vertexAttributeDescriptionCount = 0; + + VkPipelineInputAssemblyStateCreateInfo inputAssembly = {}; + inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + + VkPipelineViewportStateCreateInfo viewportState = {}; + viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewportState.viewportCount = 1; + viewportState.scissorCount = 1; + + VkPipelineRasterizationStateCreateInfo rasterizer = {}; + rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizer.polygonMode = VK_POLYGON_MODE_FILL; + rasterizer.lineWidth = 1.0f; + rasterizer.cullMode = VK_CULL_MODE_BACK_BIT; + rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; + + VkPipelineMultisampleStateCreateInfo multisampling = {}; + multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + + VkPipelineColorBlendAttachmentState colorBlendAttachment = {}; + colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + colorBlendAttachment.blendEnable = VK_FALSE; + + VkPipelineColorBlendStateCreateInfo colorBlending = {}; + colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + colorBlending.attachmentCount = 1; + colorBlending.pAttachments = &colorBlendAttachment; + + const std::array dynamicStates = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR + }; + + VkPipelineDynamicStateCreateInfo dynamicState = {}; + dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamicState.dynamicStateCount = dynamicStates.size(); + dynamicState.pDynamicStates = dynamicStates.data(); + + VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; + pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + + vkCreatePipelineLayout(renderer_.getDevice(), &pipelineLayoutInfo, nullptr, &pipelineLayout_); + + VkGraphicsPipelineCreateInfo pipelineInfo = {}; + pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineInfo.stageCount = shaderStages.size(); + pipelineInfo.pStages = shaderStages.data(); + pipelineInfo.pVertexInputState = &vertexInputInfo; + pipelineInfo.pInputAssemblyState = &inputAssembly; + pipelineInfo.pViewportState = &viewportState; + pipelineInfo.pRasterizationState = &rasterizer; + pipelineInfo.pMultisampleState = &multisampling; + pipelineInfo.pColorBlendState = &colorBlending; + pipelineInfo.pDynamicState = &dynamicState; + pipelineInfo.layout = pipelineLayout_; + pipelineInfo.renderPass = renderer_.getRenderPass(); + + vkCreateGraphicsPipelines(renderer_.getDevice(), nullptr, 1, &pipelineInfo, nullptr, &pipeline_); + + vkDestroyShaderModule(renderer_.getDevice(), fragShaderModule, nullptr); + vkDestroyShaderModule(renderer_.getDevice(), vertShaderModule, nullptr); +}