Browse Source

vulkan: implement msaa

niki 3 years ago
parent
commit
a08395e12d
2 changed files with 153 additions and 39 deletions
  1. 136 30
      src/modules/graphics/vulkan/Graphics.cpp
  2. 17 9
      src/modules/graphics/vulkan/Graphics.h

+ 136 - 30
src/modules/graphics/vulkan/Graphics.cpp

@@ -220,6 +220,8 @@ void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelh
 }
 }
 
 
 bool Graphics::setMode(void* context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) {
 bool Graphics::setMode(void* context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) {
+	requestedMsaa = msaa;
+
 	cleanUpFunctions.clear();
 	cleanUpFunctions.clear();
 	cleanUpFunctions.resize(MAX_FRAMES_IN_FLIGHT);
 	cleanUpFunctions.resize(MAX_FRAMES_IN_FLIGHT);
 
 
@@ -232,6 +234,7 @@ bool Graphics::setMode(void* context, int width, int height, int pixelwidth, int
 	createSwapChain();
 	createSwapChain();
 	createImageViews();
 	createImageViews();
 	createSyncObjects();
 	createSyncObjects();
+	createColorResources();
 	createDepthResources();
 	createDepthResources();
 	createCommandPool();
 	createCommandPool();
 	createCommandBuffers();
 	createCommandBuffers();
@@ -324,7 +327,7 @@ void Graphics::initCapabilities() {
 }
 }
 
 
 void Graphics::getAPIStats(int& shaderswitches) const {
 void Graphics::getAPIStats(int& shaderswitches) const {
-	shaderswitches = Vulkan::getNumShaderSwitches();
+	shaderswitches = static_cast<int>(Vulkan::getNumShaderSwitches());
 }
 }
 
 
 void Graphics::unSetMode() {
 void Graphics::unSetMode() {
@@ -340,6 +343,14 @@ void Graphics::setActive(bool enable) {
 	active = enable;
 	active = enable;
 }
 }
 
 
+int Graphics::getRequestedBackbufferMSAA() const {
+	return requestedMsaa;
+}
+
+int Graphics::getBackbufferMSAA() const {
+	return actualMsaa;
+}
+
 void Graphics::setFrontFaceWinding(Winding winding) {
 void Graphics::setFrontFaceWinding(Winding winding) {
 	const auto& currentState = states.back();
 	const auto& currentState = states.back();
 
 
@@ -555,19 +566,23 @@ Matrix4 Graphics::computeDeviceProjection(const Matrix4& projection, bool render
 void Graphics::setRenderTargetsInternal(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) {
 void Graphics::setRenderTargetsInternal(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) {
 	endRenderPass();
 	endRenderPass();
 
 
-	if (rts.colors.size() == 0) {
+	if (rts.colors.empty()) {
 		startRenderPass(nullptr, swapChainExtent.width, swapChainExtent.height);
 		startRenderPass(nullptr, swapChainExtent.width, swapChainExtent.height);
 	} else {
 	} else {
 		// fixme: multi canvas render.
 		// fixme: multi canvas render.
 		auto& firstRenderTarget = rts.getFirstTarget();
 		auto& firstRenderTarget = rts.getFirstTarget();
-		startRenderPass(static_cast<Texture*>(firstRenderTarget.texture), pixelw, pixelh);
+		startRenderPass(dynamic_cast<Texture*>(firstRenderTarget.texture), pixelw, pixelh);
 	}
 	}
 }
 }
 
 
 // END IMPLEMENTATION OVERRIDDEN FUNCTIONS
 // END IMPLEMENTATION OVERRIDDEN FUNCTIONS
 
 
 void Graphics::initDynamicState() {
 void Graphics::initDynamicState() {
-	setScissor();
+	if (states.back().scissor) {
+		setScissor(states.back().scissorRect);
+	} else {
+		setScissor();
+	}
 }
 }
 
 
 void Graphics::startRecordingGraphicsCommands() {
 void Graphics::startRecordingGraphicsCommands() {
@@ -804,6 +819,8 @@ void Graphics::pickPhysicalDevice() {
 	VkPhysicalDeviceProperties properties;
 	VkPhysicalDeviceProperties properties;
 	vkGetPhysicalDeviceProperties(physicalDevice, &properties);
 	vkGetPhysicalDeviceProperties(physicalDevice, &properties);
 	minUniformBufferOffsetAlignment = properties.limits.minUniformBufferOffsetAlignment;
 	minUniformBufferOffsetAlignment = properties.limits.minUniformBufferOffsetAlignment;
+
+	getMaxUsableSampleCount();
 }
 }
 
 
 bool Graphics::checkDeviceExtensionSupport(VkPhysicalDevice device) {
 bool Graphics::checkDeviceExtensionSupport(VkPhysicalDevice device) {
@@ -1146,26 +1163,23 @@ VkPresentModeKHR Graphics::chooseSwapPresentMode(const std::vector<VkPresentMode
 		if (it != availablePresentModes.end()) {
 		if (it != availablePresentModes.end()) {
 			return VK_PRESENT_MODE_FIFO_RELAXED_KHR;
 			return VK_PRESENT_MODE_FIFO_RELAXED_KHR;
 		}
 		}
-		else {
-			[[fallthrough]];
-		}
-	}
-	case 1: {
-		auto it = std::find(availablePresentModes.begin(), availablePresentModes.end(), VK_PRESENT_MODE_MAILBOX_KHR);
-		if (it != availablePresentModes.end()) {
-			return VK_PRESENT_MODE_MAILBOX_KHR;
-		}
 		else {
 		else {
 			return VK_PRESENT_MODE_FIFO_KHR;
 			return VK_PRESENT_MODE_FIFO_KHR;
 		}
 		}
 	}
 	}
 	case 0: {
 	case 0: {
-		auto it = std::find(availablePresentModes.begin(), availablePresentModes.end(), VK_PRESENT_MODE_IMMEDIATE_KHR);
+		auto it = std::find(availablePresentModes.begin(), availablePresentModes.end(), VK_PRESENT_MODE_MAILBOX_KHR);
 		if (it != availablePresentModes.end()) {
 		if (it != availablePresentModes.end()) {
-			return VK_PRESENT_MODE_IMMEDIATE_KHR;
+			return VK_PRESENT_MODE_MAILBOX_KHR;
 		}
 		}
 		else {
 		else {
-			return VK_PRESENT_MODE_FIFO_KHR;
+			auto it = std::find(availablePresentModes.begin(), availablePresentModes.end(), VK_PRESENT_MODE_IMMEDIATE_KHR);
+			if (it != availablePresentModes.end()) {
+				return VK_PRESENT_MODE_IMMEDIATE_KHR;
+			}
+			else {
+				return VK_PRESENT_MODE_FIFO_KHR;
+			}
 		}
 		}
 	}
 	}
 	default:
 	default:
@@ -1182,7 +1196,6 @@ VkExtent2D Graphics::chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabiliti
 		const void* handle = window->getHandle();
 		const void* handle = window->getHandle();
 
 
 		int width, height;
 		int width, height;
-		// is this the equivalent of glfwGetFramebufferSize ?
 		SDL_Vulkan_GetDrawableSize((SDL_Window*)handle, &width, &height);
 		SDL_Vulkan_GetDrawableSize((SDL_Window*)handle, &width, &height);
 
 
 		VkExtent2D actualExtent = {
 		VkExtent2D actualExtent = {
@@ -1237,9 +1250,10 @@ void Graphics::createImageViews() {
 }
 }
 
 
 VkFramebuffer Graphics::createFramebuffer(FramebufferConfiguration configuration) {
 VkFramebuffer Graphics::createFramebuffer(FramebufferConfiguration configuration) {
-	std::array<VkImageView, 2> attachments = {
+	std::array<VkImageView, 3> attachments = {
+		colorImageView,
+		depthImageView,
 		configuration.imageView,
 		configuration.imageView,
-		depthImageView
 	};
 	};
 
 
 	VkFramebufferCreateInfo createInfo{};
 	VkFramebufferCreateInfo createInfo{};
@@ -1285,18 +1299,18 @@ void Graphics::createDefaultShaders() {
 
 
 VkRenderPass Graphics::createRenderPass(RenderPassConfiguration configuration) {
 VkRenderPass Graphics::createRenderPass(RenderPassConfiguration configuration) {
     VkAttachmentDescription colorDescription{};
     VkAttachmentDescription colorDescription{};
-    colorDescription.format = configuration.frameBufferFormat;
-    colorDescription.samples = VK_SAMPLE_COUNT_1_BIT;
+    colorDescription.format = swapChainImageFormat;
+    colorDescription.samples = msaaSamples;
     colorDescription.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
     colorDescription.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
     colorDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
     colorDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
     colorDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
     colorDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
     colorDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
     colorDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
-    colorDescription.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+    colorDescription.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
     colorDescription.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
     colorDescription.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
 
 
 	VkAttachmentDescription depthStencilAttachment{};
 	VkAttachmentDescription depthStencilAttachment{};
 	depthStencilAttachment.format = findDepthFormat();
 	depthStencilAttachment.format = findDepthFormat();
-	depthStencilAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
+	depthStencilAttachment.samples = msaaSamples;
 	depthStencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
 	depthStencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
 	depthStencilAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
 	depthStencilAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
 	depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
 	depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
@@ -1304,6 +1318,16 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration configuration) {
 	depthStencilAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
 	depthStencilAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
 	depthStencilAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
 	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;
+
     VkAttachmentReference colorAttachmentRef{};
     VkAttachmentReference colorAttachmentRef{};
     colorAttachmentRef.attachment = 0;
     colorAttachmentRef.attachment = 0;
     colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
     colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
@@ -1312,13 +1336,18 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration configuration) {
 	depthStencilAttachmentRef.attachment = 1;
 	depthStencilAttachmentRef.attachment = 1;
 	depthStencilAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
 	depthStencilAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
 
 
+	VkAttachmentReference colorAttachmentResolveRef{};
+	colorAttachmentResolveRef.attachment = 2;
+	colorAttachmentResolveRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
     VkSubpassDescription subPass{};
     VkSubpassDescription subPass{};
     subPass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
     subPass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
     subPass.colorAttachmentCount = 1;
     subPass.colorAttachmentCount = 1;
     subPass.pColorAttachments = &colorAttachmentRef;
     subPass.pColorAttachments = &colorAttachmentRef;
 	subPass.pDepthStencilAttachment = &depthStencilAttachmentRef;
 	subPass.pDepthStencilAttachment = &depthStencilAttachmentRef;
+	subPass.pResolveAttachments = &colorAttachmentResolveRef;
 
 
-	std::array<VkAttachmentDescription, 2> attachments = { colorDescription, depthStencilAttachment };
+	std::array<VkAttachmentDescription, 3> attachments = { colorDescription, depthStencilAttachment, colorAttachmentResolve };
 
 
 	VkSubpassDependency dependency{};
 	VkSubpassDependency dependency{};
 	dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
 	dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
@@ -1419,8 +1448,6 @@ void Graphics::createVulkanVertexFormat(
 }
 }
 
 
 void Graphics::prepareDraw(const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture, PrimitiveType primitiveType, CullMode cullmode) {
 void Graphics::prepareDraw(const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture, PrimitiveType primitiveType, CullMode cullmode) {
-	states.back().stencil;
-
 	GraphicsPipelineConfiguration configuration;
 	GraphicsPipelineConfiguration configuration;
     configuration.renderPass = currentRenderPass;
     configuration.renderPass = currentRenderPass;
 	configuration.vertexAttributes = attributes;
 	configuration.vertexAttributes = attributes;
@@ -1624,7 +1651,7 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration config
 	VkPipelineMultisampleStateCreateInfo multisampling{};
 	VkPipelineMultisampleStateCreateInfo multisampling{};
 	multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
 	multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
 	multisampling.sampleShadingEnable = VK_FALSE;
 	multisampling.sampleShadingEnable = VK_FALSE;
-	multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
+	multisampling.rasterizationSamples = msaaSamples;
 	multisampling.minSampleShading = 1.0f; // Optional
 	multisampling.minSampleShading = 1.0f; // Optional
 	multisampling.pSampleMask = nullptr; // Optional
 	multisampling.pSampleMask = nullptr; // Optional
 	multisampling.alphaToCoverageEnable = VK_FALSE; // Optional
 	multisampling.alphaToCoverageEnable = VK_FALSE; // Optional
@@ -1726,6 +1753,83 @@ void Graphics::ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration
 	}
 	}
 }
 }
 
 
+void Graphics::getMaxUsableSampleCount() {
+	VkPhysicalDeviceProperties physicalDeviceProperties;
+	vkGetPhysicalDeviceProperties(physicalDevice, &physicalDeviceProperties);
+
+	VkSampleCountFlags counts = physicalDeviceProperties.limits.framebufferColorSampleCounts & physicalDeviceProperties.limits.framebufferDepthSampleCounts;
+
+	if (counts & VK_SAMPLE_COUNT_64_BIT && requestedMsaa >= 64) { 
+		msaaSamples = VK_SAMPLE_COUNT_64_BIT;
+		actualMsaa = 64;
+	} else if (counts & VK_SAMPLE_COUNT_32_BIT && requestedMsaa >= 32) { 
+		msaaSamples = VK_SAMPLE_COUNT_32_BIT;
+		actualMsaa = 32;
+	}
+	else if (counts & VK_SAMPLE_COUNT_16_BIT && requestedMsaa >= 16) { 
+		msaaSamples = VK_SAMPLE_COUNT_16_BIT;
+		actualMsaa = 16;
+	}
+	else if (counts & VK_SAMPLE_COUNT_8_BIT && requestedMsaa >= 8) {
+		msaaSamples = VK_SAMPLE_COUNT_8_BIT;
+		actualMsaa = 8;
+	}
+	else if (counts & VK_SAMPLE_COUNT_4_BIT && requestedMsaa >= 4) {
+		msaaSamples = VK_SAMPLE_COUNT_4_BIT;
+		actualMsaa = 4;
+	}
+	else if (counts & VK_SAMPLE_COUNT_2_BIT && requestedMsaa >= 2) {
+		msaaSamples = VK_SAMPLE_COUNT_2_BIT;
+		actualMsaa = 2;
+	}
+	else {
+		msaaSamples = VK_SAMPLE_COUNT_1_BIT;
+		actualMsaa = 1;
+	}
+}
+
+void Graphics::createColorResources() {
+	VkFormat colorFormat = swapChainImageFormat;
+
+	VkImageCreateInfo imageInfo{};
+	imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+	imageInfo.imageType = VK_IMAGE_TYPE_2D;
+	imageInfo.format = colorFormat;
+	imageInfo.extent.width = swapChainExtent.width;
+	imageInfo.extent.height = swapChainExtent.height;
+	imageInfo.extent.depth = 1;
+	imageInfo.mipLevels = 1;
+	imageInfo.arrayLayers = 1;
+	imageInfo.samples = msaaSamples;
+	imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
+	imageInfo.usage = VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+	imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+	imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+
+	VmaAllocationCreateInfo allocationInfo{};
+	allocationInfo.usage = VMA_MEMORY_USAGE_AUTO;
+	allocationInfo.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
+
+	vmaCreateImage(vmaAllocator, &imageInfo, &allocationInfo, &colorImage, &colorImageAllocation, nullptr);
+
+	VkImageViewCreateInfo imageViewInfo{};
+	imageViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+	imageViewInfo.image = colorImage;
+	imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
+	imageViewInfo.format = colorFormat;
+	imageViewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
+	imageViewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
+	imageViewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
+	imageViewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
+	imageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+	imageViewInfo.subresourceRange.baseMipLevel = 0;
+	imageViewInfo.subresourceRange.levelCount = 1;
+	imageViewInfo.subresourceRange.baseArrayLayer = 0;
+	imageViewInfo.subresourceRange.layerCount = 1;
+
+	vkCreateImageView(device, &imageViewInfo, nullptr, &colorImageView);
+}
+
 VkFormat Graphics::findSupportedFormat(const std::vector<VkFormat>& candidates, VkImageTiling tiling, VkFormatFeatureFlags features) {
 VkFormat Graphics::findSupportedFormat(const std::vector<VkFormat>& candidates, VkImageTiling tiling, VkFormatFeatureFlags features) {
 	for (auto format : candidates) {
 	for (auto format : candidates) {
 		VkFormatProperties properties;
 		VkFormatProperties properties;
@@ -1741,7 +1845,6 @@ VkFormat Graphics::findSupportedFormat(const std::vector<VkFormat>& candidates,
 	throw love::Exception("failed to find supported format");
 	throw love::Exception("failed to find supported format");
 }
 }
 
 
-
 VkFormat Graphics::findDepthFormat() {
 VkFormat Graphics::findDepthFormat() {
 	return findSupportedFormat(
 	return findSupportedFormat(
 		{ VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT },
 		{ VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT },
@@ -1762,7 +1865,7 @@ void Graphics::createDepthResources() {
 	imageInfo.extent.depth = 1;
 	imageInfo.extent.depth = 1;
 	imageInfo.mipLevels = 1;
 	imageInfo.mipLevels = 1;
 	imageInfo.arrayLayers = 1;
 	imageInfo.arrayLayers = 1;
-	imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
+	imageInfo.samples = msaaSamples;
 	imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
 	imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
 	imageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
 	imageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
 	imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
 	imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
@@ -1854,7 +1957,7 @@ void Graphics::createSyncObjects() {
 
 
 void Graphics::createDefaultTexture() {
 void Graphics::createDefaultTexture() {
 	Texture::Settings settings;
 	Texture::Settings settings;
-	standardTexture.reset((Texture*)newTexture(settings));
+	standardTexture.reset((Texture*)newTexture(settings, nullptr));
 	uint8_t whitePixels[] = {255, 255, 255, 255};
 	uint8_t whitePixels[] = {255, 255, 255, 255};
 	standardTexture->replacePixels(whitePixels, sizeof(whitePixels), 0, 0, { 0, 0, 1, 1 }, false);
 	standardTexture->replacePixels(whitePixels, sizeof(whitePixels), 0, 0, { 0, 0, 1, 1 }, false);
 }
 }
@@ -1905,6 +2008,8 @@ void Graphics::cleanup() {
 }
 }
 
 
 void Graphics::cleanupSwapChain() {
 void Graphics::cleanupSwapChain() {
+	vkDestroyImageView(device, colorImageView, nullptr);
+	vmaDestroyImage(vmaAllocator, colorImage, colorImageAllocation);
 	vkDestroyImageView(device, depthImageView, nullptr);
 	vkDestroyImageView(device, depthImageView, nullptr);
 	vmaDestroyImage(vmaAllocator, depthImage, depthImageAllocation);
 	vmaDestroyImage(vmaAllocator, depthImage, depthImageAllocation);
 	for (const auto& [key, val] : framebuffers) {
 	for (const auto& [key, val] : framebuffers) {
@@ -1925,6 +2030,7 @@ void Graphics::recreateSwapChain() {
 
 
 	createSwapChain();
 	createSwapChain();
 	createImageViews();
 	createImageViews();
+	createColorResources();
 	createDepthResources();
 	createDepthResources();
 }
 }
 
 

+ 17 - 9
src/modules/graphics/vulkan/Graphics.h

@@ -139,7 +139,7 @@ public:
 	const VmaAllocator getVmaAllocator() const;
 	const VmaAllocator getVmaAllocator() const;
 
 
 	// implementation for virtual functions
 	// implementation for virtual functions
-	love::graphics::Texture* newTexture(const love::graphics::Texture::Settings& settings, const love::graphics::Texture::Slices* data = nullptr) override;
+	love::graphics::Texture* newTexture(const love::graphics::Texture::Settings& settings, const love::graphics::Texture::Slices* data) override;
 	love::graphics::Buffer* newBuffer(const love::graphics::Buffer::Settings& settings, const std::vector<love::graphics::Buffer::DataDeclaration>& format, const void* data, size_t size, size_t arraylength) override;
 	love::graphics::Buffer* newBuffer(const love::graphics::Buffer::Settings& settings, const std::vector<love::graphics::Buffer::DataDeclaration>& format, const void* data, size_t size, size_t arraylength) override;
 	void clear(OptionalColorD color, OptionalInt stencil, OptionalDouble depth) override;
 	void clear(OptionalColorD color, OptionalInt stencil, OptionalDouble depth) override;
 	void clear(const std::vector<OptionalColorD>& colors, OptionalInt stencil, OptionalDouble depth) override;
 	void clear(const std::vector<OptionalColorD>& colors, OptionalInt stencil, OptionalDouble depth) override;
@@ -150,8 +150,8 @@ public:
 	bool setMode(void* context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) override;
 	bool setMode(void* context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) override;
 	void unSetMode() override;
 	void unSetMode() override;
 	void setActive(bool active) override;
 	void setActive(bool active) override;
-	int getRequestedBackbufferMSAA() const override { return 0; }
-	int getBackbufferMSAA() const  override { return 0; }
+	int getRequestedBackbufferMSAA() const override;
+	int getBackbufferMSAA() const  override;
 	void setColor(Colorf c) override;
 	void setColor(Colorf c) override;
 	void setScissor(const Rect& rect) override;
 	void setScissor(const Rect& rect) override;
 	void setScissor() override;
 	void setScissor() override;
@@ -163,7 +163,7 @@ public:
 	void setPointSize(float size) override;
 	void setPointSize(float size) override;
 	void setWireframe(bool enable) override;
 	void setWireframe(bool enable) override;
 	PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const override;
 	PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const override;
-	bool isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB = false) override;
+	bool isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB) override;
 	Renderer getRenderer() const override;
 	Renderer getRenderer() const override;
 	bool usesGLSLES() const override;
 	bool usesGLSLES() const override;
 	RendererInfo getRendererInfo() const override;
 	RendererInfo getRendererInfo() const override;
@@ -172,7 +172,7 @@ public:
 	void drawQuads(int start, int count, const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture) override;
 	void drawQuads(int start, int count, const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture) override;
 
 
 	GraphicsReadback* newReadbackInternal(ReadbackMethod method, love::graphics::Buffer* buffer, size_t offset, size_t size, data::ByteData* dest, size_t destoffset) override { return nullptr;  };
 	GraphicsReadback* newReadbackInternal(ReadbackMethod method, love::graphics::Buffer* buffer, size_t offset, size_t size, data::ByteData* dest, size_t destoffset) override { return nullptr;  };
-	GraphicsReadback* newReadbackInternal(ReadbackMethod method, love::graphics::Texture* texture, int slice, int mipmap, const Rect& rect, image::ImageData* dest, int destx, int desty) { return nullptr; }
+	GraphicsReadback* newReadbackInternal(ReadbackMethod method, love::graphics::Texture* texture, int slice, int mipmap, const Rect& rect, image::ImageData* dest, int destx, int desty) override { return nullptr; }
 
 
 	VkCommandBuffer getDataTransferCommandBuffer();
 	VkCommandBuffer getDataTransferCommandBuffer();
 	void queueCleanUp(std::function<void()> cleanUp);
 	void queueCleanUp(std::function<void()> cleanUp);
@@ -199,6 +199,7 @@ private:
 	void createVulkanInstance();
 	void createVulkanInstance();
 	bool checkValidationSupport();
 	bool checkValidationSupport();
 	void pickPhysicalDevice();
 	void pickPhysicalDevice();
+	void getMaxUsableSampleCount();
 	int rateDeviceSuitability(VkPhysicalDevice device);
 	int rateDeviceSuitability(VkPhysicalDevice device);
 	QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device);
 	QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device);
 	void createLogicalDevice();
 	void createLogicalDevice();
@@ -217,6 +218,7 @@ private:
 	void createDefaultShaders();
 	void createDefaultShaders();
     VkRenderPass createRenderPass(RenderPassConfiguration);
     VkRenderPass createRenderPass(RenderPassConfiguration);
 	VkPipeline createGraphicsPipeline(GraphicsPipelineConfiguration);
 	VkPipeline createGraphicsPipeline(GraphicsPipelineConfiguration);
+	void createColorResources();
 	VkFormat findSupportedFormat(const std::vector<VkFormat>& candidates, VkImageTiling tiling, VkFormatFeatureFlags features);
 	VkFormat findSupportedFormat(const std::vector<VkFormat>& candidates, VkImageTiling tiling, VkFormatFeatureFlags features);
 	VkFormat findDepthFormat();
 	VkFormat findDepthFormat();
 	void createDepthResources();
 	void createDepthResources();
@@ -245,12 +247,14 @@ private:
 
 
 	VkInstance instance = VK_NULL_HANDLE;
 	VkInstance instance = VK_NULL_HANDLE;
 	VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
 	VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
+	int requestedMsaa = 0;
+	int actualMsaa = 0;
 	VkDevice device = VK_NULL_HANDLE;
 	VkDevice device = VK_NULL_HANDLE;
 	VkQueue graphicsQueue = VK_NULL_HANDLE;
 	VkQueue graphicsQueue = VK_NULL_HANDLE;
 	VkQueue presentQueue = VK_NULL_HANDLE;
 	VkQueue presentQueue = VK_NULL_HANDLE;
 	VkSurfaceKHR surface = VK_NULL_HANDLE;
 	VkSurfaceKHR surface = VK_NULL_HANDLE;
     VkSwapchainKHR swapChain = VK_NULL_HANDLE;
     VkSwapchainKHR swapChain = VK_NULL_HANDLE;
-	VkSurfaceTransformFlagBitsKHR preTransform;
+	VkSurfaceTransformFlagBitsKHR preTransform = {};
 	Matrix4 displayRotation;
 	Matrix4 displayRotation;
 	std::vector<VkImage> swapChainImages;
 	std::vector<VkImage> swapChainImages;
 	VkFormat swapChainImageFormat = VK_FORMAT_UNDEFINED;
 	VkFormat swapChainImageFormat = VK_FORMAT_UNDEFINED;
@@ -258,9 +262,13 @@ private:
 	std::vector<VkImageView> swapChainImageViews;
 	std::vector<VkImageView> swapChainImageViews;
 	VkPipeline currentGraphicsPipeline = VK_NULL_HANDLE;
 	VkPipeline currentGraphicsPipeline = VK_NULL_HANDLE;
     VkRenderPass currentRenderPass = VK_NULL_HANDLE;
     VkRenderPass currentRenderPass = VK_NULL_HANDLE;
-	VkImage depthImage;
-	VkImageView depthImageView;
-	VmaAllocation depthImageAllocation;
+	VkSampleCountFlagBits msaaSamples;
+	VkImage colorImage = VK_NULL_HANDLE;
+	VkImageView colorImageView = VK_NULL_HANDLE;
+	VmaAllocation colorImageAllocation = VK_NULL_HANDLE;
+	VkImage depthImage = VK_NULL_HANDLE;
+	VkImageView depthImageView = VK_NULL_HANDLE;
+	VmaAllocation depthImageAllocation = VK_NULL_HANDLE;
     std::unordered_map<RenderPassConfiguration, VkRenderPass, RenderPassConfigurationHasher> renderPasses;
     std::unordered_map<RenderPassConfiguration, VkRenderPass, RenderPassConfigurationHasher> renderPasses;
 	std::unordered_map<FramebufferConfiguration, VkFramebuffer, FramebufferConfigurationHasher> framebuffers;
 	std::unordered_map<FramebufferConfiguration, VkFramebuffer, FramebufferConfigurationHasher> framebuffers;
 	std::unordered_map<GraphicsPipelineConfiguration, VkPipeline, GraphicsPipelineConfigurationHasher> graphicsPipelines;
 	std::unordered_map<GraphicsPipelineConfiguration, VkPipeline, GraphicsPipelineConfigurationHasher> graphicsPipelines;