diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index f3014ae..0033434 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -22,4 +22,6 @@ set(HEADERS add_library(engine STATIC ${SOURCES}) +add_subdirectory(program) + target_include_directories(engine PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/engine/engine.cpp b/engine/engine.cpp index e0e84c5..d236470 100644 --- a/engine/engine.cpp +++ b/engine/engine.cpp @@ -8,7 +8,8 @@ Engine::Engine::Engine() : physicalDevice(nullptr), logicalDevice(nullptr), deviceExtensionNames(), - deviceExtensions() + deviceExtensions(), + programs() { addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); } @@ -31,6 +32,13 @@ void Engine::Engine::enableDebug() { instance->enableDebug(); } +void Engine::Engine::addProgram(const Program& program) { + programs.emplace_back(program); + + if (logicalDevice != nullptr) + logicalDevice->addProgram(program); +} + void Engine::Engine::initVulkan() { instance->initialize(window->getRequiredVulkanExtensions()); surface = new Surface(instance, window); @@ -38,7 +46,10 @@ void Engine::Engine::initVulkan() { pickPhysicalDevice(); logicalDevice = new LogicalDevice(physicalDevice, surface, deviceExtensions, instance->getLayers()); - logicalDevice->createGraphicsPipeline("shaders/shader.vert.spv", "shaders/shader.frag.spv"); + //logicalDevice->createGraphicsPipeline("shaders/shader.vert.spv", "shaders/shader.frag.spv"); + for (const Program& program : programs) + logicalDevice->addProgram(program); + logicalDevice->createSwapChain(); } @@ -53,6 +64,7 @@ void Engine::Engine::cleanup() { surface = nullptr; instance->deinitialize(); + programs.clear(); } void Engine::Engine::pickPhysicalDevice() { diff --git a/engine/engine.h b/engine/engine.h index a745c0c..0735a4e 100644 --- a/engine/engine.h +++ b/engine/engine.h @@ -26,6 +26,7 @@ #include "instance.h" #include "physicaldevice.h" #include "logicaldevice.h" +#include "program/program.h" namespace Engine { @@ -39,6 +40,7 @@ public: void run(); void addDeviceExtension(const std::string& extensionName); void enableDebug(); + void addProgram(const Program& program); private: void initVulkan(); @@ -56,6 +58,7 @@ private: LogicalDevice* logicalDevice; std::set deviceExtensionNames; std::vector deviceExtensions; + std::vector programs; }; diff --git a/engine/logicaldevice.cpp b/engine/logicaldevice.cpp index 81176fe..e1b2689 100644 --- a/engine/logicaldevice.cpp +++ b/engine/logicaldevice.cpp @@ -17,8 +17,6 @@ Engine::LogicalDevice::LogicalDevice( graphicsQueue(), presentQueue(), renderPass(), - pipelineLayout(), - graphicsPipeline(), commandPool(), commandBuffers(), imageAvailableSemaphores(), @@ -26,7 +24,6 @@ Engine::LogicalDevice::LogicalDevice( inFlightFences(), currentFrame(0), framebufferResized(false), - hasPipeline(false), surface(surface), surfaceFormat(surface->chooseSwapSurfaceFormat(phys->swapChainSupport)), swapChain(nullptr) @@ -45,10 +42,7 @@ Engine::LogicalDevice::LogicalDevice( Engine::LogicalDevice::~LogicalDevice() { clearSwapChain(); - if (hasPipeline) { - vkDestroyPipeline(vk, graphicsPipeline, nullptr); - vkDestroyPipelineLayout(vk, pipelineLayout, nullptr); - } + pipelines.clear(); vkDestroyRenderPass(vk, renderPass, nullptr); @@ -64,6 +58,10 @@ Engine::LogicalDevice::~LogicalDevice() { vkDestroyDevice(vk, nullptr); } +void Engine::LogicalDevice::addProgram(const Program& program) { + pipelines.emplace_back(program, this); +} + void Engine::LogicalDevice::createSwapChain() { clearSwapChain(); swapChain = new SwapChain(this); @@ -126,25 +124,6 @@ VkResult Engine::LogicalDevice::queuePresent(const VkSemaphore& signal, uint32_t return vkQueuePresentKHR(presentQueue, &presentInfo); } -VkShaderModule Engine::LogicalDevice::createShaderModule(const std::string& path) { - std::vector code = readFile(path); - - VkShaderModuleCreateInfo createInfo{}; - createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - createInfo.codeSize = code.size(); - createInfo.pCode = reinterpret_cast(code.data()); - - VkShaderModule shaderModule; - if (vkCreateShaderModule(vk, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) - throw std::runtime_error("failed to create shader module!"); - - return shaderModule; -} - -void Engine::LogicalDevice::destroyShaderModule(VkShaderModule shaderModule) { - vkDestroyShaderModule(vk, shaderModule, nullptr); -} - void Engine::LogicalDevice::createDevice( VkPhysicalDevice physicalDevice, const QueueFamilyIndices& indices, @@ -154,7 +133,6 @@ void Engine::LogicalDevice::createDevice( std::vector queueCreateInfos; std::set uniqueQueueFamilies = {indices.graphicsFamily.value(), indices.presentFamily.value()}; - for (uint32_t queueFamily : uniqueQueueFamilies) { VkDeviceQueueCreateInfo queueCreateInfo{}; queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; @@ -248,8 +226,12 @@ void Engine::LogicalDevice::drawFrame() { resetFence(inFlightFences[currentFrame]); - vkResetCommandBuffer(commandBuffers[currentFrame], /*VkCommandBufferResetFlagBits*/ 0); - recordCommandBuffer(commandBuffers[currentFrame], imageIndex); + if (!pipelines.empty()) { + vkResetCommandBuffer(commandBuffers[currentFrame], /*VkCommandBufferResetFlagBits*/ 0); + recordCommandBuffer(commandBuffers[currentFrame], imageIndex); + } else { + std::cout << "no pipelines attached, skipping command buffer record" << std::endl; + } if (queueSubmitGraphics( imageAvailableSemaphores[currentFrame], @@ -413,114 +395,6 @@ void Engine::LogicalDevice::createRenderPass(VkFormat format) { throw std::runtime_error("failed to create render pass!"); } -void Engine::LogicalDevice::createGraphicsPipeline(const std::string& vertexShaderPath, const std::string& fragmentShaderPath) { - if (hasPipeline) - throw std::runtime_error("an attempt to create graphics pipeline for the second time"); - - VkShaderModule vertShaderModule = createShaderModule(vertexShaderPath); - VkShaderModule fragShaderModule = createShaderModule(fragmentShaderPath); - - 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"; - - VkPipelineShaderStageCreateInfo 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; - inputAssembly.primitiveRestartEnable = VK_FALSE; - - 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.depthClampEnable = VK_FALSE; - rasterizer.rasterizerDiscardEnable = VK_FALSE; - rasterizer.polygonMode = VK_POLYGON_MODE_FILL; - rasterizer.lineWidth = 1.0f; - rasterizer.cullMode = VK_CULL_MODE_BACK_BIT; - rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; - rasterizer.depthBiasEnable = VK_FALSE; - - VkPipelineMultisampleStateCreateInfo multisampling{}; - multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisampling.sampleShadingEnable = VK_FALSE; - 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.logicOpEnable = VK_FALSE; - colorBlending.logicOp = VK_LOGIC_OP_COPY; - colorBlending.attachmentCount = 1; - colorBlending.pAttachments = &colorBlendAttachment; - colorBlending.blendConstants[0] = 0.0f; - colorBlending.blendConstants[1] = 0.0f; - colorBlending.blendConstants[2] = 0.0f; - colorBlending.blendConstants[3] = 0.0f; - - std::vector dynamicStates = { - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_SCISSOR - }; - VkPipelineDynamicStateCreateInfo dynamicState{}; - dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamicState.dynamicStateCount = static_cast(dynamicStates.size()); - dynamicState.pDynamicStates = dynamicStates.data(); - - VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; - pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipelineLayoutInfo.setLayoutCount = 0; - pipelineLayoutInfo.pushConstantRangeCount = 0; - - if (vkCreatePipelineLayout(vk, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) - throw std::runtime_error("failed to create pipeline layout!"); - - VkGraphicsPipelineCreateInfo pipelineInfo{}; - pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipelineInfo.stageCount = 2; - pipelineInfo.pStages = shaderStages; - 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 = renderPass; - pipelineInfo.subpass = 0; - pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; - - if (vkCreateGraphicsPipelines(vk, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) - throw std::runtime_error("failed to create graphics pipeline!"); - - destroyShaderModule(fragShaderModule); - destroyShaderModule(vertShaderModule); - - hasPipeline = true; -} - void Engine::LogicalDevice::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { VkExtent2D extent = swapChain->getExtent(); VkCommandBufferBeginInfo beginInfo{}; @@ -542,7 +416,8 @@ void Engine::LogicalDevice::recordCommandBuffer(VkCommandBuffer commandBuffer, u vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); - vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline); + for (const Pipeline& pipeline: pipelines) { + pipeline.bind(commandBuffer); VkViewport viewport{}; viewport.x = 0.0f; @@ -559,6 +434,7 @@ void Engine::LogicalDevice::recordCommandBuffer(VkCommandBuffer commandBuffer, u vkCmdSetScissor(commandBuffer, 0, 1, &scissor); vkCmdDraw(commandBuffer, 3, 1, 0, 0); + } vkCmdEndRenderPass(commandBuffer); @@ -572,3 +448,28 @@ void Engine::LogicalDevice::recreateSwapChain() { phys->recreateSwapChainSupportDetails(surface); createSwapChain(); } + +VkResult Engine::LogicalDevice::createPipelineLayout(const VkPipelineLayoutCreateInfo& info, VkPipelineLayout& out) { + return vkCreatePipelineLayout(vk, &info, nullptr, &out); +} + +VkResult Engine::LogicalDevice::createPipeline(VkGraphicsPipelineCreateInfo& info, VkPipeline& out) { + info.renderPass = renderPass; + return vkCreateGraphicsPipelines(vk, VK_NULL_HANDLE, 1, &info, nullptr, &out); +} + +VkResult Engine::LogicalDevice::createShaderModule(const VkShaderModuleCreateInfo& info, VkShaderModule& out) { + return vkCreateShaderModule(vk, &info, nullptr, &out); +} + +void Engine::LogicalDevice::destroyPipeline(VkPipeline& pipline) { + vkDestroyPipeline(vk, pipline, nullptr); +} + +void Engine::LogicalDevice::destroyPipelineLayout(VkPipelineLayout& layout) { + vkDestroyPipelineLayout(vk, layout, nullptr); +} + +void Engine::LogicalDevice::destroyShaderModule(VkShaderModule& module) { + vkDestroyShaderModule(vk, module, nullptr); +} diff --git a/engine/logicaldevice.h b/engine/logicaldevice.h index 4c53aef..8e0cc47 100644 --- a/engine/logicaldevice.h +++ b/engine/logicaldevice.h @@ -8,6 +8,8 @@ #include "utils.h" #include "physicaldevice.h" #include "surface.h" +#include "program/pipeline.h" +#include "program/program.h" namespace Engine { class SwapChain; @@ -24,9 +26,9 @@ public: void createSwapChain(); void clearSwapChain(); - void createGraphicsPipeline(const std::string& vertexShaderPath, const std::string& fragmentShaderPath); void recreateSwapChain(); void setResized(); + void addProgram(const Program& program); void drawFrame(); @@ -42,10 +44,14 @@ public: void destroyVkImageView(VkImageView& view); VkResult createVkFrameBuffer(const VkImageView& imageView, const VkExtent2D& extent, VkFramebuffer& out); void destroyVkFrameBuffer(VkFramebuffer& buffer); + VkResult createPipeline(VkGraphicsPipelineCreateInfo& info, VkPipeline& out); + VkResult createPipelineLayout(const VkPipelineLayoutCreateInfo& info, VkPipelineLayout& out); + void destroyPipelineLayout(VkPipelineLayout& layout); + void destroyPipeline(VkPipeline& pipline); + VkResult createShaderModule(const VkShaderModuleCreateInfo& info, VkShaderModule& out); + void destroyShaderModule(VkShaderModule& shaderModule); private: - VkShaderModule createShaderModule(const std::string& path); - void destroyShaderModule(VkShaderModule shaderModule); void createDevice( VkPhysicalDevice physicalDevice, const QueueFamilyIndices& indices, @@ -73,8 +79,7 @@ private: VkQueue graphicsQueue; VkQueue presentQueue; VkRenderPass renderPass; - VkPipelineLayout pipelineLayout; - VkPipeline graphicsPipeline; + std::vector pipelines; VkCommandPool commandPool; std::vector commandBuffers; std::vector imageAvailableSemaphores; @@ -82,7 +87,6 @@ private: std::vector inFlightFences; uint32_t currentFrame; bool framebufferResized; - bool hasPipeline; Surface* surface; VkSurfaceFormatKHR surfaceFormat; SwapChain* swapChain; diff --git a/engine/program/CMakeLists.txt b/engine/program/CMakeLists.txt new file mode 100644 index 0000000..a963d1a --- /dev/null +++ b/engine/program/CMakeLists.txt @@ -0,0 +1,11 @@ +set(SOURCES + pipeline.cpp + program.cpp +) + +set(HEADERS + pipeline.h + program.h +) + +target_sources(engine PRIVATE ${SOURCES}) diff --git a/engine/program/pipeline.cpp b/engine/program/pipeline.cpp new file mode 100644 index 0000000..9628736 --- /dev/null +++ b/engine/program/pipeline.cpp @@ -0,0 +1,149 @@ +#include "pipeline.h" +#include "logicaldevice.h" + +Engine::Pipeline::Pipeline(const Program& program, LogicalDevice* device): + device(device), + program(program), + vk(), + layout() +{ + createLayout(); + createPipeline(); +} + +Engine::Pipeline::Pipeline(const Pipeline& other): + device(other.device), + program(other.program), + vk(), + layout() +{ + createLayout(); + createPipeline(); +} + +Engine::Pipeline::~Pipeline() { + device->destroyPipeline(vk); + device->destroyPipelineLayout(layout); +} + +void Engine::Pipeline::createLayout() { + VkPipelineLayoutCreateInfo info{}; + info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + info.setLayoutCount = 0; + info.pushConstantRangeCount = 0; + + if (device->createPipelineLayout(info, layout) != VK_SUCCESS) + throw std::runtime_error("failed to create pipeline layout!"); +} + +VkShaderModule Engine::Pipeline::createShaderModule(Program::ShaderType type) { + VkShaderModuleCreateInfo info{}; + info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + info.codeSize = program.codeSize(type); + info.pCode = program.code(type); + + VkShaderModule module; + if (device->createShaderModule(info, module) != VK_SUCCESS) + throw std::runtime_error("failed to create shader module!"); + + return module; +} + +void Engine::Pipeline::createPipeline() { + VkShaderModule vertShaderModule = createShaderModule(Program::vertex); + VkShaderModule fragShaderModule = createShaderModule(Program::fragment); + + 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"; + + VkPipelineShaderStageCreateInfo 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; + inputAssembly.primitiveRestartEnable = VK_FALSE; + + 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.depthClampEnable = VK_FALSE; + rasterizer.rasterizerDiscardEnable = VK_FALSE; + rasterizer.polygonMode = VK_POLYGON_MODE_FILL; + rasterizer.lineWidth = 1.0f; + rasterizer.cullMode = VK_CULL_MODE_BACK_BIT; + rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; + rasterizer.depthBiasEnable = VK_FALSE; + + VkPipelineMultisampleStateCreateInfo multisampling{}; + multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampling.sampleShadingEnable = VK_FALSE; + 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.logicOpEnable = VK_FALSE; + colorBlending.logicOp = VK_LOGIC_OP_COPY; + colorBlending.attachmentCount = 1; + colorBlending.pAttachments = &colorBlendAttachment; + colorBlending.blendConstants[0] = 0.0f; + colorBlending.blendConstants[1] = 0.0f; + colorBlending.blendConstants[2] = 0.0f; + colorBlending.blendConstants[3] = 0.0f; + + std::vector dynamicStates = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR + }; + VkPipelineDynamicStateCreateInfo dynamicState{}; + dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamicState.dynamicStateCount = static_cast(dynamicStates.size()); + dynamicState.pDynamicStates = dynamicStates.data(); + + VkGraphicsPipelineCreateInfo pipelineInfo{}; + pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineInfo.stageCount = 2; + pipelineInfo.pStages = shaderStages; + pipelineInfo.pVertexInputState = &vertexInputInfo; + pipelineInfo.pInputAssemblyState = &inputAssembly; + pipelineInfo.pViewportState = &viewportState; + pipelineInfo.pRasterizationState = &rasterizer; + pipelineInfo.pMultisampleState = &multisampling; + pipelineInfo.pColorBlendState = &colorBlending; + pipelineInfo.pDynamicState = &dynamicState; + pipelineInfo.layout = layout; + //pipelineInfo.renderPass = renderPass; + pipelineInfo.subpass = 0; + pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; + + if (device->createPipeline(pipelineInfo, vk) != VK_SUCCESS) + throw std::runtime_error("failed to create graphics pipeline!"); + + device->destroyShaderModule(fragShaderModule); + device->destroyShaderModule(vertShaderModule); +} + +void Engine::Pipeline::bind(const VkCommandBuffer& buffer) const { + vkCmdBindPipeline(buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vk); +} diff --git a/engine/program/pipeline.h b/engine/program/pipeline.h new file mode 100644 index 0000000..37c5d8e --- /dev/null +++ b/engine/program/pipeline.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include + +#include + +#include "program.h" + +namespace Engine { +class LogicalDevice; + +class Pipeline { +public: + Pipeline(const Program& program, LogicalDevice* device); + Pipeline(const Pipeline& other); + ~Pipeline(); + + void bind(const VkCommandBuffer& buffer) const; + +private: + void createLayout(); + void createPipeline(); + VkShaderModule createShaderModule(Program::ShaderType type); + +private: + LogicalDevice* device; + const Program& program; + VkPipeline vk; + VkPipelineLayout layout; +}; + +} diff --git a/engine/program/program.cpp b/engine/program/program.cpp new file mode 100644 index 0000000..16e63c2 --- /dev/null +++ b/engine/program/program.cpp @@ -0,0 +1,38 @@ +#include "program.h" + +Engine::Program::Program(): + vertexShader(), + fragmentShader() +{} + + +std::size_t Engine::Program::codeSize(ShaderType type) const { + switch (type) { + case vertex: + return vertexShader.size(); + case fragment: + return fragmentShader.size(); + } + + return 0; +} + +const uint32_t* Engine::Program::code(ShaderType type) const { + switch (type) { + case vertex: + return reinterpret_cast(vertexShader.data()); + case fragment: + return reinterpret_cast(fragmentShader.data()); + } + + return nullptr; +} + +void Engine::Program::loadSPIRV(const std::string& path, ShaderType type) { + switch (type) { + case vertex: + vertexShader = readFile(path); + case fragment: + fragmentShader = readFile(path); + } +} diff --git a/engine/program/program.h b/engine/program/program.h new file mode 100644 index 0000000..1d48fb2 --- /dev/null +++ b/engine/program/program.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include +#include + +#include + +#include "utils.h" + +namespace Engine { + +class Program { +public: + enum ShaderType { + vertex, + fragment + }; + Program(); + + void loadSPIRV(const std::string& path, ShaderType type); + std::size_t codeSize(ShaderType type) const; + const uint32_t* code(ShaderType type) const; + +private: + std::vector vertexShader; + std::vector fragmentShader; +}; + +} diff --git a/engine/swapchain.cpp b/engine/swapchain.cpp index 535d329..763a026 100644 --- a/engine/swapchain.cpp +++ b/engine/swapchain.cpp @@ -13,17 +13,6 @@ Engine::SwapChain::SwapChain(LogicalDevice* logical): create(); } -Engine::SwapChain::SwapChain(LogicalDevice* logical, const VkExtent2D& extent): - logical(logical), - vk(), - images(), - extent(extent), - imageViews(), - frameBuffers() -{ - create(); -} - void Engine::SwapChain::create() { VkResult result = logical->createVkSwapChain(extent, vk); diff --git a/engine/swapchain.h b/engine/swapchain.h index 7207ea0..10f5bde 100644 --- a/engine/swapchain.h +++ b/engine/swapchain.h @@ -11,7 +11,6 @@ class SwapChain { friend class LogicalDevice; public: SwapChain(LogicalDevice* logical); - SwapChain(LogicalDevice* logical, const VkExtent2D& extent); ~SwapChain(); VkExtent2D getExtent() const; diff --git a/engine/utils.cpp b/engine/utils.cpp index 90d6777..8b13e02 100644 --- a/engine/utils.cpp +++ b/engine/utils.cpp @@ -153,7 +153,7 @@ std::vector Engine::readFile(const std::string& filename) { std::ifstream file(filename, std::ios::ate | std::ios::binary); if (!file.is_open()) - throw std::runtime_error("failed to open file!"); + throw std::runtime_error("failed to open file " + filename); size_t fileSize = (size_t) file.tellg(); std::vector buffer(fileSize); diff --git a/main.cpp b/main.cpp index 357e5bb..d99d95d 100644 --- a/main.cpp +++ b/main.cpp @@ -1,9 +1,24 @@ #include "engine/engine.h" +#include "engine/program/program.h" + int main() { Engine::Engine app; app.enableDebug(); + Engine::Program tl; + Engine::Program br; + + //logicalDevice->createGraphicsPipeline("shaders/shader.vert.spv", "shaders/shader.frag.spv"); + tl.loadSPIRV("shaders/tl.vert.spv", Engine::Program::vertex); + tl.loadSPIRV("shaders/shader.frag.spv", Engine::Program::fragment); + + br.loadSPIRV("shaders/br.vert.spv", Engine::Program::vertex); + br.loadSPIRV("shaders/shader.frag.spv", Engine::Program::fragment); + + app.addProgram(tl); + app.addProgram(br); + try { app.run(); } catch (const std::exception& e) { diff --git a/shaders/br.vert b/shaders/br.vert new file mode 100644 index 0000000..5f3b6bb --- /dev/null +++ b/shaders/br.vert @@ -0,0 +1,20 @@ +#version 450 + +layout(location = 0) out vec3 fragColor; + +vec2 positions[3] = vec2[]( + vec2(0.5, -0.5), + vec2(0.5, 0.5), + vec2(-0.5, -0.5) +); + +vec3 colors[3] = vec3[]( + vec3(1.0, 0.0, 0.0), + vec3(0.0, 1.0, 0.0), + vec3(0.0, 0.0, 1.0) +); + +void main() { + gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); + fragColor = colors[gl_VertexIndex]; +} diff --git a/shaders/tl.vert b/shaders/tl.vert new file mode 100644 index 0000000..708f076 --- /dev/null +++ b/shaders/tl.vert @@ -0,0 +1,20 @@ +#version 450 + +layout(location = 0) out vec3 fragColor; + +vec2 positions[3] = vec2[]( + vec2(0.5, 0.5), + vec2(-0.5, 0.5), + vec2(-0.5, -0.5) +); + +vec3 colors[3] = vec3[]( + vec3(1.0, 0.0, 0.0), + vec3(0.0, 1.0, 0.0), + vec3(0.0, 0.0, 1.0) +); + +void main() { + gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); + fragColor = colors[gl_VertexIndex]; +}