Browse Source

vulkan: fix uniform buffer descriptor

There was a bug where the count of used builtin uniform buffer objects
was not advanced. This caused another problem since vulkan requires
a certain alignment for the buffer. This commit fixes both of those
things.
niki 3 years ago
parent
commit
7a3e9ed71e

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

@@ -26,7 +26,7 @@ namespace love {
 			}
 
 			Buffer::Buffer(love::graphics::Graphics* gfx, const Settings& settings, const std::vector<DataDeclaration>& format, const void* data, size_t size, size_t arraylength)
-				: love::graphics::Buffer(gfx, settings, format, size, arraylength), usageFlags(settings.usageFlags), allocator(allocator), gfx(gfx) {
+				: love::graphics::Buffer(gfx, settings, format, size, arraylength), usageFlags(settings.usageFlags), gfx(gfx) {
 				loadVolatile();
 			}
 

+ 19 - 10
src/modules/graphics/vulkan/Graphics.cpp

@@ -7,6 +7,7 @@
 #include "graphics/Texture.h"
 #include "Vulkan.h"
 #include "common/version.h"
+#include "common/pixelformat.h"
 
 #include <algorithm>
 #include <vector>
@@ -99,8 +100,8 @@ namespace love {
 
 				VkClearRect rect{};
 				rect.layerCount = 1;
-				rect.rect.extent.width = currentViewportWidth;
-				rect.rect.extent.height = currentViewportHeight;
+				rect.rect.extent.width = static_cast<uint32_t>(currentViewportWidth);
+				rect.rect.extent.height = static_cast<uint32_t>(currentViewportHeight);
 
 				vkCmdClearAttachments(commandBuffers[imageIndex], 1, &attachment, 1, &rect);
 			}
@@ -121,8 +122,8 @@ namespace love {
 
 				VkClearRect rect{};
 				rect.layerCount = 1;
-				rect.rect.extent.width = currentViewportWidth;
-				rect.rect.extent.height = currentViewportHeight;
+				rect.rect.extent.width = static_cast<uint32_t>(currentViewportWidth);
+				rect.rect.extent.height = static_cast<uint32_t>(currentViewportHeight);
 
 				vkCmdClearAttachments(commandBuffers[imageIndex], static_cast<uint32_t>(attachments.size()), attachments.data(), 1, &rect);
 			}
@@ -433,7 +434,7 @@ namespace love {
 
 			PixelFormat Graphics::getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const { 
 				switch (format) {
-				PIXELFORMAT_NORMAL:
+				case PIXELFORMAT_NORMAL:
 					if (isGammaCorrect()) {
 						return PIXELFORMAT_RGBA8_UNORM_sRGB;
 					}
@@ -534,6 +535,10 @@ namespace love {
 				return MAX_FRAMES_IN_FLIGHT;
 			}
 
+			const VkDeviceSize Graphics::getMinUniformBufferOffsetAlignment() const {
+				return minUniformBufferOffsetAlignment;
+			}
+
 			const PFN_vkCmdPushDescriptorSetKHR Graphics::getVkCmdPushDescriptorSetKHRFunctionPointer() const {
 				return vkCmdPushDescriptorSet;
 			}
@@ -596,8 +601,8 @@ namespace love {
 				// Same with point size.
 				data.normalMatrix[1].w = getPointSize();
 
-				data.screenSizeParams.x = swapChainExtent.width;
-				data.screenSizeParams.y = swapChainExtent.height;
+				data.screenSizeParams.x = static_cast<float>(swapChainExtent.width);
+				data.screenSizeParams.y = static_cast<float>(swapChainExtent.height);
 
 				data.screenSizeParams.z = 1.0f;
 				data.screenSizeParams.w = 0.0f;
@@ -711,6 +716,10 @@ namespace love {
 				else {
 					throw love::Exception("failed to find a suitable gpu");
 				}
+
+				VkPhysicalDeviceProperties properties;
+				vkGetPhysicalDeviceProperties(physicalDevice, &properties);
+				minUniformBufferOffsetAlignment = properties.limits.minUniformBufferOffsetAlignment;
 			}
 
 			bool Graphics::checkDeviceExtensionSupport(VkPhysicalDevice device) {
@@ -1184,7 +1193,7 @@ namespace love {
 
 				ensureGraphicsPipelineConfiguration(configuration);
 
-				configuration.shader->cmdPushDescriptorSets(commandBuffers.at(imageIndex), currentFrame);
+				configuration.shader->cmdPushDescriptorSets(commandBuffers.at(imageIndex), static_cast<uint32_t>(currentFrame));
 				vkCmdBindVertexBuffers(commandBuffers.at(imageIndex), 0, static_cast<uint32_t>(bufferVector.size()), bufferVector.data(), offsets.data());
 			}
 
@@ -1241,9 +1250,9 @@ namespace love {
 
 				VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
 				vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
-				vertexInputInfo.vertexBindingDescriptionCount = configuration.vertexInputBindingDescriptions.size();
+				vertexInputInfo.vertexBindingDescriptionCount = static_cast<uint32_t>(configuration.vertexInputBindingDescriptions.size());
 				vertexInputInfo.pVertexBindingDescriptions = configuration.vertexInputBindingDescriptions.data();
-				vertexInputInfo.vertexAttributeDescriptionCount = configuration.vertexInputAttributeDescriptions.size();
+				vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(configuration.vertexInputAttributeDescriptions.size());
 				vertexInputInfo.pVertexAttributeDescriptions = configuration.vertexInputAttributeDescriptions.data();
 
 				VkPipelineInputAssemblyStateCreateInfo inputAssembly{};

+ 2 - 0
src/modules/graphics/vulkan/Graphics.h

@@ -118,6 +118,7 @@ namespace love {
 
 				uint32_t getNumImagesInFlight() const;
 				const PFN_vkCmdPushDescriptorSetKHR getVkCmdPushDescriptorSetKHRFunctionPointer() const;
+				const VkDeviceSize getMinUniformBufferOffsetAlignment() const;
 
 			protected:
 				graphics::ShaderStage* newShaderStageInternal(ShaderStageType stage, const std::string& cachekey, const std::string& source, bool gles) override { 
@@ -189,6 +190,7 @@ namespace love {
 				std::vector<VkSemaphore> renderFinishedSemaphores;
 				std::vector<VkFence> inFlightFences;
 				std::vector<VkFence> imagesInFlight;
+				VkDeviceSize minUniformBufferOffsetAlignment;
 				PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSet;
 				size_t currentFrame = 0;
 				uint32_t imageIndex = 0;

+ 24 - 8
src/modules/graphics/vulkan/Shader.cpp

@@ -150,6 +150,7 @@ namespace love {
 			}
 
 			bool Shader::loadVolatile() {
+				calculateUniformBufferSizeAligned();
 				compileShaders();
 				createDescriptorSetLayout();
 				createPipelineLayout();
@@ -211,15 +212,15 @@ namespace love {
 					}
 				}
 
-				auto mapInfo = streamBuffers[currentImage]->map(sizeof(BuiltinUniformData));
-				memcpy(mapInfo.data, &uniformData, sizeof(BuiltinUniformData));
-				streamBuffers[currentImage]->unmap(sizeof(BuiltinUniformData));
-				streamBuffers[currentImage]->markUsed(sizeof(BuiltinUniformData));
+				auto mapInfo = streamBuffers[currentImage]->map(uniformBufferSizeAligned);
+				memcpy(mapInfo.data, &uniformData, uniformBufferSizeAligned);
+				streamBuffers[currentImage]->unmap(uniformBufferSizeAligned);
+				streamBuffers[currentImage]->markUsed(uniformBufferSizeAligned);
 
 				VkDescriptorBufferInfo bufferInfo{};
 				bufferInfo.buffer = (VkBuffer)streamBuffers[currentImage]->getHandle();
-				bufferInfo.offset = count * sizeof(BuiltinUniformData);
-				bufferInfo.range = sizeof(graphics::Shader::BuiltinUniformData);
+				bufferInfo.offset = count * uniformBufferSizeAligned;
+				bufferInfo.range = sizeof(BuiltinUniformData);
 				
 				auto mainTexImageInfo = createDescriptorImageInfo(mainTex);
 				auto ytextureImageInfo = createDescriptorImageInfo(ytexture);
@@ -268,6 +269,8 @@ namespace love {
 				descriptorWrite[4].pImageInfo = &crtextureImageInfo;
 
 				vkCmdPushDescriptorSet(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, static_cast<uint32_t>(descriptorWrite.size()), descriptorWrite.data());
+
+				count++;
 			}
 
 			Shader::~Shader() {
@@ -286,6 +289,19 @@ namespace love {
 				return vertexAttributeIndices.at(name);
 			}
 
+			void Shader::calculateUniformBufferSizeAligned() {
+				gfx = Module::getInstance<Graphics>(Module::ModuleType::M_GRAPHICS);
+				auto vgfx = (Graphics*)gfx;
+				auto minAlignment = vgfx->getMinUniformBufferOffsetAlignment();
+				uniformBufferSizeAligned = 
+					static_cast<VkDeviceSize>(
+						std::ceil(
+							static_cast<float>(sizeof(BuiltinUniformData)) / static_cast<float>(minAlignment)
+						)
+					)
+					* minAlignment;
+			}
+
 			void Shader::compileShaders() {
 				using namespace glslang;
 				using namespace spirv_cross;
@@ -315,7 +331,7 @@ namespace love {
 
 					auto& glsl = stages[i]->getSource();
 					const char* csrc = glsl.c_str();
-					const int sourceLength = glsl.length();
+					const int sourceLength = static_cast<int>(glsl.length());
 					tshader->setStringsWithLengths(&csrc, &sourceLength, 1);
 
 					int defaultVersio = 450;
@@ -451,7 +467,7 @@ namespace love {
 				const auto numImagesInFlight = vgfx->getNumImagesInFlight();
 				streamBuffers.resize(numImagesInFlight);
 				for (uint32_t i = 0; i < numImagesInFlight; i++) {
-					streamBuffers[i] = new StreamBuffer(gfx, BUFFERUSAGE_UNIFORM, STREAMBUFFER_SIZE * sizeof(BuiltinUniformData));
+					streamBuffers[i] = new StreamBuffer(gfx, BUFFERUSAGE_UNIFORM, STREAMBUFFER_SIZE * uniformBufferSizeAligned);
 				}
 			}
 

+ 2 - 0
src/modules/graphics/vulkan/Shader.h

@@ -52,11 +52,13 @@ namespace love {
 				void setMainTex(graphics::Texture* texture);
 
 			private:
+				void calculateUniformBufferSizeAligned();
 				void compileShaders();
 				void createDescriptorSetLayout();
 				void createPipelineLayout();
 				void createStreamBuffers();
 
+				VkDeviceSize uniformBufferSizeAligned;
 				PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSet;
 
 				VkDescriptorSetLayout descriptorSetLayout;

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

@@ -146,7 +146,7 @@ namespace love {
 
 				VkImageSubresourceRange range{};
 				range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
-				range.layerCount = 1;
+				range.layerCount = getMipmapCount();
 				range.levelCount = 1;
 
 				vkCmdClearColorImage(commandBuffer, textureImage, VK_IMAGE_LAYOUT_GENERAL, &clearColor, 1, &range);