Browse Source

vulkan: add support for custom depth/stencil tex

niki 2 years ago
parent
commit
1658c89f3d

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

@@ -240,6 +240,11 @@ void Graphics::present(void *screenshotCallbackdata)
 	if (!isActive())
 		return;
 
+	if (isRenderTargetActive())
+		throw love::Exception("present cannot be called while a render target is active.");
+
+	deprecations.draw(this);
+
 	submitGpuCommands(true);
 
 	VkPresentInfoKHR presentInfo{};
@@ -266,6 +271,13 @@ void Graphics::present(void *screenshotCallbackdata)
 	else if (result != VK_SUCCESS)
 		throw love::Exception("failed to present swap chain image");
 
+	drawCalls = 0;
+	renderTargetSwitchCount = 0;
+	drawCallsBatched = 0;
+
+	updatePendingReadbacks();
+	updateTemporaryResources();
+
 	currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
 
 	beginFrame();
@@ -720,7 +732,7 @@ bool Graphics::dispatch(int x, int y, int z)
 
 	vkCmdBindPipeline(commandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_COMPUTE, computeShader->getComputePipeline());
 
-	computeShader->cmdPushDescriptorSets(commandBuffers.at(currentFrame), currentFrame, VK_PIPELINE_BIND_POINT_COMPUTE);
+	computeShader->cmdPushDescriptorSets(commandBuffers.at(currentFrame), static_cast<uint32_t>(currentFrame), VK_PIPELINE_BIND_POINT_COMPUTE);
 
 	vkCmdDispatch(commandBuffers.at(currentFrame), static_cast<uint32_t>(x), static_cast<uint32_t>(y), static_cast<uint32_t>(z));
 
@@ -1475,8 +1487,8 @@ VkPresentModeKHR Graphics::chooseSwapPresentMode(const std::vector<VkPresentMode
 {
 	int vsync = Vulkan::getVsync();
 
-	auto begin = availablePresentModes.begin();
-	auto end = availablePresentModes.end();
+	const auto begin = availablePresentModes.begin();
+	const auto end = availablePresentModes.end();
 
 	switch (vsync) {
 	case -1:

+ 12 - 6
src/modules/graphics/vulkan/Shader.cpp

@@ -217,7 +217,7 @@ void Shader::unloadVolatile()
 	descriptorSetsVector.clear();
 }
 
-const std::vector<VkPipelineShaderStageCreateInfo>& Shader::getShaderStages() const
+const std::vector<VkPipelineShaderStageCreateInfo> &Shader::getShaderStages() const
 {
 	return shaderStages;
 }
@@ -232,7 +232,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;
 
@@ -409,13 +409,13 @@ void Shader::attach()
 		vgfx->setComputeShader(this);
 }
 
-int Shader::getVertexAttributeIndex(const std::string& name)
+int Shader::getVertexAttributeIndex(const std::string &name)
 {
 	auto it = attributes.find(name);
 	return it == attributes.end() ? -1 : it->second;
 }
 
-const Shader::UniformInfo* Shader::getUniformInfo(const std::string& name) const
+const Shader::UniformInfo* Shader::getUniformInfo(const std::string &name) const
 {
 	return &uniformInfos.at(name);
 }
@@ -425,7 +425,13 @@ const Shader::UniformInfo* Shader::getUniformInfo(BuiltinUniform builtin) const
 	return builtinUniformInfo[builtin];
 }
 
