Browse Source

vulkan: fix canvas rendering on android

niki 3 years ago
parent
commit
18221beb25

+ 4 - 6
src/modules/graphics/Shader.cpp

@@ -56,10 +56,8 @@ static const char global_syntax[] = R"(
 #endif
 #if __VERSION__ >= 300
 #define LOVE_IO_LOCATION(x) layout (location = x)
-#define LOVE_IO_BINDING(x) layout (binding = x)
 #else
 #define LOVE_IO_LOCATION(x)
-#define LOVE_IO_BINDING(x)
 #endif
 #define number float
 #define Image sampler2D
@@ -311,9 +309,9 @@ static const char pixel_header[] = R"(
 )";
 
 static const char pixel_functions[] = R"(
-LOVE_IO_BINDING(2) uniform sampler2D love_VideoYChannel;
-LOVE_IO_BINDING(3) uniform sampler2D love_VideoCbChannel;
-LOVE_IO_BINDING(4) uniform sampler2D love_VideoCrChannel;
+uniform sampler2D love_VideoYChannel;
+uniform sampler2D love_VideoCbChannel;
+uniform sampler2D love_VideoCrChannel;
 
 vec4 VideoTexel(vec2 texcoords) {
 	vec3 yuv;
@@ -339,7 +337,7 @@ static const char pixel_main[] = R"(
 	#define love_PixelColor gl_FragColor
 #endif
 
-LOVE_IO_BINDING(1) uniform sampler2D MainTex;
+uniform sampler2D MainTex;
 LOVE_IO_LOCATION(0) varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord;
 LOVE_IO_LOCATION(1) varying mediump vec4 VaryingColor;
 

+ 104 - 71
src/modules/graphics/vulkan/Graphics.cpp

@@ -325,7 +325,6 @@ void Graphics::getAPIStats(int& shaderswitches) const {
 
 void Graphics::unSetMode() {
 	created = false;
-	auto fpn = vkDeviceWaitIdle;
 	vkDeviceWaitIdle(device);
 	Volatile::unloadAll();
 	cleanup();
@@ -559,12 +558,11 @@ Matrix4 Graphics::computeDeviceProjection(const Matrix4& projection, bool render
 void Graphics::setRenderTargetsInternal(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) {
 	endRenderPass();
 
-	if (rts.colors.empty()) {
-		startRenderPass(nullptr, swapChainExtent.width, swapChainExtent.height);
+	bool isWindow = rts.getFirstTarget().texture == nullptr;
+	if (isWindow) {
+		startDefaultRenderPass();
 	} else {
-		// fixme: multi canvas render.
-		auto& firstRenderTarget = rts.getFirstTarget();
-		startRenderPass(dynamic_cast<Texture*>(firstRenderTarget.texture), pixelw, pixelh);
+		startRenderPass(rts, pixelw, pixelh, hasSRGBtexture);
 	}
 }
 
@@ -615,7 +613,7 @@ void Graphics::startRecordingGraphicsCommands() {
 
 	Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), swapChainImages[imageIndex], VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
 
-	startRenderPass(nullptr, swapChainExtent.width, swapChainExtent.height);
+	startDefaultRenderPass();
 
 	Vulkan::resetShaderSwitches();
 }
@@ -1166,7 +1164,7 @@ VkPresentModeKHR Graphics::chooseSwapPresentMode(const std::vector<VkPresentMode
 			return VK_PRESENT_MODE_MAILBOX_KHR;
 		}
 		else {
-			auto it = std::find(availablePresentModes.begin(), availablePresentModes.end(), VK_PRESENT_MODE_IMMEDIATE_KHR);
+			it = std::find(availablePresentModes.begin(), availablePresentModes.end(), VK_PRESENT_MODE_IMMEDIATE_KHR);
 			if (it != availablePresentModes.end()) {
 				return VK_PRESENT_MODE_IMMEDIATE_KHR;
 			}
@@ -1244,7 +1242,10 @@ void Graphics::createImageViews() {
 
 void Graphics::createDefaultRenderPass() {
 	RenderPassConfiguration renderPassConfiguration{};
-	renderPassConfiguration.frameBufferFormat = swapChainImageFormat;
+	renderPassConfiguration.colorFormat = swapChainImageFormat;
+	renderPassConfiguration.msaaSamples = msaaSamples;
+	renderPassConfiguration.depthFormat = findDepthFormat();
+	renderPassConfiguration.resolve = true;
 	defaultRenderPass = createRenderPass(renderPassConfiguration);
 }
 
@@ -1256,18 +1257,26 @@ void Graphics::createDefaultFramebuffers() {
 		configuration.renderPass = defaultRenderPass;
 		configuration.width = swapChainExtent.width;
 		configuration.height = swapChainExtent.height;
-		configuration.imageView = view;
+		configuration.imageView = colorImageView;
+		configuration.depthView = depthImageView;
+		configuration.resolveView = view;
 		defaultFramebuffers.push_back(createFramebuffer(configuration));
 	}
 }
 
 VkFramebuffer Graphics::createFramebuffer(FramebufferConfiguration configuration) {
-	std::array<VkImageView, 3> attachments = {
-		colorImageView,
-		depthImageView,
+	std::vector<VkImageView> attachments = {
 		configuration.imageView,
 	};
 
+	if (configuration.depthView) {
+		attachments.push_back(configuration.depthView);
+	}
+
+	if (configuration.resolveView) {
+		attachments.push_back(configuration.resolveView);
+	}
+
 	VkFramebufferCreateInfo createInfo{};
 	createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
 	createInfo.renderPass = configuration.renderPass;
@@ -1310,35 +1319,44 @@ void Graphics::createDefaultShaders() {
 }
 
 VkRenderPass Graphics::createRenderPass(RenderPassConfiguration configuration) {
+	std::vector<VkAttachmentDescription> attachments;
+
     VkAttachmentDescription colorDescription{};
-    colorDescription.format = swapChainImageFormat;
-    colorDescription.samples = msaaSamples;
+    colorDescription.format = configuration.colorFormat;
+    colorDescription.samples = configuration.msaaSamples;
     colorDescription.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
     colorDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
     colorDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
     colorDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
     colorDescription.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
     colorDescription.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
-
-	VkAttachmentDescription depthStencilAttachment{};
-	depthStencilAttachment.format = findDepthFormat();
-	depthStencilAttachment.samples = msaaSamples;
-	depthStencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-	depthStencilAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
-	depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-	depthStencilAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
-	depthStencilAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
-	depthStencilAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
-
-	VkAttachmentDescription colorAttachmentResolve{};
-	colorAttachmentResolve.format = configuration.frameBufferFormat;
-	colorAttachmentResolve.samples = VK_SAMPLE_COUNT_1_BIT;
-	colorAttachmentResolve.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-	colorAttachmentResolve.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
-	colorAttachmentResolve.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-	colorAttachmentResolve.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
-	colorAttachmentResolve.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
-	colorAttachmentResolve.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+	attachments.push_back(colorDescription);
+
+	if (configuration.depthFormat != VK_FORMAT_UNDEFINED) {
+		VkAttachmentDescription depthStencilAttachment{};
+		depthStencilAttachment.format = configuration.depthFormat;
+		depthStencilAttachment.samples = configuration.msaaSamples;
+		depthStencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+		depthStencilAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+		depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+		depthStencilAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+		depthStencilAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+		depthStencilAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+		attachments.push_back(depthStencilAttachment);
+	}
+
+	if (configuration.resolve) {
+		VkAttachmentDescription colorAttachmentResolve{};
+		colorAttachmentResolve.format = configuration.colorFormat;
+		colorAttachmentResolve.samples = VK_SAMPLE_COUNT_1_BIT;
+		colorAttachmentResolve.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+		colorAttachmentResolve.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+		colorAttachmentResolve.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+		colorAttachmentResolve.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+		colorAttachmentResolve.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+		colorAttachmentResolve.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+		attachments.push_back(colorAttachmentResolve);
+	}
 
     VkAttachmentReference colorAttachmentRef{};
     colorAttachmentRef.attachment = 0;
@@ -1356,10 +1374,14 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration configuration) {
     subPass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
     subPass.colorAttachmentCount = 1;
     subPass.pColorAttachments = &colorAttachmentRef;
-	subPass.pDepthStencilAttachment = &depthStencilAttachmentRef;
-	subPass.pResolveAttachments = &colorAttachmentResolveRef;
 
-	std::array<VkAttachmentDescription, 3> attachments = { colorDescription, depthStencilAttachment, colorAttachmentResolve };
+	if (configuration.depthFormat != VK_FORMAT_UNDEFINED) {
+		subPass.pDepthStencilAttachment = &depthStencilAttachmentRef;
+	}
+
+	if (configuration.resolve) {
+		subPass.pResolveAttachments = &colorAttachmentResolveRef;
+	}
 
 	VkSubpassDependency dependency{};
 	dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
@@ -1475,6 +1497,8 @@ void Graphics::prepareDraw(const VertexAttributes& attributes, const BufferBindi
 	configuration.cullmode = cullmode;
 	configuration.viewportWidth = currentViewportWidth;
 	configuration.viewportHeight = currentViewportHeight;
+	configuration.msaaSamples = currentMsaaSamples;
+
 	std::vector<VkBuffer> bufferVector;
 	std::vector<VkDeviceSize> offsets;
 
@@ -1505,54 +1529,63 @@ void Graphics::prepareDraw(const VertexAttributes& attributes, const BufferBindi
 	vkCmdBindVertexBuffers(commandBuffers.at(currentFrame), 0, static_cast<uint32_t>(bufferVector.size()), bufferVector.data(), offsets.data());
 }
 
-void Graphics::startRenderPass(Texture* texture, uint32_t w, uint32_t h) {
-    VkRenderPass renderPass;
-	VkFramebuffer framebuffer;
+void Graphics::startDefaultRenderPass() {
+	VkRenderPassBeginInfo renderPassInfo{};
+	renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+	renderPassInfo.renderPass = defaultRenderPass;
+	renderPassInfo.framebuffer = defaultFramebuffers[imageIndex];
+	renderPassInfo.renderArea.offset = { 0, 0 };
+	renderPassInfo.renderArea.extent = swapChainExtent;
 
-	if (texture == nullptr) {
-		renderTargetTexture = nullptr;
-		renderPass = defaultRenderPass;
-		framebuffer = defaultFramebuffers[imageIndex];
-	} else {
-		RenderPassConfiguration renderPassConfiguration{};
+	vkCmdBeginRenderPass(commandBuffers.at(currentFrame), &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
 
-		renderPassConfiguration.frameBufferFormat = Vulkan::getTextureFormat(texture->getPixelFormat()).internalFormat;
-		renderTargetTexture = texture;
+	currentRenderPass = defaultRenderPass;
+	currentGraphicsPipeline = VK_NULL_HANDLE;
+	renderTargetTexture = VK_NULL_HANDLE;
+	currentViewportWidth = (float)swapChainExtent.width;
+	currentViewportHeight = (float)swapChainExtent.height;
+	currentMsaaSamples = msaaSamples;
+}
 
-		auto it = renderPasses.find(renderPassConfiguration);
-		if (it != renderPasses.end()) {
-			renderPass = it->second;
-		} else {
-			renderPass = createRenderPass(renderPassConfiguration);
-			renderPasses[renderPassConfiguration] = renderPass;
-		}
+void Graphics::startRenderPass(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) {
+	renderTargetTexture = dynamic_cast<Texture*>(rts.colors[0].texture);
 
-		FramebufferConfiguration configuration{};
-		configuration.renderPass = renderPass;
-		configuration.imageView = (VkImageView)texture->getRenderTargetHandle();
-		configuration.width = w;
-		configuration.height = h;
-		framebuffer = getFramebuffer(configuration);
+	RenderPassConfiguration renderPassConfiguration{};
+	renderPassConfiguration.colorFormat = Vulkan::getTextureFormat(renderTargetTexture->getPixelFormat()).internalFormat;
+
+    VkRenderPass renderPass;
+	auto it = renderPasses.find(renderPassConfiguration);
+	if (it != renderPasses.end()) {
+		renderPass = it->second;
+	} else {
+		renderPass = createRenderPass(renderPassConfiguration);
+		renderPasses[renderPassConfiguration] = renderPass;
 	}
 
+	FramebufferConfiguration configuration{};
+	configuration.renderPass = renderPass;
+	configuration.imageView = (VkImageView)renderTargetTexture->getRenderTargetHandle();
+	configuration.width = static_cast<uint32_t>(renderTargetTexture->getWidth());
+	configuration.height = static_cast<uint32_t>(renderTargetTexture->getHeight());
+	VkFramebuffer framebuffer = getFramebuffer(configuration);
+
+	Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), (VkImage)renderTargetTexture->getHandle(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+
     VkRenderPassBeginInfo renderPassInfo{};
     renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
     renderPassInfo.renderPass = renderPass;
 	renderPassInfo.framebuffer = framebuffer;
     renderPassInfo.renderArea.offset = {0, 0};
-    renderPassInfo.renderArea.extent.width = static_cast<uint32_t>(w);
-    renderPassInfo.renderArea.extent.height = static_cast<uint32_t>(h);
-
-    if (renderTargetTexture) {
-		Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), (VkImage)texture->getHandle(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
-	}
+    renderPassInfo.renderArea.extent.width = static_cast<uint32_t>(renderTargetTexture->getWidth());
+    renderPassInfo.renderArea.extent.height = static_cast<uint32_t>(renderTargetTexture->getHeight());
 
     vkCmdBeginRenderPass(commandBuffers.at(currentFrame), &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
 
     currentRenderPass = renderPass;
 	currentGraphicsPipeline = VK_NULL_HANDLE;
-	currentViewportWidth = (float)w;
-	currentViewportHeight = (float)h;
+	currentViewportWidth = (float)renderTargetTexture->getWidth();
+	currentViewportHeight = (float)renderTargetTexture->getHeight();
+	currentMsaaSamples = VK_SAMPLE_COUNT_1_BIT;
 }
 
 void Graphics::endRenderPass() {
@@ -1661,7 +1694,7 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration config
 	VkPipelineMultisampleStateCreateInfo multisampling{};
 	multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
 	multisampling.sampleShadingEnable = VK_FALSE;
-	multisampling.rasterizationSamples = msaaSamples;
+	multisampling.rasterizationSamples = configuration.msaaSamples;
 	multisampling.minSampleShading = 1.0f; // Optional
 	multisampling.pSampleMask = nullptr; // Optional
 	multisampling.alphaToCoverageEnable = VK_FALSE; // Optional

+ 15 - 6
src/modules/graphics/vulkan/Graphics.h

@@ -25,7 +25,10 @@ namespace love {
 namespace graphics {
 namespace vulkan {
 struct RenderPassConfiguration {
-    VkFormat frameBufferFormat;
+    VkFormat colorFormat = VK_FORMAT_UNDEFINED;
+	VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT;
+	VkFormat depthFormat = VK_FORMAT_UNDEFINED;
+	bool resolve = false;
 
     bool operator==(const RenderPassConfiguration& conf) const {
         return memcmp(this, &conf, sizeof(RenderPassConfiguration)) == 0;
@@ -41,6 +44,8 @@ struct RenderPassConfigurationHasher {
 struct FramebufferConfiguration {
 	VkRenderPass renderPass = VK_NULL_HANDLE;
 	VkImageView imageView = VK_NULL_HANDLE;
+	VkImageView depthView = VK_NULL_HANDLE;
+	VkImageView resolveView = VK_NULL_HANDLE;
 	uint32_t width = 0;
 	uint32_t height = 0;
 
@@ -69,6 +74,7 @@ struct GraphicsPipelineConfiguration {
 	float viewportHeight;
 	StencilState stencil;
 	DepthState depthState;
+	VkSampleCountFlagBits msaaSamples;
 
 	GraphicsPipelineConfiguration() {
 		memset(this, 0, sizeof(GraphicsPipelineConfiguration));
@@ -122,14 +128,16 @@ struct SwapChainSupportDetails {
 
 class Graphics final : public love::graphics::Graphics {
 public:
-	Graphics() {
 #ifdef LOVE_ANDROID
+	Graphics() {
 		auto result = volkInitialize();
 		if (result != VK_SUCCESS) {
 			throw love::Exception("could not initialize volk");
 		}
-#endif
 	}
+#else
+	Graphics() = default;
+#endif
 
 	virtual ~Graphics();
 
@@ -243,7 +251,8 @@ private:
 		std::vector<VkVertexInputBindingDescription> &bindingDescriptions, 
 		std::vector<VkVertexInputAttributeDescription> &attributeDescriptions);
 	void prepareDraw(const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture, PrimitiveType, CullMode);
-	void startRenderPass(Texture*, uint32_t w, uint32_t h);
+	void startRenderPass(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture);
+	void startDefaultRenderPass();
 	void endRenderPass();
 	VkSampler createSampler(const SamplerState&);
 
@@ -271,7 +280,7 @@ private:
 	VkImage depthImage = VK_NULL_HANDLE;
 	VkImageView depthImageView = VK_NULL_HANDLE;
 	VmaAllocation depthImageAllocation = VK_NULL_HANDLE;
-	VkRenderPass defaultRenderPass;
+	VkRenderPass defaultRenderPass = VK_NULL_HANDLE;
 	std::vector<VkFramebuffer> defaultFramebuffers;
     std::unordered_map<RenderPassConfiguration, VkRenderPass, RenderPassConfigurationHasher> renderPasses;
 	std::unordered_map<FramebufferConfiguration, VkFramebuffer, FramebufferConfigurationHasher> framebuffers;
@@ -298,10 +307,10 @@ private:
 	std::vector<std::vector<std::function<void()>>> cleanUpFunctions;
 
 	// render pass variables.
-	graphics::Texture* currentTexture = nullptr;
 	Texture* renderTargetTexture = nullptr;
 	float currentViewportWidth = 0;
 	float currentViewportHeight = 0;
+	VkSampleCountFlagBits currentMsaaSamples = VK_SAMPLE_COUNT_1_BIT;
 };
 } // vulkan
 } // graphics