diff --git a/main.cpp b/main.cpp index 4ce022f..d1442b9 100644 --- a/main.cpp +++ b/main.cpp @@ -53,6 +53,107 @@ const std::vector vertices = { const std::vector indices = { 0, 1, 2, 2, 3, 0 }; +struct CustomShader { + + void create(VkDevice device) { + std::vector vertShaderByteCode = readFile("bin/vert.spv"); + mVertexModule = createShaderModule(device, vertShaderByteCode); + + std::vector fragShaderByteCode = readFile("bin/frag.spv"); + mFragmentModule = createShaderModule(device, fragShaderByteCode); + + VkPipelineShaderStageCreateInfo vertShaderStageCreateInfo{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_VERTEX_BIT, + .module = mVertexModule, + .pName = "main", + }; + + VkPipelineShaderStageCreateInfo fragShaderStageCreateInfo{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_FRAGMENT_BIT, + .module = mFragmentModule, + .pName = "main", + }; + + mStageCreateInfos = { + vertShaderStageCreateInfo, + fragShaderStageCreateInfo + }; + } + + void destroy(VkDevice device) const { + vkDestroyShaderModule(device, mVertexModule, nullptr); + vkDestroyShaderModule(device, mFragmentModule, nullptr); + } + + static std::vector readFile(const std::string &fileName) { + std::ifstream file(fileName, std::ios::ate | std::ios::binary); + + if (!file.is_open()) { + throw std::runtime_error("cannot open file"); + } + + size_t fileSize = (size_t) file.tellg(); + std::vector buffer(fileSize); + + file.seekg(0); + file.read(buffer.data(), (std::streamsize) fileSize); + + file.close(); + + return buffer; + } + + static VkShaderModule createShaderModule(VkDevice device, const std::vector &bytecode) { + VkShaderModuleCreateInfo createInfo{ + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .codeSize = (uint32_t) bytecode.size(), + .pCode = (uint32_t *) bytecode.data(), + }; + + VkShaderModule shaderModule; + + if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { + throw std::runtime_error("cannot create shader module"); + } + + return shaderModule; + } + +public: + struct UniformBuffer { + glm::mat4 transforms {}; + glm::vec4 origin {}; + } mVertexUBO; + + VkVertexInputBindingDescription mVertexInputDescription { + .binding = 0, + .stride = sizeof(Vertex), + .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, + }; + + std::vector mVertexAttributes = { + { + .location = 0, + .binding = 0, + .format = VK_FORMAT_R32G32_SFLOAT, + .offset = offsetof(Vertex, pos), + }, + { + .location = 1, + .binding = 0, + .format = VK_FORMAT_R32G32B32_SFLOAT, + .offset = offsetof(Vertex, color), + }, + }; + + std::vector mStageCreateInfos; + + VkShaderModule mVertexModule = VK_NULL_HANDLE; + VkShaderModule mFragmentModule = VK_NULL_HANDLE; +}; + class Application { public: void run() { @@ -99,6 +200,8 @@ private: createSwapChain(width, height); createSwapChainImageViews(); + mShader.create(mDevice); + createRenderPass(); createGraphicsPipeline(); @@ -521,30 +624,6 @@ private: } void createGraphicsPipeline() { - std::vector vertShaderByteCode = readFile("bin/vert.spv"); - mShaderModuleVert = createShaderModule(vertShaderByteCode); - - VkPipelineShaderStageCreateInfo vertShaderStageCreateInfo{ - .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - .stage = VK_SHADER_STAGE_VERTEX_BIT, - .module = mShaderModuleVert, - .pName = "main", - }; - - std::vector fragShaderByteCode = readFile("bin/frag.spv"); - mShaderModuleFrag = createShaderModule(fragShaderByteCode); - - VkPipelineShaderStageCreateInfo fragShaderStageCreateInfo{ - .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - .stage = VK_SHADER_STAGE_FRAGMENT_BIT, - .module = mShaderModuleFrag, - .pName = "main", - }; - - VkPipelineShaderStageCreateInfo shaderStageCreateInfos[] = { - vertShaderStageCreateInfo, - fragShaderStageCreateInfo - }; std::vector dynamicStates = { VK_DYNAMIC_STATE_VIEWPORT, @@ -557,15 +636,12 @@ private: .pDynamicStates = dynamicStates.data(), }; - auto attributes = getShaderAttributesDescriptors(); - auto vertexInput = getShaderVertexInputDescription(); - VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo{ .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, .vertexBindingDescriptionCount = 1, - .pVertexBindingDescriptions = &vertexInput, - .vertexAttributeDescriptionCount = (uint32_t) attributes.size(), - .pVertexAttributeDescriptions = attributes.data(), + .pVertexBindingDescriptions = &mShader.mVertexInputDescription, + .vertexAttributeDescriptionCount = (uint32_t) mShader.mVertexAttributes.size(), + .pVertexAttributeDescriptions = mShader.mVertexAttributes.data(), }; VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo{ @@ -643,7 +719,7 @@ private: VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfo{ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .stageCount = 2, - .pStages = shaderStageCreateInfos, + .pStages = mShader.mStageCreateInfos.data(), .pVertexInputState = &vertexInputStateCreateInfo, .pInputAssemblyState = &inputAssemblyStateCreateInfo, .pViewportState = &viewportState, @@ -710,46 +786,11 @@ private: } void destroyGraphicsPipeline() { - vkDestroyShaderModule(mDevice, mShaderModuleVert, nullptr); - vkDestroyShaderModule(mDevice, mShaderModuleFrag, nullptr); + mShader.destroy(mDevice); vkDestroyPipelineLayout(mDevice, mGraphicsPipelineLayout, nullptr); vkDestroyPipeline(mDevice, mGraphicsPipeline, nullptr); } - VkShaderModule createShaderModule(const std::vector &bytecode) { - VkShaderModuleCreateInfo createInfo{ - .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, - .codeSize = (uint32_t) bytecode.size(), - .pCode = (uint32_t *) bytecode.data(), - }; - - VkShaderModule shaderModule; - - if (vkCreateShaderModule(mDevice, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { - throw std::runtime_error("cannot create shader module"); - } - - return shaderModule; - } - - static std::vector readFile(const std::string &fileName) { - std::ifstream file(fileName, std::ios::ate | std::ios::binary); - - if (!file.is_open()) { - throw std::runtime_error("cannot open file"); - } - - size_t fileSize = (size_t) file.tellg(); - std::vector buffer(fileSize); - - file.seekg(0); - file.read(buffer.data(), (std::streamsize) fileSize); - - file.close(); - - return buffer; - } - void createCommandPool() { VkCommandPoolCreateInfo createInfo{ .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, @@ -1044,34 +1085,6 @@ private: */ } - static VkVertexInputBindingDescription getShaderVertexInputDescription() { - return { - .binding = 0, - .stride = sizeof(Vertex), - .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, - }; - } - - static std::vector getShaderAttributesDescriptors() { - std::vector out(2); - - out[0] = { - .location = 0, - .binding = 0, - .format = VK_FORMAT_R32G32_SFLOAT, - .offset = offsetof(Vertex, pos), - }; - - out[1] = { - .location = 1, - .binding = 0, - .format = VK_FORMAT_R32G32B32_SFLOAT, - .offset = offsetof(Vertex, color), - }; - - return out; - } - void destroySynchronizationObjects() { vkDestroySemaphore(mDevice, mSemaphoreImageAcquired, nullptr); vkDestroySemaphore(mDevice, mSemaphoreFramebufferDrawn, nullptr); @@ -1127,9 +1140,8 @@ private: std::vector mSwapChainImageViews; std::vector mSwapChainFrameBuffers; + CustomShader mShader; VkPipeline mGraphicsPipeline = VK_NULL_HANDLE; - VkShaderModule mShaderModuleVert = VK_NULL_HANDLE; - VkShaderModule mShaderModuleFrag = VK_NULL_HANDLE; VkRenderPass mGraphicsRenderPass = VK_NULL_HANDLE; VkPipelineLayout mGraphicsPipelineLayout{}; // no uniforms used in the shader