-void Shader::sendTextures(const UniformInfo* info, graphics::Texture** textures, int count)
+void Shader::updateUniform(const UniformInfo* info, int count)
+{
+	if (current == this)
+		Graphics::flushBatchedDrawsGlobal();
+}
+
+void Shader::sendTextures(const UniformInfo *info, graphics::Texture **textures, int count)
 {
 	for (unsigned i = 0; i < count; i++)
 	{
@@ -447,7 +453,7 @@ void Shader::calculateUniformBufferSizeAligned()
 	uniformBufferSizeAligned = factor * minAlignment;
 }
 
-void Shader::buildLocalUniforms(spirv_cross::Compiler& comp, const spirv_cross::SPIRType &type, size_t baseoff, const std::string &basename)
+void Shader::buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross::SPIRType &type, size_t baseoff, const std::string &basename)
 {
 	using namespace spirv_cross;
 

+ 17 - 20
src/modules/graphics/vulkan/Shader.h

@@ -1,8 +1,8 @@
 #pragma once
 
 // LÖVE
-#include <graphics/Shader.h>
-#include <graphics/vulkan/ShaderStage.h>
+#include "graphics/Shader.h"
+#include "graphics/vulkan/ShaderStage.h"
 #include "Vulkan.h"
 
 // Libraries
@@ -39,7 +39,7 @@ public:
 
 	VkPipeline getComputePipeline() const;
 
-	const std::vector<VkPipelineShaderStageCreateInfo>& getShaderStages() const;
+	const std::vector<VkPipelineShaderStageCreateInfo> &getShaderStages() const;
 
 	const VkPipelineLayout getGraphicsPipelineLayout() const;
 
@@ -51,26 +51,23 @@ public:
 
 	std::string getWarnings() const override { return ""; }
 
-	int getVertexAttributeIndex(const std::string& name) override;
+	int getVertexAttributeIndex(const std::string &name) override;
 
-	const UniformInfo* getUniformInfo(const std::string& name) const override;
-	const UniformInfo* getUniformInfo(BuiltinUniform builtin) const override;
+	const UniformInfo *getUniformInfo(const std::string &name) const override;
+	const UniformInfo *getUniformInfo(BuiltinUniform builtin) const override;
 
-	// Not needed right now, since the logic that links the values of the uniforms to the shader is done in cmdPushDescriptorSets
-	// which gets called from the vulkan::Graphics class whenever a draw call happens.
-	// I'll have to reevaluate the use of this function in the future though.
-	void updateUniform(const UniformInfo* info, int count) override {}
+	void updateUniform(const UniformInfo *info, int count) override;
 
-	void sendTextures(const UniformInfo* info, graphics::Texture** textures, int count) override;
-	void sendBuffers(const UniformInfo* info, love::graphics::Buffer** buffers, int count) override {}
+	void sendTextures(const UniformInfo *info, graphics::Texture **textures, int count) override;
+	void sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count) override {}
 
-	bool hasUniform(const std::string& name) const override;
+	bool hasUniform(const std::string &name) const override;
 
-	void setVideoTextures(graphics::Texture* ytexture, graphics::Texture* cbtexture, graphics::Texture* crtexture) override;
+	void setVideoTextures(graphics::Texture *ytexture, graphics::Texture *cbtexture, graphics::Texture *crtexture) override;
 
 	// fixme: use normal methods for this in the future.
-	void setUniformData(BuiltinUniformData& data);
-	void setMainTex(graphics::Texture* texture);
+	void setUniformData(BuiltinUniformData &data);
+	void setMainTex(graphics::Texture *texture);
 
 private:
 	void calculateUniformBufferSizeAligned();
@@ -79,10 +76,10 @@ private:
 	void createPipelineLayout();
 	void createStreamBuffers();
 	void buildLocalUniforms(
-		spirv_cross::Compiler& comp, 
-		const spirv_cross::SPIRType& type, 
+		spirv_cross::Compiler &comp, 
+		const spirv_cross::SPIRType &type, 
 		size_t baseoff, 
-		const std::string& basename);
+		const std::string &basename);
 
 	VkDescriptorSet allocateDescriptorSet();
 
@@ -112,7 +109,7 @@ private:
 	bool isCompute = false;
 
 	std::unordered_map<std::string, graphics::Shader::UniformInfo> uniformInfos;
