From 864c0247bb2c061c7e1df02c9826f19608600108 Mon Sep 17 00:00:00 2001 From: JimmyBinoculars Date: Sun, 22 Feb 2026 17:27:44 +0000 Subject: [PATCH] Made simple render system --- VulkanTest | Bin 116472 -> 121824 bytes build/cve_renderer.d | 6 ++ build/cve_renderer.o | Bin 0 -> 23680 bytes build/first_app.d | 10 +- build/first_app.o | Bin 39488 -> 19648 bytes build/main.d | 8 +- build/main.o | Bin 3992 -> 3992 bytes build/simple_render_system.d | 9 ++ build/simple_render_system.o | Bin 0 -> 9264 bytes cve_renderer.cpp | 143 +++++++++++++++++++++++++ cve_renderer.hpp | 47 +++++++++ first_app.cpp | 196 ++--------------------------------- first_app.hpp | 16 +-- simple_render_system.cpp | 85 +++++++++++++++ simple_render_system.hpp | 29 ++++++ 15 files changed, 341 insertions(+), 208 deletions(-) create mode 100644 build/cve_renderer.d create mode 100644 build/cve_renderer.o create mode 100644 build/simple_render_system.d create mode 100644 build/simple_render_system.o create mode 100644 cve_renderer.cpp create mode 100644 cve_renderer.hpp create mode 100644 simple_render_system.cpp create mode 100644 simple_render_system.hpp diff --git a/VulkanTest b/VulkanTest index 6c769c1029b398bb5231aac4a803dbc6ccfc231d..c54f8a3f8945729f9603ae0e9efe24b98c91fa50 100755 GIT binary patch delta 37479 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

