Browse Source

vulkan: add support for uniform texture arrays

niki 2 years ago
parent
commit
ef80e11b4d

+ 0 - 15
src/modules/graphics/vulkan/Graphics.cpp

@@ -55,11 +55,6 @@ const VkDevice Graphics::getDevice() const
 	return device;
 }
 
-const VkPhysicalDevice Graphics::getPhysicalDevice() const
-{
-	return physicalDevice;
-}
-
 const VmaAllocator Graphics::getVmaAllocator() const
 {
 	return vmaAllocator;
@@ -2072,16 +2067,6 @@ std::set<Shader*> &Graphics::getUsedShadersInFrame()
 	return usedShadersInFrame;
 }
 
-const OptionalDeviceFeatures &Graphics::getOptionalDeviceFeatures() const
-{
-	return optionalDeviceFeatures;
-}
-
-const OptionalDeviceExtensionFunctions &Graphics::getExtensionFunctions() const
-{
-	return ext;
-}
-
 VkSampler Graphics::getCachedSampler(const SamplerState &samplerState)
 {
 	auto it = samplers.find(samplerState);

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

@@ -122,7 +122,7 @@ struct GraphicsPipelineConfiguration
 {
     VkRenderPass renderPass;
 	VertexAttributes vertexAttributes;
-	Shader* shader = nullptr;
+	Shader *shader = nullptr;
 	bool wireFrame;
 	BlendState blendState;
 	ColorChannelMask colorChannelMask;
@@ -168,10 +168,10 @@ struct SamplerStateHasher
 
 struct BatchedDrawBuffers
 {
-	StreamBuffer* vertexBuffer1;
-	StreamBuffer* vertexBuffer2;
-	StreamBuffer* indexBuffer;
-	StreamBuffer* constantColorBuffer;
+	StreamBuffer *vertexBuffer1;
+	StreamBuffer *vertexBuffer2;
+	StreamBuffer *indexBuffer;
+	StreamBuffer *constantColorBuffer;
 
 	~BatchedDrawBuffers()
 	{
@@ -231,7 +231,6 @@ public:
 
 	const char *getName() const override;
 	const VkDevice getDevice() const;
-	const VkPhysicalDevice getPhysicalDevice() const;
 	const VmaAllocator getVmaAllocator() const;
 
 	// implementation for virtual functions
@@ -282,14 +281,11 @@ public:
 
 	const VkDeviceSize getMinUniformBufferOffsetAlignment() const;
 	graphics::Texture *getDefaultTexture() const;
-	VkSampler getCachedSampler(const SamplerState&);
+	VkSampler getCachedSampler(const SamplerState &);
 
-	void setComputeShader(Shader*);
+	void setComputeShader(Shader *);
 	std::set<Shader*> &getUsedShadersInFrame();
 
-	const OptionalDeviceFeatures &getOptionalDeviceFeatures() const;
-	const OptionalDeviceExtensionFunctions &getExtensionFunctions() const;
-
 	graphics::Shader::BuiltinUniformData getCurrentBuiltinUniformData();
 
 protected:

+ 81 - 71
src/modules/graphics/vulkan/Shader.cpp

@@ -159,7 +159,6 @@ Shader::Shader(StrongRef<love::graphics::ShaderStage> stages[])
 {
 	auto gfx = Module::getInstance<Graphics>(Module::ModuleType::M_GRAPHICS);
 	vgfx = dynamic_cast<Graphics*>(gfx);
-	auto &optionalDeviceFeaures = vgfx->getOptionalDeviceFeatures();
 
 	loadVolatile();
 }
@@ -175,6 +174,7 @@ bool Shader::loadVolatile()
 	calculateUniformBufferSizeAligned();
 	createDescriptorSetLayout();
 	createPipelineLayout();
+	createDescriptorPoolSizes();
 	createStreamBuffers();
 	descriptorSetsVector.resize(vgfx->getNumImagesInFlight());
 	currentFrame = 0;
@@ -230,7 +230,7 @@ VkPipeline Shader::getComputePipeline() const
 	return computePipeline;
 }
 
-static VkDescriptorImageInfo* createDescriptorImageInfo(graphics::Texture* texture, bool sampler)
+static VkDescriptorImageInfo *createDescriptorImageInfo(graphics::Texture *texture, bool sampler)
 {
 	auto vkTexture = (Texture*)texture;
 
@@ -270,10 +270,6 @@ void Shader::newFrame(uint32_t frameIndex)
 
 	currentDescriptorSet = descriptorSetsVector.at(currentFrame).at(currentUsedDescriptorSetsCount);
 
-	std::vector<VkWriteDescriptorSet> descriptorWrite{};
-
-	std::vector<VkDescriptorImageInfo*> imageInfos;
-
 	// update everything other than uniform buffers
 	for (const auto &[key, val] : uniformInfos) {
 		// fixme: other types.
@@ -284,14 +280,25 @@ void Shader::newFrame(uint32_t frameIndex)
 			write.dstBinding = val.location;
 			write.dstArrayElement = 0;
 			write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
-			write.descriptorCount = 1;
+			write.descriptorCount = val.count;
 
-			VkDescriptorImageInfo* imageInfo = createDescriptorImageInfo(val.textures[0], true);	// fixme: arrays
-			imageInfos.push_back(imageInfo);
+			std::vector<VkDescriptorImageInfo> imageInfos;
+
+			for (int i = 0; i < val.count; i++)
+			{
+				auto vkTexture = dynamic_cast<Texture*>(val.textures[i]);
+
+				VkDescriptorImageInfo imageInfo{};
+				imageInfo.imageLayout = vkTexture->getImageLayout();
+				imageInfo.imageView = (VkImageView)vkTexture->getRenderTargetHandle();
+				imageInfo.sampler = (VkSampler)vkTexture->getSamplerHandle();
+
+				imageInfos.push_back(imageInfo);
+			}
 
-			write.pImageInfo = imageInfo;
+			write.pImageInfo = imageInfos.data();
 
-			descriptorWrite.push_back(write);
+			vkUpdateDescriptorSets(device, 1, &write, 0, nullptr);
 		}
 		if (val.baseType == UNIFORM_STORAGETEXTURE) {
 			VkWriteDescriptorSet write{};
@@ -300,20 +307,26 @@ void Shader::newFrame(uint32_t frameIndex)
 			write.dstBinding = val.location;
 			write.dstArrayElement = 0;
 			write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
-			write.descriptorCount = 1;
+			write.descriptorCount = val.count;
 
-			VkDescriptorImageInfo* imageInfo = createDescriptorImageInfo(val.textures[0], false);	// fixme: arrays
-			imageInfos.push_back(imageInfo);
+			std::vector<VkDescriptorImageInfo> imageInfos;
 
-			write.pImageInfo = imageInfo;
-			descriptorWrite.push_back(write);
-		}
-	}
+			for (int i = 0; i < val.count; i++)
+			{
+				auto vkTexture = dynamic_cast<Texture*>(val.textures[i]);
+
+				VkDescriptorImageInfo imageInfo{};
+				imageInfo.imageLayout = vkTexture->getImageLayout();
+				imageInfo.imageView = (VkImageView)vkTexture->getRenderTargetHandle();
+
+				imageInfos.push_back(imageInfo);
+			}
 
-	vkUpdateDescriptorSets(device, static_cast<uint32_t>(descriptorWrite.size()), descriptorWrite.data(), 0, nullptr);
+			write.pImageInfo = imageInfos.data();
 
-	for (const auto imageInfo : imageInfos)
-		delete imageInfo;
+			vkUpdateDescriptorSets(device, 1, &write, 0, nullptr);
+		}
+	}
 }
 
 void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint bindPoint)
