Browse Source

implement basic per frame uniform variables

niki 3 years ago
parent
commit
158052c52c

+ 6 - 4
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);
 }

+ 1 - 0
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
 };

+ 101 - 1
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<uint32_t>(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<float>(swapChainExtent.width);
+				ubo.windowHeight = static_cast<float>(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<StreamBuffer>(device, physicalDevice, BUFFERUSAGE_UNIFORM, bufferSize));
+				}
+			}
+
+			void Graphics::createDescriptorPool() {
+				VkDescriptorPoolSize poolSize{};
+				poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+				poolSize.descriptorCount = static_cast<uint32_t>(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<uint32_t>(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<VkDescriptorSetLayout> layouts(MAX_FRAMES_IN_FLIGHT, descriptorSetLayout);
+				VkDescriptorSetAllocateInfo allocInfo{};
+				allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+				allocInfo.descriptorPool = descriptorPool;
+				allocInfo.descriptorSetCount = static_cast<uint32_t>(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*>(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();

+ 11 - 1
src/modules/graphics/vulkan/Graphics.h

@@ -11,6 +11,7 @@
 
 #include <optional>
 #include <iostream>
+#include <memory>
 
 
 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<VkImageView> swapChainImageViews;
+				VkDescriptorSetLayout descriptorSetLayout;
 				VkPipelineLayout pipelineLayout;
 				VkRenderPass renderPass;
 				VkPipeline graphicsPipeline;
@@ -147,7 +155,9 @@ namespace love {
 				VkCommandPool commandPool;
 				std::vector<VkCommandBuffer> commandBuffers;
 				VkClearValue clearColor = { {{0.0f, 0.0f, 0.0f, 1.0f}} };
-
+				std::vector<std::unique_ptr<StreamBuffer>> uniformBuffers;
+				VkDescriptorPool descriptorPool;
+				std::vector<VkDescriptorSet> descriptorSets;
 				std::vector<VkSemaphore> imageAvailableSemaphores;
 				std::vector<VkSemaphore> renderFinishedSemaphores;
 				std::vector<VkFence> inFlightFences;

+ 7 - 0
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 }
 				};
+
+
 			};
 		}
 	}

+ 6 - 0
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());

+ 1 - 0
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;