diff --git a/VulkanTest b/VulkanTest index 6c769c1..c54f8a3 100755 Binary files a/VulkanTest and b/VulkanTest differ diff --git a/build/cve_renderer.d b/build/cve_renderer.d new file mode 100644 index 0000000..9de2d02 --- /dev/null +++ b/build/cve_renderer.d @@ -0,0 +1,6 @@ +build/cve_renderer.o: cve_renderer.cpp cve_renderer.hpp cve_window.hpp \ + cve_device.hpp cve_swap_chain.hpp +cve_renderer.hpp: +cve_window.hpp: +cve_device.hpp: +cve_swap_chain.hpp: diff --git a/build/cve_renderer.o b/build/cve_renderer.o new file mode 100644 index 0000000..dc26fb8 Binary files /dev/null and b/build/cve_renderer.o differ diff --git a/build/first_app.d b/build/first_app.d index 76a52c1..29f33e0 100644 --- a/build/first_app.d +++ b/build/first_app.d @@ -1,10 +1,12 @@ build/first_app.o: first_app.cpp first_app.hpp cve_window.hpp \ - cve_pipeline.hpp cve_device.hpp cve_swap_chain.hpp cve_game_object.hpp \ - cve_model.hpp + cve_device.hpp cve_game_object.hpp cve_model.hpp cve_renderer.hpp \ + cve_swap_chain.hpp simple_render_system.hpp cve_pipeline.hpp first_app.hpp: cve_window.hpp: -cve_pipeline.hpp: cve_device.hpp: -cve_swap_chain.hpp: cve_game_object.hpp: cve_model.hpp: +cve_renderer.hpp: +cve_swap_chain.hpp: +simple_render_system.hpp: +cve_pipeline.hpp: diff --git a/build/first_app.o b/build/first_app.o index 83d46c5..93acf03 100644 Binary files a/build/first_app.o and b/build/first_app.o differ diff --git a/build/main.d b/build/main.d index 5ff42ad..147c3d3 100644 --- a/build/main.d +++ b/build/main.d @@ -1,9 +1,9 @@ -build/main.o: main.cpp first_app.hpp cve_window.hpp cve_pipeline.hpp \ - cve_device.hpp cve_swap_chain.hpp cve_game_object.hpp cve_model.hpp +build/main.o: main.cpp first_app.hpp cve_window.hpp cve_device.hpp \ + cve_game_object.hpp cve_model.hpp cve_renderer.hpp cve_swap_chain.hpp first_app.hpp: cve_window.hpp: -cve_pipeline.hpp: cve_device.hpp: -cve_swap_chain.hpp: cve_game_object.hpp: cve_model.hpp: +cve_renderer.hpp: +cve_swap_chain.hpp: diff --git a/build/main.o b/build/main.o index c08fd61..5232a0f 100644 Binary files a/build/main.o and b/build/main.o differ diff --git a/build/simple_render_system.d b/build/simple_render_system.d new file mode 100644 index 0000000..b579d0f --- /dev/null +++ b/build/simple_render_system.d @@ -0,0 +1,9 @@ +build/simple_render_system.o: simple_render_system.cpp \ + simple_render_system.hpp cve_pipeline.hpp cve_device.hpp cve_window.hpp \ + cve_game_object.hpp cve_model.hpp +simple_render_system.hpp: +cve_pipeline.hpp: +cve_device.hpp: +cve_window.hpp: +cve_game_object.hpp: +cve_model.hpp: diff --git a/build/simple_render_system.o b/build/simple_render_system.o new file mode 100644 index 0000000..6280127 Binary files /dev/null and b/build/simple_render_system.o differ diff --git a/cve_renderer.cpp b/cve_renderer.cpp new file mode 100644 index 0000000..166d72d --- /dev/null +++ b/cve_renderer.cpp @@ -0,0 +1,143 @@ +#include "cve_renderer.hpp" + +#include +#include + +namespace cve { + CveRenderer::CveRenderer(CveWindow& window, CveDevice& device) : cveWindow{window}, cveDevice{device}{ + recreateSwapChain(); + createCommandBuffers(); + } + + CveRenderer::~CveRenderer() { + freeCommandBuffers(); + } + + void CveRenderer::recreateSwapChain() { + auto extent = cveWindow.getExtent(); + while (extent.width == 0 || extent.height == 0) { + extent = cveWindow.getExtent(); + glfwWaitEvents(); + } + + vkDeviceWaitIdle(cveDevice.device()); + + if (cveSwapChain == nullptr) { + cveSwapChain = std::make_unique(cveDevice, extent); + } else { + cveSwapChain = std::make_unique(cveDevice, extent, std::move(cveSwapChain)); + if (cveSwapChain->imageCount() != commandBuffers.size()) { + freeCommandBuffers(); + createCommandBuffers(); + } + } + + // Come back + } + + void CveRenderer::createCommandBuffers() { + commandBuffers.resize(cveSwapChain->imageCount()); + + VkCommandBufferAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandPool = cveDevice.getCommandPool(); + allocInfo.commandBufferCount = static_cast(commandBuffers.size()); + + if (vkAllocateCommandBuffers(cveDevice.device(), &allocInfo, commandBuffers.data()) != + VK_SUCCESS) { + throw std::runtime_error("Failed to allocate command buffers"); + } + } + + void CveRenderer::freeCommandBuffers() { + vkFreeCommandBuffers(cveDevice.device(), cveDevice.getCommandPool(), + static_cast(commandBuffers.size()), commandBuffers.data()); + commandBuffers.clear(); + } + + VkCommandBuffer CveRenderer::beginFrame() { + assert(!isFrameStarted && "Can't call begin frame if frame is already in progress"); + + auto result = cveSwapChain->acquireNextImage(¤tImageIndex); + + if (result == VK_ERROR_OUT_OF_DATE_KHR) { + recreateSwapChain(); + return nullptr; + } + if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { + throw std::runtime_error("Failed to acquire swap chain image!"); + } + + isFrameStarted = true; + + auto commandBuffer = getCurrentCommandBuffer(); + + VkCommandBufferBeginInfo beginInfo{}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + + if (vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) { + throw std::runtime_error("Failed to begin command buffer recording"); + } + + return commandBuffer; + } + void CveRenderer::endFrame() { + assert(isFrameStarted && "Can't end a frame that hasn't started"); + auto commandBuffer = getCurrentCommandBuffer(); + + if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS) { + throw std::runtime_error("Failed to record command buffer!"); + } + + auto result = cveSwapChain->submitCommandBuffers(&commandBuffer, ¤tImageIndex); + if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || cveWindow.wasWindowResized()) { + cveWindow.resetWindowResizedFlag(); + recreateSwapChain(); + } else if (result != VK_SUCCESS) { + throw std::runtime_error("Failed to present swap chain image!"); + } + + isFrameStarted = false; + } + + void CveRenderer::beginSwapChainRenderPass(VkCommandBuffer commandBuffer) { + assert(isFrameStarted && "Can't begin swap chain render pass if frame isn't started"); + assert(commandBuffer == getCurrentCommandBuffer() && + "Can't begin render pass on buffer from another frame."); + + VkRenderPassBeginInfo renderPassInfo{}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassInfo.renderPass = cveSwapChain->getRenderPass(); + renderPassInfo.framebuffer = cveSwapChain->getFrameBuffer(currentImageIndex); + + renderPassInfo.renderArea.offset = {0, 0}; + renderPassInfo.renderArea.extent = cveSwapChain->getSwapChainExtent(); + + std::array clearValues{}; + clearValues[0].color = {0.01f, 0.01f, 0.01f, 1.0f}; + clearValues[1].depthStencil = {1.0f, 0}; + renderPassInfo.clearValueCount = static_cast(clearValues.size()); + renderPassInfo.pClearValues = clearValues.data(); + + vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); + + VkViewport viewport{}; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = static_cast(cveSwapChain->getSwapChainExtent().width); + viewport.height = static_cast(cveSwapChain->getSwapChainExtent().height); + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + VkRect2D scissor{{0, 0}, cveSwapChain->getSwapChainExtent()}; + vkCmdSetViewport(commandBuffer, 0, 1, &viewport); + vkCmdSetScissor(commandBuffer, 0, 1, &scissor); + } + void CveRenderer::endSwapChainRenderPass(VkCommandBuffer commandBuffer) { + assert(isFrameStarted && "Can't end swap chain render pass if frame isn't started"); + assert(commandBuffer == getCurrentCommandBuffer() && + "Can't end render pass on buffer from another frame."); + + vkCmdEndRenderPass(commandBuffer); + } +} diff --git a/cve_renderer.hpp b/cve_renderer.hpp new file mode 100644 index 0000000..5a3e0d0 --- /dev/null +++ b/cve_renderer.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include "cve_window.hpp" +#include "cve_device.hpp" +#include "cve_swap_chain.hpp" + +#include +#include +#include + +namespace cve { + class CveRenderer { + public: + + CveRenderer(CveWindow &window, CveDevice &device); + ~CveRenderer(); + + CveRenderer(const CveRenderer &) = delete; + CveRenderer &operator=(const CveRenderer &) = delete; + + VkRenderPass getSwapChainRenderPass() const { return cveSwapChain->getRenderPass(); } + bool isFrameInProgress() const { return isFrameStarted; } + + VkCommandBuffer getCurrentCommandBuffer() const { + assert(isFrameStarted && "Cannot get command buffer when frame is not in progress"); + return commandBuffers[currentImageIndex]; + } + + VkCommandBuffer beginFrame(); + void endFrame(); + void beginSwapChainRenderPass(VkCommandBuffer commandBuffer); + void endSwapChainRenderPass(VkCommandBuffer commandBuffer); + + private: + void createCommandBuffers(); + void freeCommandBuffers(); + void recreateSwapChain(); + + CveWindow& cveWindow; + CveDevice& cveDevice; + std::unique_ptr cveSwapChain; + std::vector commandBuffers; + + uint32_t currentImageIndex; + bool isFrameStarted = false; + }; +} diff --git a/first_app.cpp b/first_app.cpp index 19acd31..671d372 100644 --- a/first_app.cpp +++ b/first_app.cpp @@ -1,4 +1,5 @@ #include "first_app.hpp" +#include "simple_render_system.hpp" #include #include @@ -9,27 +10,23 @@ #include namespace cve { - struct SimplePushConstantData{ - glm::mat2 transform{1.f}; // Identity matrix - glm::vec2 offset; - alignas(16) glm::vec3 color; - }; - FirstApp::FirstApp() { loadGameObjects(); - createPipelineLayout(); - recreateSwapChain(); - createCommandBuffers(); } - FirstApp::~FirstApp() { - vkDestroyPipelineLayout(cveDevice.device(), pipelineLayout, nullptr); - } + FirstApp::~FirstApp() {} void FirstApp::run() { + SimpleRenderSystem simpleRenderSystem{cveDevice, cveRenderer.getSwapChainRenderPass()}; + while (!cveWindow.shouldClose()) { glfwPollEvents(); - drawFrame(); + if (auto commandBuffer = cveRenderer.beginFrame()) { + cveRenderer.beginSwapChainRenderPass(commandBuffer); + simpleRenderSystem.renderGameObjects(commandBuffer, gameObjects); + cveRenderer.endSwapChainRenderPass(commandBuffer); + cveRenderer.endFrame(); + } } vkDeviceWaitIdle(cveDevice.device()); @@ -53,177 +50,4 @@ namespace cve { gameObjects.push_back(std::move(triangle)); } - - void FirstApp::createPipelineLayout() { - VkPushConstantRange pushConstantRange{}; - pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; - pushConstantRange.offset = 0; - pushConstantRange.size = sizeof(SimplePushConstantData); - - VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; - pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipelineLayoutInfo.setLayoutCount = 0; - pipelineLayoutInfo.pSetLayouts = nullptr; - pipelineLayoutInfo.pushConstantRangeCount = 1; - pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange; - if (vkCreatePipelineLayout(cveDevice.device(), &pipelineLayoutInfo, nullptr, &pipelineLayout) != - VK_SUCCESS) { - throw std::runtime_error("Failed to create pipeline layout"); - } - } - - void FirstApp::createPipeline() { - assert(cveSwapChain != nullptr && "Cannot create pipeline before swap chain"); - assert(pipelineLayout != nullptr && "Cannot create pipeline before pipeline layout"); - - PipelineConfigInfo pipelineConfig{}; - CvePipeline::defaultPipelineConfigInfo(pipelineConfig); - pipelineConfig.renderPass = cveSwapChain->getRenderPass(); - pipelineConfig.pipelineLayout = pipelineLayout; - cvePipeline = std::make_unique( - cveDevice, - "shaders/simple_shader.vert.spv", - "shaders/simple_shader.frag.spv", - pipelineConfig - ); - } - - void FirstApp::recreateSwapChain() { - auto extent = cveWindow.getExtent(); - while (extent.width == 0 || extent.height == 0) { - extent = cveWindow.getExtent(); - glfwWaitEvents(); - } - - vkDeviceWaitIdle(cveDevice.device()); - - if (cveSwapChain == nullptr) { - cveSwapChain = std::make_unique(cveDevice, extent); - } else { - cveSwapChain = std::make_unique(cveDevice, extent, std::move(cveSwapChain)); - if (cveSwapChain->imageCount() != commandBuffers.size()) { - freeCommandBuffers(); - createCommandBuffers(); - } - } - - // Check if render pass is compatible - createPipeline(); - } - - void FirstApp::createCommandBuffers() { - commandBuffers.resize(cveSwapChain->imageCount()); - - VkCommandBufferAllocateInfo allocInfo{}; - allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - allocInfo.commandPool = cveDevice.getCommandPool(); - allocInfo.commandBufferCount = static_cast(commandBuffers.size()); - - if (vkAllocateCommandBuffers(cveDevice.device(), &allocInfo, commandBuffers.data()) != - VK_SUCCESS) { - throw std::runtime_error("Failed to allocate command buffers"); - } - } - - void FirstApp::freeCommandBuffers() { - vkFreeCommandBuffers(cveDevice.device(), cveDevice.getCommandPool(), - static_cast(commandBuffers.size()), commandBuffers.data()); - commandBuffers.clear(); - } - - void FirstApp::recordCommandBuffer(int imageIndex) { - - VkCommandBufferBeginInfo beginInfo{}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - - if (vkBeginCommandBuffer(commandBuffers[imageIndex], &beginInfo) != VK_SUCCESS) { - throw std::runtime_error("Failed to begin command buffer recording"); - } - - VkRenderPassBeginInfo renderPassInfo{}; - renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassInfo.renderPass = cveSwapChain->getRenderPass(); - renderPassInfo.framebuffer = cveSwapChain->getFrameBuffer(imageIndex); - - renderPassInfo.renderArea.offset = {0, 0}; - renderPassInfo.renderArea.extent = cveSwapChain->getSwapChainExtent(); - - std::array clearValues{}; - clearValues[0].color = {0.01f, 0.01f, 0.01f, 1.0f}; - clearValues[1].depthStencil = {1.0f, 0}; - renderPassInfo.clearValueCount = static_cast(clearValues.size()); - renderPassInfo.pClearValues = clearValues.data(); - - vkCmdBeginRenderPass(commandBuffers[imageIndex], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); - - VkViewport viewport{}; - viewport.x = 0.0f; - viewport.y = 0.0f; - viewport.width = static_cast(cveSwapChain->getSwapChainExtent().width); - viewport.height = static_cast(cveSwapChain->getSwapChainExtent().height); - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - VkRect2D scissor{{0, 0}, cveSwapChain->getSwapChainExtent()}; - vkCmdSetViewport(commandBuffers[imageIndex], 0, 1, &viewport); - vkCmdSetScissor(commandBuffers[imageIndex], 0, 1, &scissor); - - renderGameObjects(commandBuffers[imageIndex]); - - - - vkCmdEndRenderPass(commandBuffers[imageIndex]); - if (vkEndCommandBuffer(commandBuffers[imageIndex]) != VK_SUCCESS) { - throw std::runtime_error("Failed to record command buffer!"); - } - } - - void FirstApp::renderGameObjects(VkCommandBuffer commandBuffer) { - cvePipeline->bind(commandBuffer); - - for (auto& obj: gameObjects) { - obj.transform2d.rotation = glm::mod(obj.transform2d.rotation + 0.001f, glm::two_pi()); - - SimplePushConstantData push{}; - push.offset = obj.transform2d.translation; - push.color = obj.color; - push.transform = obj.transform2d.mat2(); - - vkCmdPushConstants( - commandBuffer, - pipelineLayout, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, - 0, - sizeof(SimplePushConstantData), - &push - ); - - obj.model->bind(commandBuffer); - obj.model->draw(commandBuffer); - } - } - - void FirstApp::drawFrame() { - uint32_t imageIndex; - auto result = cveSwapChain->acquireNextImage(&imageIndex); - - if (result == VK_ERROR_OUT_OF_DATE_KHR) { - recreateSwapChain(); - return; - } - if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { - throw std::runtime_error("Failed to acquire swap chain image!"); - } - - recordCommandBuffer(imageIndex); - result = cveSwapChain->submitCommandBuffers(&commandBuffers[imageIndex], &imageIndex); - if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || cveWindow.wasWindowResized()) { - cveWindow.resetWindowResizedFlag(); - recreateSwapChain(); - return; - } - if (result != VK_SUCCESS) { - throw std::runtime_error("Failed to present swap chain image!"); - } - } } diff --git a/first_app.hpp b/first_app.hpp index efc124b..e423970 100644 --- a/first_app.hpp +++ b/first_app.hpp @@ -1,10 +1,9 @@ #pragma once #include "cve_window.hpp" -#include "cve_pipeline.hpp" #include "cve_device.hpp" -#include "cve_swap_chain.hpp" #include "cve_game_object.hpp" +#include "cve_renderer.hpp" #include #include @@ -24,21 +23,10 @@ namespace cve { void run(); private: void loadGameObjects(); - void createPipelineLayout(); - void createPipeline(); - void createCommandBuffers(); - void freeCommandBuffers(); - void drawFrame(); - void recreateSwapChain(); - void recordCommandBuffer(int imageIndex); - void renderGameObjects(VkCommandBuffer commandBuffer); CveWindow cveWindow{WIDTH, HEIGHT, "Hello Vulkan!"}; CveDevice cveDevice{cveWindow}; - std::unique_ptr cveSwapChain; - std::unique_ptr cvePipeline; - VkPipelineLayout pipelineLayout; - std::vector commandBuffers; + CveRenderer cveRenderer{cveWindow, cveDevice}; std::vector gameObjects; }; } diff --git a/simple_render_system.cpp b/simple_render_system.cpp new file mode 100644 index 0000000..2859b9c --- /dev/null +++ b/simple_render_system.cpp @@ -0,0 +1,85 @@ +#include "simple_render_system.hpp" + +#include +#include + +#define GLM_FORCE_RADIANS +#define GLM_FORCE_DEPTH_ZERO_TO_ONE +#include +#include + +namespace cve { + struct SimplePushConstantData{ + glm::mat2 transform{1.f}; // Identity matrix + glm::vec2 offset; + alignas(16) glm::vec3 color; + }; + + SimpleRenderSystem::SimpleRenderSystem(CveDevice& device, VkRenderPass renderPass): + cveDevice{device} { + createPipelineLayout(); + createPipeline(renderPass); + } + + SimpleRenderSystem::~SimpleRenderSystem() { + vkDestroyPipelineLayout(cveDevice.device(), pipelineLayout, nullptr); + } + + void SimpleRenderSystem::createPipelineLayout() { + VkPushConstantRange pushConstantRange{}; + pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; + pushConstantRange.offset = 0; + pushConstantRange.size = sizeof(SimplePushConstantData); + + VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; + pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutInfo.setLayoutCount = 0; + pipelineLayoutInfo.pSetLayouts = nullptr; + pipelineLayoutInfo.pushConstantRangeCount = 1; + pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange; + if (vkCreatePipelineLayout(cveDevice.device(), &pipelineLayoutInfo, nullptr, &pipelineLayout) != + VK_SUCCESS) { + throw std::runtime_error("Failed to create pipeline layout"); + } + } + + void SimpleRenderSystem::createPipeline(VkRenderPass renderPass) { + assert(pipelineLayout != nullptr && "Cannot create pipeline before pipeline layout"); + + PipelineConfigInfo pipelineConfig{}; + CvePipeline::defaultPipelineConfigInfo(pipelineConfig); + pipelineConfig.renderPass = renderPass; + pipelineConfig.pipelineLayout = pipelineLayout; + cvePipeline = std::make_unique( + cveDevice, + "shaders/simple_shader.vert.spv", + "shaders/simple_shader.frag.spv", + pipelineConfig + ); + } + + void SimpleRenderSystem::renderGameObjects(VkCommandBuffer commandBuffer, std::vector &gameObjects) { + cvePipeline->bind(commandBuffer); + + for (auto& obj: gameObjects) { + obj.transform2d.rotation = glm::mod(obj.transform2d.rotation + 0.001f, glm::two_pi()); + + SimplePushConstantData push{}; + push.offset = obj.transform2d.translation; + push.color = obj.color; + push.transform = obj.transform2d.mat2(); + + vkCmdPushConstants( + commandBuffer, + pipelineLayout, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, + 0, + sizeof(SimplePushConstantData), + &push + ); + + obj.model->bind(commandBuffer); + obj.model->draw(commandBuffer); + } + } +} diff --git a/simple_render_system.hpp b/simple_render_system.hpp new file mode 100644 index 0000000..5791d31 --- /dev/null +++ b/simple_render_system.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include "cve_pipeline.hpp" +#include "cve_device.hpp" +#include "cve_game_object.hpp" + +#include +#include + +namespace cve { + class SimpleRenderSystem { + public: + + SimpleRenderSystem(CveDevice &device, VkRenderPass renderPass); + ~SimpleRenderSystem(); + + SimpleRenderSystem(const SimpleRenderSystem &) = delete; + SimpleRenderSystem &operator=(const SimpleRenderSystem &) = delete; + void renderGameObjects(VkCommandBuffer commandBuffer, std::vector& gameObjects); + + private: + void createPipelineLayout(); + void createPipeline(VkRenderPass renderPass); + + CveDevice& cveDevice; + std::unique_ptr cvePipeline; + VkPipelineLayout pipelineLayout; + }; +}