@@ -334,7 +347,6 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBind
 			memcpy(dst, &builtinData, sizeof(builtinData));
 		}
 
-		// additional data is always added onto the last stream buffer in the current frame
 		auto currentStreamBuffer = streamBuffers.at(currentFrame).back();
 
 		auto mapInfo = currentStreamBuffer->map(uniformBufferSizeAligned);
@@ -928,6 +940,30 @@ void Shader::createPipelineLayout()
 	}
 }
 
+void Shader::createDescriptorPoolSizes()
+{
+	if (!localUniformData.empty())
+	{
+		VkDescriptorPoolSize size{};
+		size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+		size.descriptorCount = 1;
+
+		descriptorPoolSizes.push_back(size);
+	}
+
+	for (const auto &[key, val] : uniformInfos)
+	{
+		VkDescriptorPoolSize size{};
+		auto type = Vulkan::getDescriptorType(val.baseType);
+		if (type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) {
+			continue;
+		}
+		size.type = type;
+		size.descriptorCount = 1;
+		descriptorPoolSizes.push_back(size);
+	}
+}
+
 void Shader::createStreamBuffers()
 {
 	const auto numImagesInFlight = vgfx->getNumImagesInFlight();
@@ -938,29 +974,25 @@ void Shader::createStreamBuffers()
 
 void Shader::setVideoTextures(graphics::Texture *ytexture, graphics::Texture *cbtexture, graphics::Texture *crtexture)
 {
-	// if the shader doesn't actually use these textures they might get optimized out
-	// in that case this function becomes a noop.
-	if (builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_Y] != nullptr)
-	{
-		auto oldTexture = builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_Y]->textures[0];
-		ytexture->retain();
-		oldTexture->release();
-		builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_Y]->textures[0] = ytexture;
-	}
-	if (builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CB] != nullptr)
-	{
-		auto oldTexture = builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CB]->textures[0];
-		cbtexture->retain();
-		oldTexture->release();
-		builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CB]->textures[0] = cbtexture;
-	}
-	if (builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CR] != nullptr)
-	{
-		auto oldTexture = builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CR]->textures[0];
-		crtexture->retain();
-		oldTexture->release();
-		builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CR]->textures[0] = crtexture;
-	}
+	std::array<graphics::Texture*, 3> textures = {
+		ytexture, cbtexture, crtexture
+	};
+
+	std::array<BuiltinUniform, 3> builtIns = {
+		BUILTIN_TEXTURE_VIDEO_Y,
+		BUILTIN_TEXTURE_VIDEO_CB,
+		BUILTIN_TEXTURE_VIDEO_CR,
+	};
+
+	static_assert(textures.size() == builtIns.size());
+
+	for (size_t i = 0; i < textures.size(); i++)
+		if (builtinUniformInfo[builtIns[i]] != nullptr)
+		{
+			textures[i]->retain();
+			builtinUniformInfo[builtIns[i]]->textures[0]->release();
+			builtinUniformInfo[builtIns[i]]->textures[0] = textures[i];
+		}
 }
 
 bool Shader::hasUniform(const std::string &name) const
