Add triangle rendering
This commit is contained in:
parent
8fe2718606
commit
162252e38d
7 changed files with 211 additions and 2 deletions
|
@ -14,6 +14,23 @@ endif()
|
||||||
|
|
||||||
add_executable(Graph
|
add_executable(Graph
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/renderer.cpp)
|
src/renderer.cpp
|
||||||
|
src/worldpass.cpp)
|
||||||
target_link_libraries(Graph PUBLIC SDL2::SDL2 SDL2::SDL2main ${Vulkan_LIBRARY})
|
target_link_libraries(Graph PUBLIC SDL2::SDL2 SDL2::SDL2main ${Vulkan_LIBRARY})
|
||||||
target_include_directories(Graph PUBLIC include ${Vulkan_INCLUDE_DIRS})
|
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)
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
|
#include "worldpass.h"
|
||||||
|
|
||||||
struct RenderTarget {
|
struct RenderTarget {
|
||||||
VkSurfaceKHR surface = nullptr;
|
VkSurfaceKHR surface = nullptr;
|
||||||
VkSwapchainKHR swapchain = nullptr;
|
VkSwapchainKHR swapchain = nullptr;
|
||||||
|
@ -30,10 +32,20 @@ public:
|
||||||
RenderTarget* createSurfaceRenderTarget(VkSurfaceKHR surface, RenderTarget* oldRenderTarget = nullptr);
|
RenderTarget* createSurfaceRenderTarget(VkSurfaceKHR surface, RenderTarget* oldRenderTarget = nullptr);
|
||||||
void destroyRenderTarget(RenderTarget* target);
|
void destroyRenderTarget(RenderTarget* target);
|
||||||
|
|
||||||
|
VkShaderModule createShader(const char* path);
|
||||||
|
|
||||||
VkInstance getInstance() const {
|
VkInstance getInstance() const {
|
||||||
return instance_;
|
return instance_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkDevice getDevice() const {
|
||||||
|
return device_;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkRenderPass getRenderPass() const {
|
||||||
|
return presentationRenderPass_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createInstance();
|
void createInstance();
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -66,4 +78,6 @@ private:
|
||||||
VkCommandPool commandPool_ = nullptr;
|
VkCommandPool commandPool_ = nullptr;
|
||||||
|
|
||||||
VkRenderPass presentationRenderPass_ = nullptr;
|
VkRenderPass presentationRenderPass_ = nullptr;
|
||||||
|
|
||||||
|
WorldPass* worldPass_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
20
include/worldpass.h
Normal file
20
include/worldpass.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
|
class Renderer;
|
||||||
|
|
||||||
|
class WorldPass {
|
||||||
|
public:
|
||||||
|
WorldPass(Renderer& renderer);
|
||||||
|
|
||||||
|
void render(VkCommandBuffer commandBuffer);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void createPipeline();
|
||||||
|
|
||||||
|
VkPipelineLayout pipelineLayout_ = nullptr;
|
||||||
|
VkPipeline pipeline_ = nullptr;
|
||||||
|
|
||||||
|
Renderer& renderer_;
|
||||||
|
};
|
7
shaders/triangle.frag
Normal file
7
shaders/triangle.frag
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#version 460 core
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
outColor = vec4(1.0);
|
||||||
|
}
|
11
shaders/triangle.vert
Normal file
11
shaders/triangle.vert
Normal file
|
@ -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);
|
||||||
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
@ -17,11 +18,15 @@ Renderer::Renderer() {
|
||||||
createLogicalDevice();
|
createLogicalDevice();
|
||||||
createCommandPool();
|
createCommandPool();
|
||||||
createPresentationRenderPass();
|
createPresentationRenderPass();
|
||||||
|
|
||||||
|
worldPass_ = new WorldPass(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Renderer::~Renderer() {
|
Renderer::~Renderer() {
|
||||||
vkDeviceWaitIdle(device_);
|
vkDeviceWaitIdle(device_);
|
||||||
|
|
||||||
|
delete worldPass_;
|
||||||
|
|
||||||
vkDestroyRenderPass(device_, presentationRenderPass_, nullptr);
|
vkDestroyRenderPass(device_, presentationRenderPass_, nullptr);
|
||||||
|
|
||||||
vkDestroyCommandPool(device_, commandPool_, nullptr);
|
vkDestroyCommandPool(device_, commandPool_, nullptr);
|
||||||
|
@ -49,6 +54,18 @@ void Renderer::render(RenderTarget* target) {
|
||||||
|
|
||||||
vkBeginCommandBuffer(commandBuffer, &beginInfo);
|
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 = {};
|
VkClearValue clearColor = {};
|
||||||
clearColor.color.float32[0] = sin((platform::getTime() / 500.0f) * 0.2f) * 0.5f + 0.5f;
|
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;
|
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;
|
renderPassBeginInfo.pClearValues = &clearColor;
|
||||||
|
|
||||||
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
|
|
||||||
|
worldPass_->render(commandBuffer);
|
||||||
|
|
||||||
vkCmdEndRenderPass(commandBuffer);
|
vkCmdEndRenderPass(commandBuffer);
|
||||||
|
|
||||||
vkEndCommandBuffer(commandBuffer);
|
vkEndCommandBuffer(commandBuffer);
|
||||||
|
@ -238,6 +257,26 @@ void Renderer::destroyRenderTarget(RenderTarget* target) {
|
||||||
delete 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<char> 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<const uint32_t*>(buffer.data());
|
||||||
|
|
||||||
|
VkShaderModule shaderModule;
|
||||||
|
vkCreateShaderModule(device_, &createInfo, nullptr, &shaderModule);
|
||||||
|
|
||||||
|
return shaderModule;
|
||||||
|
}
|
||||||
|
|
||||||
void Renderer::createInstance() {
|
void Renderer::createInstance() {
|
||||||
uint32_t layerCount = 0;
|
uint32_t layerCount = 0;
|
||||||
vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
|
vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
|
||||||
|
|
101
src/worldpass.cpp
Normal file
101
src/worldpass.cpp
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
#include "worldpass.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#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<VkPipelineShaderStageCreateInfo, 2> 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<VkDynamicState, 2> 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);
|
||||||
|
}
|
Reference in a new issue