From 158052c52c1a0f2ecf9a053f759b7a787641f74f Mon Sep 17 00:00:00 2001 From: niki Date: Tue, 22 Mar 2022 14:31:50 +0100 Subject: [PATCH] implement basic per frame uniform variables --- src/modules/graphics/Shader.cpp | 10 +- src/modules/graphics/vertex.h | 1 + src/modules/graphics/vulkan/Graphics.cpp | 102 ++++++++++++++++++- src/modules/graphics/vulkan/Graphics.h | 12 ++- src/modules/graphics/vulkan/Shader.h | 7 ++ src/modules/graphics/vulkan/StreamBuffer.cpp | 6 ++ src/modules/graphics/vulkan/StreamBuffer.h | 1 + 7 files changed, 133 insertions(+), 6 deletions(-) diff --git a/src/modules/graphics/Shader.cpp b/src/modules/graphics/Shader.cpp index d5b4cfaad..148ea4896 100644 --- a/src/modules/graphics/Shader.cpp +++ b/src/modules/graphics/Shader.cpp @@ -439,13 +439,15 @@ layout(location = 0) in vec2 inPosition; layout(location = 0) out vec4 fragColor; -float windowWidth = 800; -float windowHeight = 600; +layout(binding = 0) uniform LoveUniforms { + float windowWidth; + float windowHeight; +} loveUniforms; void main() { gl_Position = vec4( - 2 * inPosition.x / windowWidth - 1, - 2 * inPosition.y / windowHeight - 1, + 2 * inPosition.x / loveUniforms.windowWidth - 1, + 2 * inPosition.y / loveUniforms.windowHeight - 1, 0.0, 1.0); fragColor = vec4(1, 1, 1, 1); } diff --git a/src/modules/graphics/vertex.h b/src/modules/graphics/vertex.h index 73ed163fd..4994b603c 100644 --- a/src/modules/graphics/vertex.h +++ b/src/modules/graphics/vertex.h @@ -59,6 +59,7 @@ enum BufferUsage BUFFERUSAGE_VERTEX = 0, BUFFERUSAGE_INDEX, BUFFERUSAGE_TEXEL, + BUFFERUSAGE_UNIFORM, BUFFERUSAGE_SHADER_STORAGE, BUFFERUSAGE_MAX_ENUM }; diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 4bbc5a2bd..0adf98080 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -67,10 +67,14 @@ namespace love { createImageViews(); createRenderPass(); createDefaultShaders(); + createDescriptorSetLayout(); createGraphicsPipeline(); createFramebuffers(); createCommandPool(); createCommandBuffers(); + createUniformBuffers(); + createDescriptorPool(); + createDescriptorSets(); createSyncObjects(); startRecordingGraphicsCommands(); } @@ -227,6 +231,9 @@ namespace love { buffers.push_back((VkBuffer)cmd.buffers->info[0].buffer->getHandle()); offsets.push_back((VkDeviceSize) 0); + prepareDraw(currentFrame); + + vkCmdBindDescriptorSets(commandBuffers.at(imageIndex), VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets.at(currentFrame), 0, nullptr); vkCmdBindVertexBuffers(commandBuffers.at(imageIndex), 0, 1, buffers.data(), offsets.data()); vkCmdBindIndexBuffer(commandBuffers.at(imageIndex), (VkBuffer) cmd.indexBuffer->getHandle(), 0, VK_INDEX_TYPE_UINT16); vkCmdDrawIndexed(commandBuffers.at(imageIndex), static_cast(cmd.indexCount), 1, 0, 0, 0); @@ -239,6 +246,18 @@ namespace love { // END IMPLEMENTATION OVERRIDDEN FUNCTIONS + void Graphics::prepareDraw(uint32_t currentImage) { + auto& buffer = uniformBuffers.at(currentImage); + + Shader::UniformBufferObject ubo{}; + ubo.windowWidth = static_cast(swapChainExtent.width); + ubo.windowHeight = static_cast(swapChainExtent.height); + + auto mappedInfo = buffer->map(0); + memcpy(mappedInfo.data, &ubo, sizeof(ubo)); + buffer->unmap(0); + } + void Graphics::createVulkanInstance() { if (enableValidationLayers && !checkValidationSupport()) { throw love::Exception("validation layers requested, but not available"); @@ -699,6 +718,79 @@ namespace love { } } + void Graphics::createDescriptorSetLayout() { + VkDescriptorSetLayoutBinding uboLayoutBinding{}; + uboLayoutBinding.binding = 0; + uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + uboLayoutBinding.descriptorCount = 1; + uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + + VkDescriptorSetLayoutCreateInfo layoutInfo{}; + layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + layoutInfo.bindingCount = 1; + layoutInfo.pBindings = &uboLayoutBinding; + + if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS) { + throw love::Exception("failed to create descriptor set layout"); + } + } + + void Graphics::createUniformBuffers() { + VkDeviceSize bufferSize = sizeof(Shader::UniformBufferObject); + + for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + uniformBuffers.push_back(std::make_unique(device, physicalDevice, BUFFERUSAGE_UNIFORM, bufferSize)); + } + } + + void Graphics::createDescriptorPool() { + VkDescriptorPoolSize poolSize{}; + poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + poolSize.descriptorCount = static_cast(MAX_FRAMES_IN_FLIGHT); + + VkDescriptorPoolCreateInfo poolInfo{}; + poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + poolInfo.poolSizeCount = 1; + poolInfo.pPoolSizes = &poolSize; + poolInfo.maxSets = static_cast(MAX_FRAMES_IN_FLIGHT); + + if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) { + throw love::Exception("failed to create descriptor pool"); + } + } + + void Graphics::createDescriptorSets() { + std::vector layouts(MAX_FRAMES_IN_FLIGHT, descriptorSetLayout); + VkDescriptorSetAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + allocInfo.descriptorPool = descriptorPool; + allocInfo.descriptorSetCount = static_cast(MAX_FRAMES_IN_FLIGHT); + allocInfo.pSetLayouts = layouts.data(); + + descriptorSets.resize(MAX_FRAMES_IN_FLIGHT); + if (vkAllocateDescriptorSets(device, &allocInfo, descriptorSets.data()) != VK_SUCCESS) { + throw love::Exception("failed to allocate descriptor sets"); + } + + for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + VkDescriptorBufferInfo bufferInfo{}; + bufferInfo.buffer = (VkBuffer) uniformBuffers.at(i)->getHandle(); + bufferInfo.offset = 0; + bufferInfo.range = sizeof(Shader::UniformBufferObject); + + VkWriteDescriptorSet descriptorWrite{}; + descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrite.dstSet = descriptorSets[i]; + descriptorWrite.dstBinding = 0; + descriptorWrite.dstArrayElement = 0; + descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptorWrite.descriptorCount = 1; + descriptorWrite.pBufferInfo = &bufferInfo; + + vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr); + } + } + void Graphics::createGraphicsPipeline() { auto shader = reinterpret_cast(love::graphics::vulkan::Shader::standardShaders[Shader::STANDARD_DEFAULT]); auto shaderStages = shader->getShaderStages(); @@ -786,7 +878,8 @@ namespace love { VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipelineLayoutInfo.setLayoutCount = 0; + pipelineLayoutInfo.setLayoutCount = 1; + pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout; pipelineLayoutInfo.pushConstantRangeCount = 0; if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) { @@ -892,6 +985,9 @@ namespace love { cleanupSwapChain(); + vkDestroyDescriptorPool(device, descriptorPool, nullptr); + + vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); vkDestroyCommandPool(device, commandPool, nullptr); vkDestroyDevice(device, nullptr); vkDestroySurfaceKHR(instance, surface, nullptr); @@ -915,6 +1011,7 @@ namespace love { vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr); vkDestroyFence(device, inFlightFences[i], nullptr); } + uniformBuffers.clear(); } void Graphics::recreateSwapChain() { @@ -927,6 +1024,9 @@ namespace love { createRenderPass(); createGraphicsPipeline(); createFramebuffers(); + createUniformBuffers(); + createDescriptorPool(); + createDescriptorSets(); createCommandBuffers(); createSyncObjects(); startRecordingGraphicsCommands(); diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index e46d44a96..0e079e992 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -11,6 +11,7 @@ #include #include +#include namespace love { @@ -117,6 +118,10 @@ namespace love { void createImageViews(); void createRenderPass(); void createDefaultShaders(); + void createDescriptorSetLayout(); + void createUniformBuffers(); + void createDescriptorPool(); + void createDescriptorSets(); void createGraphicsPipeline(); void createFramebuffers(); void createCommandPool(); @@ -128,6 +133,8 @@ namespace love { void startRecordingGraphicsCommands(); void endRecordingGraphicsCommands(); + + void prepareDraw(uint32_t currentImage); VkInstance instance; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; @@ -140,6 +147,7 @@ namespace love { VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; std::vector swapChainImageViews; + VkDescriptorSetLayout descriptorSetLayout; VkPipelineLayout pipelineLayout; VkRenderPass renderPass; VkPipeline graphicsPipeline; @@ -147,7 +155,9 @@ namespace love { VkCommandPool commandPool; std::vector commandBuffers; VkClearValue clearColor = { {{0.0f, 0.0f, 0.0f, 1.0f}} }; - + std::vector> uniformBuffers; + VkDescriptorPool descriptorPool; + std::vector descriptorSets; std::vector imageAvailableSemaphores; std::vector renderFinishedSemaphores; std::vector inFlightFences; diff --git a/src/modules/graphics/vulkan/Shader.h b/src/modules/graphics/vulkan/Shader.h index 0370ee63e..01e76616a 100644 --- a/src/modules/graphics/vulkan/Shader.h +++ b/src/modules/graphics/vulkan/Shader.h @@ -40,6 +40,11 @@ namespace love { void setVideoTextures(Texture* ytexture, Texture* cbtexture, Texture* crtexture) override {} + struct UniformBufferObject { + float windowWidth; + float windowHeight; + }; + private: struct Vec4 { float x, y, z, w; @@ -64,6 +69,8 @@ namespace love { { "love_VideoCrChannel", 3 }, { "MainTex", 4 } }; + + }; } } diff --git a/src/modules/graphics/vulkan/StreamBuffer.cpp b/src/modules/graphics/vulkan/StreamBuffer.cpp index 9d1626c19..19acf0e73 100644 --- a/src/modules/graphics/vulkan/StreamBuffer.cpp +++ b/src/modules/graphics/vulkan/StreamBuffer.cpp @@ -22,6 +22,7 @@ namespace love { switch (mode) { case BUFFERUSAGE_VERTEX: return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; case BUFFERUSAGE_INDEX: return VK_BUFFER_USAGE_INDEX_BUFFER_BIT; + case BUFFERUSAGE_UNIFORM: return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; default: throw love::Exception("unsupported BufferUsage mode"); } @@ -55,6 +56,11 @@ namespace love { vkBindBufferMemory(device, buffer, bufferMemory, 0); } + StreamBuffer::~StreamBuffer() { + //vkDestroyBuffer(device, buffer, nullptr); + //vkFreeMemory(device, bufferMemory, nullptr); + } + love::graphics::StreamBuffer::MapInfo StreamBuffer::map(size_t minsize) { vkMapMemory(device, bufferMemory, 0, getSize(), 0, &mappedMemory); return love::graphics::StreamBuffer::MapInfo((uint8*) mappedMemory, getSize()); diff --git a/src/modules/graphics/vulkan/StreamBuffer.h b/src/modules/graphics/vulkan/StreamBuffer.h index 45ff57460..46af2bf8a 100644 --- a/src/modules/graphics/vulkan/StreamBuffer.h +++ b/src/modules/graphics/vulkan/StreamBuffer.h @@ -11,6 +11,7 @@ namespace love { class StreamBuffer : public love::graphics::StreamBuffer { public: StreamBuffer(VkDevice device, VkPhysicalDevice physicalDevice, BufferUsage mode, size_t size); + virtual ~StreamBuffer(); MapInfo map(size_t minsize) override; size_t unmap(size_t usedSize) override;