-	UniformInfo* builtinUniformInfo[BUILTIN_MAX_ENUM];
+	UniformInfo *builtinUniformInfo[BUILTIN_MAX_ENUM];
 
 	std::unique_ptr<StreamBuffer> uniformBufferObjectBuffer;
 	std::vector<uint8> localUniformStagingData;

+ 42 - 13
src/modules/graphics/vulkan/Texture.cpp

@@ -79,7 +79,11 @@ bool Texture::loadVolatile()
 
 	auto commandBuffer = vgfx->getCommandBufferForDataTransfer();
 
-	if (computeWrite)
+	if (isPixelFormatDepthStencil(format))
+		imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+	else if (isPixelFormatDepth(format))
+		imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;
+	else if (computeWrite)
 		imageLayout = VK_IMAGE_LAYOUT_GENERAL;
 	else
 		imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
@@ -103,7 +107,7 @@ bool Texture::loadVolatile()
 				sliceCount = slices.getSliceCount();
 			for (int slice = 0; slice < sliceCount; slice++)
 			{
-				auto* id = slices.get(slice, mip);
+				auto *id = slices.get(slice, mip);
 				if (id != nullptr)
 					uploadImageData(id, mip, slice, 0, 0);
 			}
@@ -200,29 +204,54 @@ void Texture::clear()
 {
 	auto commandBuffer = vgfx->getCommandBufferForDataTransfer();
 
-	auto clearColor = getClearValue();
-
 	VkImageSubresourceRange range{};
-	range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+	if (isPixelFormatDepthStencil(format))
+		range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
+	else if (isPixelFormatDepth(format))
+		range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
+	else
+		range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 	range.baseMipLevel = 0;
 	range.levelCount = VK_REMAINING_MIP_LEVELS;
 	range.baseArrayLayer = 0;
 	range.layerCount = VK_REMAINING_ARRAY_LAYERS;
 
-	if (imageLayout != VK_IMAGE_LAYOUT_GENERAL)
+	if (imageLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
 	{
-		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, 
-			VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 
-			0, range.levelCount, 0, range.layerCount);
+		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage,
+			VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+			0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS);
+
+		auto clearColor = getClearValue();
 
 		vkCmdClearColorImage(commandBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor, 1, &range);
 
-		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, 
-			VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 
-			0, range.levelCount, 0, range.layerCount);
+		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage,
+			VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+			0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS);
 	}
-	else
+	else if (imageLayout == VK_IMAGE_LAYOUT_GENERAL)
+	{
+		auto clearColor = getClearValue();
+
 		vkCmdClearColorImage(commandBuffer, textureImage, VK_IMAGE_LAYOUT_GENERAL, &clearColor, 1, &range);
+	}
+	else
+	{
+		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage,
+			imageLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+			0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS);
+
+		VkClearDepthStencilValue depthStencilColor{};
+		depthStencilColor.depth = 0.0f;
+		depthStencilColor.stencil = 0;
+
+		vkCmdClearDepthStencilImage(commandBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &depthStencilColor, 1, &range);
+
+		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage,
+			VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageLayout,
+			0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS);
+	}
 }
 
 VkClearColorValue Texture::getClearValue()

+ 28 - 0
src/modules/graphics/vulkan/Vulkan.cpp

@@ -789,6 +789,33 @@ void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage ima
 		sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
 		destinationStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;
 	}
+	else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && 
+			(newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL || newLayout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL))
+	{
+		barrier.srcAccessMask = 0;
+		barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
+
+		sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+		destinationStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
+	}
+	else if ((oldLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL || oldLayout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL) && 
+			  newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
+	{
+		barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
+		barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+
+		sourceStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
+		destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
+	}
+	else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL &&
+			(newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL || newLayout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL))
+	{
+		barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+		barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
+
+		sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
+		destinationStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
+	}
 	else
 		throw std::invalid_argument("unsupported layout transition!");
 
@@ -801,6 +828,7 @@ void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage ima
 		1, &barrier
 	);
 }
+
 } // vulkan
 } // graphics
 } // love