@@ -972,9 +1004,8 @@ void Shader::setMainTex(graphics::Texture *texture)
 {
 	if (builtinUniformInfo[BUILTIN_TEXTURE_MAIN] != nullptr)
 	{
-		auto oldTexture = builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0];
 		texture->retain();
-		oldTexture->release();
+		builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0]->release();
 		builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0] = texture;
 	}
 }
@@ -983,32 +1014,11 @@ VkDescriptorSet Shader::allocateDescriptorSet()
 {
 	if (freeDescriptorSets.empty())
 	{
-		// fixme: we can optimize this, since sizes should never change for a given shader.
-		std::vector<VkDescriptorPoolSize> sizes;
-
-		VkDescriptorPoolSize size{};
-		size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
-		size.descriptorCount = 1;
-
-		sizes.push_back(size);
-
-		for (const auto &[key, val] : uniformInfos)
-		{
-			VkDescriptorPoolSize size{};
-			auto type = Vulkan::getDescriptorType(val.baseType);
-			if (type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) {
-				continue;
-			} 
-			size.type = type;
-			size.descriptorCount = 1;
-			sizes.push_back(size);
-		}
-
 		VkDescriptorPoolCreateInfo createInfo{};
 		createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
 		createInfo.maxSets = DESCRIPTOR_POOL_SIZE;
-		createInfo.poolSizeCount = static_cast<uint32_t>(sizes.size());
-		createInfo.pPoolSizes = sizes.data();
+		createInfo.poolSizeCount = static_cast<uint32_t>(descriptorPoolSizes.size());
+		createInfo.pPoolSizes = descriptorPoolSizes.data();
 
 		VkDescriptorPool pool;
 		if (vkCreateDescriptorPool(device, &createInfo, nullptr, &pool) != VK_SUCCESS)
@@ -1019,7 +1029,7 @@ VkDescriptorSet Shader::allocateDescriptorSet()
 
 		VkDescriptorSetAllocateInfo allocInfo{};
 		allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
-		allocInfo.descriptorPool = descriptorPools.back();
+		allocInfo.descriptorPool = pool;
 		allocInfo.descriptorSetCount = DESCRIPTOR_POOL_SIZE;
 		allocInfo.pSetLayouts = layouts.data();
 

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

@@ -74,6 +74,7 @@ private:
 	void compileShaders();
 	void createDescriptorSetLayout();
 	void createPipelineLayout();
+	void createDescriptorPoolSizes();
 	void createStreamBuffers();
 	void buildLocalUniforms(
 		spirv_cross::Compiler &comp, 
@@ -89,6 +90,7 @@ private:
 
 	VkDescriptorSetLayout descriptorSetLayout;
 	VkPipelineLayout pipelineLayout;
+	std::vector<VkDescriptorPoolSize> descriptorPoolSizes;
 
 	// we don't know how much memory we need per frame for the uniform buffer descriptors
 	// we keep a vector of stream buffers per frame in flight