Browse Source

use different uniform buffers for each draw call

niki 3 years ago
parent
commit
0cea07806f

+ 10 - 0
src/common/Matrix.h

@@ -83,6 +83,16 @@ public:
 	 **/
 	void operator *= (const Matrix4 &m);
 
+	static friend bool operator==(const Matrix4& first, const Matrix4& other)
+	{
+		for (int i = 0; i < 16; i++) {
+			if (first.e[i] != other.e[i]) {
+				return false;
+			}
+		}
+		return true;
+	}
+
 	/**
 	 * Gets a pointer to the 16 array elements.
 	 * @return The array elements.

+ 8 - 0
src/modules/graphics/Shader.h

@@ -179,6 +179,14 @@ public:
  		Vector4 normalMatrix[3]; // 3x3 matrix padded to an array of 3 vector4s.
  		Vector4 screenSizeParams;
  		Colorf constantColor;
+
+		bool operator==(const BuiltinUniformData& other) {
+			auto first = *this;
+			return first.transformMatrix == other.transformMatrix && first.projectionMatrix == other.projectionMatrix
+				&& first.normalMatrix[0] == other.normalMatrix[0] && first.normalMatrix[1] == other.normalMatrix[1]
+				&& first.normalMatrix[2] == other.normalMatrix[2] && first.screenSizeParams == other.screenSizeParams
+				&& first.constantColor == other.constantColor;
+		}
  	};
 
 	// Pointer to currently active Shader.

+ 2 - 1
src/modules/graphics/vulkan/Buffer.cpp

@@ -32,7 +32,6 @@ namespace love {
 				bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
 				bufferInfo.size = size;
 				bufferInfo.usage = getVulkanUsageFlags(settings.usageFlags);
-				bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
 
 				VmaAllocationCreateInfo allocCreateInfo = {};
 				allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO;
@@ -57,6 +56,8 @@ namespace love {
 			}
 
 			void Buffer::unmap(size_t usedoffset, size_t usedsize) {
+				(void)usedoffset;
+				(void)usedsize;
 			}
 
 			void Buffer::copyTo(love::graphics::Buffer* dest, size_t sourceoffset, size_t destoffset, size_t size) {

+ 65 - 25
src/modules/graphics/vulkan/Graphics.cpp

@@ -121,8 +121,6 @@ namespace love {
 
 				endRecordingGraphicsCommands();
 
-				prepareDraw(currentFrame);
-
 				if (imagesInFlight[imageIndex] != VK_NULL_HANDLE) {
 					vkWaitForFences(device, 1, &imagesInFlight.at(imageIndex), VK_TRUE, UINT64_MAX);
 				}
@@ -209,7 +207,6 @@ namespace love {
 				createFramebuffers();
 				createCommandPool();
 				createCommandBuffers();
-				createUniformBuffers();
 				createDefaultTexture();
 				createQuadIndexBuffer();
 				createDescriptorPool();
@@ -333,12 +330,42 @@ namespace love {
 
 				ensureGraphicsPipelineConfiguration(configuration);
 
-				vkCmdBindDescriptorSets(commandBuffers.at(imageIndex), VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, getDescriptorSet(currentFrame), 0, nullptr);
+				auto descriptorSets = getDescriptorSet(currentFrame);
+				auto descriptorSet = *descriptorSets;
+				vkCmdBindDescriptorSets(commandBuffers.at(imageIndex), VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, descriptorSets, 0, nullptr);
 				vkCmdBindVertexBuffers(commandBuffers.at(imageIndex), 0, buffers.size(), buffers.data(), offsets.data());
 				vkCmdBindIndexBuffer(commandBuffers.at(imageIndex), (VkBuffer)cmd.indexBuffer->getHandle(), 0, getVulkanIndexBufferType(cmd.indexType));
 				vkCmdDrawIndexed(commandBuffers.at(imageIndex), static_cast<uint32_t>(cmd.indexCount), 1, 0, 0, 0);
 			}
 
+			PixelFormat Graphics::getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const { 
+				std::cout << "getSizedFormat ";
+				
+				switch (format) {
+				PIXELFORMAT_NORMAL:
+					if (isGammaCorrect()) {
+						return PIXELFORMAT_RGBA8_UNORM_sRGB;
+					}
+					else {
+						return PIXELFORMAT_RGBA8_UNORM;
+					}
+				case PIXELFORMAT_HDR:
+					return PIXELFORMAT_RGBA16_FLOAT;
+				default:
+					return format;
+				}
+			}
+
+			bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB) { 
+				std::cout << "isPixelFormatSupported ";
+				switch (format) {
+				case PIXELFORMAT_LA8_UNORM:
+					return false;
+				default:
+					return true;
+				}
+			}
+
 			void Graphics::drawQuads(int start, int count, const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture) {
 				std::cout << "drawQuads ";
 
@@ -416,12 +443,29 @@ namespace love {
 			}
 
 			VkDescriptorSet* Graphics::getDescriptorSet(int currentFrame) {
-				auto it = textureToDescriptorSetsMap.find(currentTexture);
-				if (it == textureToDescriptorSetsMap.end()) {
-					textureToDescriptorSetsMap[currentTexture] = createDescriptorSets(currentTexture);
+				DecriptorSetConfiguration config;
+				config.texture = currentTexture;
+				config.buffer = getUniformBuffer();
+				for (auto i = 0; i < descriptorSetsMap.size(); i++) {
+					if (descriptorSetsMap[i].first == config) {
+						return &descriptorSetsMap[i].second[currentFrame];
+					}
 				}
+				auto descriptorSets = createDescriptorSets(config);
+				descriptorSetsMap.push_back(std::make_pair(config, descriptorSets));
+				return &descriptorSetsMap.back().second[currentFrame];
+			}
 
-				return &textureToDescriptorSetsMap.at(currentTexture)[currentFrame];
+			graphics::StreamBuffer* Graphics::getUniformBuffer() {
+				auto data = getCurrentBuiltinUniformData();
+				for (auto it : uniformBufferMap) {
+					if (it.first == data) {
+						return it.second;
+					}
+				}
+				auto buffer = createUniformBufferFromData(data);
+				uniformBufferMap.push_back(std::make_pair(data, buffer));
+				return buffer;
 			}
 
 			VkCommandBuffer Graphics::beginSingleTimeCommands() {
@@ -456,9 +500,7 @@ namespace love {
 				vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);
 			}
 
-			void Graphics::prepareDraw(uint32_t currentImage) {
-				auto& buffer = uniformBuffers.at(currentImage);
-
+			graphics::Shader::BuiltinUniformData Graphics::getCurrentBuiltinUniformData() {
 				love::graphics::Shader::BuiltinUniformData data;
 
 				data.transformMatrix = getTransform();
@@ -493,9 +535,16 @@ namespace love {
 				data.constantColor = getColor();
 				gammaCorrectColor(data.constantColor);
 
+				return data;
+			}
+
+			graphics::StreamBuffer* Graphics::createUniformBufferFromData(graphics::Shader::BuiltinUniformData data) {
+				auto buffer = newStreamBuffer(BUFFERUSAGE_UNIFORM, sizeof(data));
 				auto mappedInfo = buffer->map(0);
 				memcpy(mappedInfo.data, &data, sizeof(data));
 				buffer->unmap(0);
+
+				return buffer;
 			}
 
 			void Graphics::createVulkanInstance() {
@@ -997,14 +1046,6 @@ namespace love {
 				}
 			}
 
-			void Graphics::createUniformBuffers() {
-				VkDeviceSize bufferSize = sizeof(graphics::Shader::BuiltinUniformData);
-				
-				for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
-					uniformBuffers.push_back(std::make_unique<StreamBuffer>(vmaAllocator, BUFFERUSAGE_UNIFORM, bufferSize));
-				}
-			}
-
 			void Graphics::createDescriptorPool() {
 				std::array<VkDescriptorPoolSize, 2> poolSizes{};
 				poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
@@ -1026,7 +1067,7 @@ namespace love {
 				}
 			}
 
-			std::vector<VkDescriptorSet> Graphics::createDescriptorSets(graphics::Texture* texture) {
+			std::vector<VkDescriptorSet> Graphics::createDescriptorSets(DecriptorSetConfiguration config) {
 				std::vector<VkDescriptorSetLayout> layouts(MAX_FRAMES_IN_FLIGHT, descriptorSetLayout);
 				VkDescriptorSetAllocateInfo allocInfo{};
 				allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
@@ -1055,13 +1096,13 @@ namespace love {
 
 				for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
 					VkDescriptorBufferInfo bufferInfo{};
-					bufferInfo.buffer = (VkBuffer)uniformBuffers.at(i)->getHandle();
+					bufferInfo.buffer = (VkBuffer)config.buffer->getHandle();
 					bufferInfo.offset = 0;
 					bufferInfo.range = sizeof(graphics::Shader::BuiltinUniformData);
 
 					VkDescriptorImageInfo imageInfo{};
 					imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
-					Texture* vkTexture = (Texture*)texture;
+					Texture* vkTexture = (Texture*)config.texture;
 					imageInfo.imageView = vkTexture->getImageView();
 					imageInfo.sampler = vkTexture->getSampler();
 
@@ -1448,8 +1489,8 @@ namespace love {
 					vkDestroyImageView(device, swapChainImageViews[i], nullptr);
 				}
 				vkDestroySwapchainKHR(device, swapChain, nullptr);
-				uniformBuffers.clear();
-				textureToDescriptorSetsMap.clear();
+				uniformBufferMap.clear();
+				descriptorSetsMap.clear();
 			}
 
 			void Graphics::recreateSwapChain() {
@@ -1461,7 +1502,6 @@ namespace love {
 				createImageViews();
 				createRenderPass();
 				createFramebuffers();
-				createUniformBuffers();
 				createDescriptorPool();
 				createCommandBuffers();
 				startRecordingGraphicsCommands();

+ 18 - 8
src/modules/graphics/vulkan/Graphics.h

@@ -65,8 +65,8 @@ namespace love {
 				void setBlendState(const BlendState& blend) override { std::cout << "setBlendState "; }
 				void setPointSize(float size) override { std::cout << "setPointSize "; }
 				void setWireframe(bool enable) override { std::cout << "setWireframe "; }
-				PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const override { std::cout << "getSizedFormat "; return format; }
-				bool isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB = false) override { std::cout << "isPixelFormatSupported "; return true; }
+				PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const override;
+				bool isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB = false) override;
 				Renderer getRenderer() const override { std::cout << "getRenderer "; return RENDERER_VULKAN; }
 				bool usesGLSLES() const override { std::cout << "usesGLSES "; return false; }
 				RendererInfo getRendererInfo() const override { std::cout << "getRendererInfo "; return {}; }
@@ -87,6 +87,15 @@ namespace love {
 					friend static bool operator==(const GraphicsPipelineConfiguration& first, const GraphicsPipelineConfiguration& other);
 				};
 
+				struct DecriptorSetConfiguration {
+					graphics::Texture* texture;
+					graphics::StreamBuffer* buffer;
+
+					bool operator==(const DecriptorSetConfiguration& conf2) {
+						return this->texture == conf2.texture && this->buffer == conf2.buffer;
+					}
+				};
+
 				void setShader(Shader*);
 
 			protected:
@@ -112,8 +121,10 @@ namespace love {
 				}
 
 				VkDescriptorSet* getDescriptorSet(int currentFrame);
+				graphics::StreamBuffer* getUniformBuffer();
 
-				std::unordered_map<graphics::Texture*, std::vector<VkDescriptorSet>> textureToDescriptorSetsMap;
+				std::vector<std::pair<graphics::Shader::BuiltinUniformData, graphics::StreamBuffer*>> uniformBufferMap;
+				std::vector<std::pair<DecriptorSetConfiguration, std::vector<VkDescriptorSet>>> descriptorSetsMap;
 
 				struct BatchedDrawBuffers {
 					StreamBuffer* vertexBuffer1;
@@ -129,7 +140,7 @@ namespace love {
 					}
 				};
 
-				// we need an arrow of draw buffers, since the frames are being rendered asynchronously
+				// we need an array of draw buffers, since the frames are being rendered asynchronously
 				// and we can't (or shouldn't) update the contents of the buffers while they're still in flight / being rendered.
 				std::vector<BatchedDrawBuffers> batchedDrawBuffers;
 				void updatedBatchedDrawBuffers();
@@ -173,9 +184,8 @@ namespace love {
 				void createRenderPass();
 				void createDefaultShaders();
 				void createDescriptorSetLayout();
-				void createUniformBuffers();
 				void createDescriptorPool();
-				std::vector<VkDescriptorSet> createDescriptorSets(graphics::Texture* texture);
+				std::vector<VkDescriptorSet> createDescriptorSets(DecriptorSetConfiguration);
 				VkPipeline createGraphicsPipeline(GraphicsPipelineConfiguration);
 				void createFramebuffers();
 				void createCommandPool();
@@ -189,7 +199,8 @@ namespace love {
 				void startRecordingGraphicsCommands();
 				void endRecordingGraphicsCommands();
 				void ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration);
-				void prepareDraw(uint32_t currentImage);
+				graphics::StreamBuffer* createUniformBufferFromData(graphics::Shader::BuiltinUniformData);
+				graphics::Shader::BuiltinUniformData getCurrentBuiltinUniformData();
 				
 				VkInstance instance;
 				VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
@@ -211,7 +222,6 @@ 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<VkSemaphore> imageAvailableSemaphores;
 				std::vector<VkSemaphore> renderFinishedSemaphores;

+ 0 - 1
src/modules/graphics/vulkan/StreamBuffer.h

@@ -28,7 +28,6 @@ namespace love {
 				VmaAllocator allocator;
 				VmaAllocation allocation;
 				VmaAllocationInfo allocInfo;
-				VkDevice device;
 				VkBuffer buffer;
 				size_t usedGPUMemory;
 

+ 2 - 0
src/modules/graphics/vulkan/Texture.cpp

@@ -171,6 +171,8 @@ namespace love {
 			}
 
 			void Texture::uploadByteData(PixelFormat pixelformat, const void* data, size_t size, int level, int slice, const Rect& r) {
+				format = pixelformat;
+
 				VkBuffer stagingBuffer;
 				VmaAllocation vmaAllocation;
 

+ 1 - 1
src/modules/graphics/vulkan/Texture.h

@@ -23,7 +23,7 @@ namespace love {
 				ptrdiff_t getRenderTargetHandle() const override { std::cout << "Texture::getRenderTargetHandle "; return (ptrdiff_t)0; };
 				ptrdiff_t getSamplerHandle() const override { std::cout << "Texture::getSamplerHandle "; return (ptrdiff_t)0; };
 
-				void uploadByteData(PixelFormat pixelformat, const void* data, size_t size, int level, int slice, const Rect& r)  override;
+				void uploadByteData(PixelFormat pixelformat, const void* data, size_t size, int level, int slice, const Rect& r) override;
 
 				void generateMipmapsInternal()  override { std::cout << "Texture::generateMipmapsInternal "; };
 

+ 12 - 4
src/modules/graphics/vulkan/Vulkan.cpp

@@ -163,12 +163,20 @@ namespace love {
 						textureFormat.internalFormat = VK_FORMAT_R32G32_UINT;
 						break;
 					case PIXELFORMAT_RGBA8_UNORM:
-					case PIXELFORMAT_RGBA8_UNORM_sRGB:	// fixme ?
-						textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_UNORM;
+						textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_SRGB;	// fixme?
+						break;
+					case PIXELFORMAT_RGBA8_UNORM_sRGB:
+						textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_SRGB;
 						break;
 					case PIXELFORMAT_BGRA8_UNORM:
-					case PIXELFORMAT_BGRA8_UNORM_sRGB:	// fixme ?
-						textureFormat.internalFormat = VK_FORMAT_B8G8R8A8_UNORM;
+						textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_UNORM;
+						textureFormat.swizzleR = VK_COMPONENT_SWIZZLE_B;
+						textureFormat.swizzleB = VK_COMPONENT_SWIZZLE_R;
+						break;
+					case PIXELFORMAT_BGRA8_UNORM_sRGB:
+						textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_SRGB;
+						textureFormat.swizzleR = VK_COMPONENT_SWIZZLE_B;
+						textureFormat.swizzleB = VK_COMPONENT_SWIZZLE_R;
 						break;
 					case PIXELFORMAT_RGBA8_INT:
 						textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_SINT;