C?dv3mi-2#?j-l!o#Gcbf;0C>{hMbWj zYv{XVeC9CdjNIACt{kSWH)ZpOsh22gyqg@M);Wu;{z@`#lsX96n)(rn9}L)&wd<<8 z&dQ-Rbkv@zUOFrHFfQiXGPzD&)#f96s*&g9(0V$TqlH+Gnt&v!6VJ)5Yi?X2^!^yj Z&jugF+XLt1hBYVaYjYPA66#6y{trbYsbT;C delta 34464 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 literal 0 HcmV?d00001 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 83d46c560d82193948ea93c93f271f6064953cf0..93acf03419374b887df71465946f220817b41744 100644 GIT binary patch literal 19648 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 literal 39488 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 VF@9!h;GFEuqzt4s7cgn?0szwU62kxh delta 73 zcmbOsKSO@PF-DJx$DM>CSQr>mJi1v_H5eEeJUUxcJSIysY6yFPg|#8Vr92*uM4zJ2@lY4^0pAKX}Du@Fuc@+~sc;wT}R>t^b0wAx0lCW|QVmC&}c zZf~!$;=@4kLZ4FnG^7+?RYuP_qDrZDc_T0=MW4$iA5n@6UCQW3(onlnx*aN(ye$1@ z&cpReX^BfI?FP1;w%^w-B}xg{qsq;OaK2p`J?hx8(|gyr1bzEX>VJLj+A*d0j(qYg z4z3ja@Vo?LxuEJ$il>6bcZ?pU_q|`x=2$G|mX_|N29Hfj*L@UHO7%+dWBH^~8geM5 zLxWaAnBWeZvhNN3TBZ0F8{@6#ogld5pC~OYZ6iCz1#Ms#>g!X=TO2Xz{Uh?p5X^tu zCG%Hc{$-!5Rw?T)hcw^k0&9J)7Bt}{fail=W&$+ld7uepGY$u(16Kh`4=xc3FQjJe zJ0k5v4s@6@h1IP_Jx#(&b8E_>zZAHk$YW@0D_&P zdmKdC+X92(qJ6BC?{{_oZaoY%sXUF7=th6zn$i&_r3X5|eb&QH;E)#KGSs@H`FmY9 z&_+3epunS)uY!IUb0SzyxZ0F*_Drxi6)YxPp0m$?IyDt6M_mra6a*(Z4UTt%MR3^J zA0r3Gg;HvE1&jX+7SAZf_o;TJbid0HY`v)4(GMV&u}tHhVC(w^4g)egSc=$`;x1d) zzPI(Og2i_!GhJTZP)g6aPQdJyeN#Hj?ANZ-*jVuyQ)~EX#^18?&{1?J#;A9v_inE` zu9R_ekY{hj8JE{!T`6zCg6g0z3>l?3PDAR8)Mv#n?6p6`Ui%ng4JNcsd8yMjJ%UpF z_jK@%9<@O<7(-0Z;bJuYc{~J)ud!`A391H_(jM4-!q(j;AE5>ZV2gE?qApvY^{BLW z2lymVoWOW+;sP(hh;ZP_HPHRwpdOg?O53_tO-hb$plMK2CrFJiOiFjxAtW`Pka}O0 z+#eNyYt;$ZJ}0NS`d*)uR-Tj^&rC`$o}MH1zB?)1^_sNxRjKjCN$E~19xVPBq9`yr z(E@$PsNVTO*F0u#-`jLM9tVv8!aLz=@E*d=17LH4cj!7$mE+?~X_c5jT=B#>G>p5xP;m@X~FqR>M@FXa~o*onej0#Ro zSqMC}8E^%ZwyW#f$%a+5e)ZOy9=DR8Sn8g(lEap|?^?-UEOo!NQuc0xy>_vqiME$P zdt*4B(4tN~?Tlo#u&y~X@r;&;r!;3GJd)1qxKv1mbUf;e6twm0L-AxLq4j8~sFn?l zrrEFFbw18Zp~3^RHNyRWy1sRT&7U1zo2DxqyMl2lu&2#ZHlSQNS&s%x)()$w?TCiArIb;7}C_#)E=W| zdUtkotamo{_2*N1-YKtkuXcNGS(~TLrU#mu-JWK*yn=OrXe~VGa@@R~oBIf)%_E4x zPcNl~thC(MLoCA%%i?+UwlT;wxM!EJzMo;)Zg(80>9jZOxBBeP(b`VCrzSYp?)2Il zymm*s-R8Sun%{C?caUnU{}Dy7{WY8H4Wlr2re^nCIwo*?uOJP;GmOkYId~|)Ju_}{|SrrhnKM*G*l#1T}wWgs?=%4s4>yC(5?}18Y7IyO6Hij zji!~@X5mFZY6KkD5a~sD5a)>yeT`HHh9dro(In_EqyY6%Jvn4Fr{9|y{`xdxR6-1I zG~wGQKG%d2vXk)-ntJ*vj*)RG4N!dEr69DDjNj~u9K&g>2vQ>qH*4BM@p^&NsO|+E z_q&;nRl)yQ1;-QE0`T-ROcCx^N)QUmYUojeHu*f30A6X_<|=qs6}-L*-UoOkd-4pY z7bLIW{O!eRD`(r>c?RVOf@&`op<+M9t~hcxoUJ3F)#N84PDtJsXbexj@7p z3d74UH>q7}B%K1jd_)g)Zvw2)tA<+Ckly5hQ`Jy78&%`FmJRD^kcMMZJeLi-Jp_hZ z4d*<$W%fC*$#dyB&p6BZ3+_ld5xtzC+R;Z|t>|caboTcolO(AnBbgDR z!U}~WyVS_wE;R;6?8|w_*W@n{-yQC(7IUlW!0@n|fs<`I6;8zU5w+kUgs|r*+EU6yD{NL7BQen&>Vhrx_}&CFA?jYYoP9(An|N616k9rQI7;w`|-P^7pE}-u9qhtth~(?G4OQ z1)j!%^}%dPRP(;Z(Fe zAB$;OwYMjvuPs1tIvYT@t%hwiBZ7%F)U5jb(<6y%*4z&vR#7P=_EaRDi{ZveM!WO5 zK?n~>4k9Y0QA>T>x*j z9DiKE7YX=r0l!ATPYF1l!MUD$**O5mT`J&@3Am{LqJZP40MoHqy5R98b+09}@K33^>>GsDLjP@F%O_&k49V-{S%<>UpOMzJQ%Kup3Y7+@9+M z9M9MsUoPNy+U594hNFL03HYr7F8cX^fa6DHuIKv#j&~4_pB8Xgz!&0xKxjYy2f+ES z7jQ|yR|+_udpQ3Z0msj09PbwJ1p=-MxX3@oa4ebx{#9`PLPC5sJY0W^fHw=cPr&iB zE$6>iz(s$a1s){SFRr_BPcr<2qFm2y%%A8t#QC>^P7_{+KBSNde~_Yts3tta@TW}p z%M9l?V6@W-54VTkoY0=H3wQ(6k&u5GJe(gtXd~fXya67LuSF0D^|;{SI6r@*p5+4G z1$89E@y^WoH3WeWzX=|W--93!;-df46rGK8zasxF@Nhj33j88o7I1MLpQ?gS2)Jk` z_qW;3Hw1n$Z&Zt)^8&x9pTYEc$-jpo=42h{e|$Kptb!O{Q-t_;49@=yLyspx11nx+k^@ckW**zSRBI?odm^V3%?J^?|@_hxEi0FNU)<6w;7S|ah%33Xf| zo(G{yshgE~F-QS(Fq{{d6Hr$h2UvNQ{v|+&jSYn3pN zGQ41tH{00*{gwQG9uK2H_&pH`{f}ew@wxwFfK{^p6E;3m16&4iyLp)h80&Zz5vhR< zWR4decf9-#2vw5zRFUWUc=;HUx0)Q&#^m{Yxozh57<5qondA>)U;}YKq5rOghs$&P z1;EgL4?H3%jL|KEP)A-QUgGZ}uhS0pD)50sumbNXz;LNd=96J2?}R>)%xXV`P8{DX ze~>YrHyLM^$KRn!@pppx?;w*$|6z=9dG5bTV*?v`crLyn->^J@>4e8H;#?l@IOe^N e{Ri=o4YbL$u}ssUxwDe|ApKt+bejZBP4a)~d6JU= literal 0 HcmV?d00001 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; + }; +}