Browse Source

metal: some fixes for MSAA

Alex Szpakowski 3 years ago
parent
commit
4e1c4a6afe

+ 4 - 0
src/modules/graphics/metal/Graphics.h

@@ -123,6 +123,8 @@ public:
 	id<MTLCommandBuffer> getCommandBuffer() const { return commandBuffer; }
 	id<MTLCommandBuffer> getCommandBuffer() const { return commandBuffer; }
 	void submitCommandBuffer(SubmitType type);
 	void submitCommandBuffer(SubmitType type);
 
 
+	void submitAllEncoders(SubmitType type);
+
 	id<MTLRenderCommandEncoder> useRenderEncoder();
 	id<MTLRenderCommandEncoder> useRenderEncoder();
 	id<MTLRenderCommandEncoder> getRenderEncoder() const { return renderEncoder; }
 	id<MTLRenderCommandEncoder> getRenderEncoder() const { return renderEncoder; }
 	void submitRenderEncoder(SubmitType type);
 	void submitRenderEncoder(SubmitType type);
@@ -141,6 +143,8 @@ public:
 	Buffer *getDefaultAttributesBuffer() const { return defaultAttributesBuffer; }
 	Buffer *getDefaultAttributesBuffer() const { return defaultAttributesBuffer; }
 	Texture *getDefaultTexture(TextureType textype) const { return defaultTextures[textype]; }
 	Texture *getDefaultTexture(TextureType textype) const { return defaultTextures[textype]; }
 
 
+	int getClosestMSAASamples(int requestedsamples);
+
 	static Graphics *getInstance() { return graphicsInstance; }
 	static Graphics *getInstance() { return graphicsInstance; }
 
 
 	id<MTLDevice> device;
 	id<MTLDevice> device;

+ 28 - 20
src/modules/graphics/metal/Graphics.mm

@@ -118,7 +118,7 @@ static MTLPrimitiveType getMTLPrimitiveType(PrimitiveType prim)
 	{
 	{
 		case PRIMITIVE_TRIANGLES: return MTLPrimitiveTypeTriangle;
 		case PRIMITIVE_TRIANGLES: return MTLPrimitiveTypeTriangle;
 		case PRIMITIVE_TRIANGLE_STRIP: return MTLPrimitiveTypeTriangleStrip;
 		case PRIMITIVE_TRIANGLE_STRIP: return MTLPrimitiveTypeTriangleStrip;
-		case PRIMITIVE_TRIANGLE_FAN: return MTLPrimitiveTypeTriangle; // This needs to be emulated.
+		case PRIMITIVE_TRIANGLE_FAN: return MTLPrimitiveTypeTriangle; // TODO: This needs to be emulated.
 		case PRIMITIVE_POINTS: return MTLPrimitiveTypePoint;
 		case PRIMITIVE_POINTS: return MTLPrimitiveTypePoint;
 		case PRIMITIVE_MAX_ENUM: return MTLPrimitiveTypeTriangle;
 		case PRIMITIVE_MAX_ENUM: return MTLPrimitiveTypeTriangle;
 	}
 	}
@@ -448,7 +448,7 @@ void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelh
 	backbufferMSAA.set(nullptr);
 	backbufferMSAA.set(nullptr);
 	if (settings.msaa > 1)
 	if (settings.msaa > 1)
 	{
 	{
-		settings.format = isGammaCorrect() ? PIXELFORMAT_RGBA8_UNORM_sRGB : PIXELFORMAT_RGBA8_UNORM;
+		settings.format = isGammaCorrect() ? PIXELFORMAT_BGRA8_UNORM_sRGB : PIXELFORMAT_BGRA8_UNORM;
 		backbufferMSAA.set(newTexture(settings), Acquire::NORETAIN);
 		backbufferMSAA.set(newTexture(settings), Acquire::NORETAIN);
 	}
 	}
 
 
@@ -537,9 +537,7 @@ id<MTLCommandBuffer> Graphics::useCommandBuffer()
 
 
 void Graphics::submitCommandBuffer(SubmitType type)
 void Graphics::submitCommandBuffer(SubmitType type)
 {
 {
-	submitRenderEncoder(type);
-	submitBlitEncoder();
-	submitComputeEncoder();
+	submitAllEncoders(type);
 
 
 	if (commandBuffer != nil)
 	if (commandBuffer != nil)
 	{
 	{
@@ -548,6 +546,13 @@ void Graphics::submitCommandBuffer(SubmitType type)
 	}
 	}
 }
 }
 
 
+void Graphics::submitAllEncoders(SubmitType type)
+{
+	submitRenderEncoder(type);
+	submitBlitEncoder();
+	submitComputeEncoder();
+}
+
 static inline void setAttachment(const Graphics::RenderTarget &rt, MTLRenderPassAttachmentDescriptor *desc, MTLStoreAction &storeaction, bool setload = true)
 static inline void setAttachment(const Graphics::RenderTarget &rt, MTLRenderPassAttachmentDescriptor *desc, MTLStoreAction &storeaction, bool setload = true)
 {
 {
 	bool isvolume = rt.texture->getTextureType() == TEXTURE_VOLUME;
 	bool isvolume = rt.texture->getTextureType() == TEXTURE_VOLUME;
@@ -579,8 +584,7 @@ id<MTLRenderCommandEncoder> Graphics::useRenderEncoder()
 {
 {
 	if (renderEncoder == nil)
 	if (renderEncoder == nil)
 	{
 	{
-		submitBlitEncoder();
-		submitComputeEncoder();
+		submitAllEncoders(SUBMIT_STORE);
 
 
 		// Pass desc info for non-backbuffer render targets are set up in
 		// Pass desc info for non-backbuffer render targets are set up in
 		// setRenderTargetsInternal.
 		// setRenderTargetsInternal.
@@ -682,8 +686,7 @@ id<MTLBlitCommandEncoder> Graphics::useBlitEncoder()
 {
 {
 	if (blitEncoder == nil)
 	if (blitEncoder == nil)
 	{
 	{
-		submitRenderEncoder(SUBMIT_STORE);
-		submitComputeEncoder();
+		submitAllEncoders(SUBMIT_STORE);
 		blitEncoder = [useCommandBuffer() blitCommandEncoder];
 		blitEncoder = [useCommandBuffer() blitCommandEncoder];
 	}
 	}
 
 
@@ -703,8 +706,7 @@ id<MTLComputeCommandEncoder> Graphics::useComputeEncoder()
 {
 {
 	if (computeEncoder == nil)
 	if (computeEncoder == nil)
 	{
 	{
-		submitRenderEncoder(SUBMIT_STORE);
-		submitBlitEncoder();
+		submitAllEncoders(SUBMIT_STORE);
 		computeEncoder = [useCommandBuffer() computeCommandEncoder];
 		computeEncoder = [useCommandBuffer() computeCommandEncoder];
 		renderBindings = {};
 		renderBindings = {};
 	}
 	}
@@ -902,20 +904,26 @@ void Graphics::applyRenderState(id<MTLRenderCommandEncoder> encoder, const Verte
 			key.blend = state.blend;
 			key.blend = state.blend;
 			key.colorChannelMask = state.colorMask;
 			key.colorChannelMask = state.colorMask;
 
 
-			if (state.renderTargets.getFirstTarget().texture.get() == nullptr)
+			const auto &firsttarget = state.renderTargets.getFirstTarget();
+
+			if (firsttarget.texture.get() == nullptr)
 			{
 			{
 				key.colorRenderTargetFormats = isGammaCorrect() ? PIXELFORMAT_BGRA8_UNORM_sRGB : PIXELFORMAT_BGRA8_UNORM;
 				key.colorRenderTargetFormats = isGammaCorrect() ? PIXELFORMAT_BGRA8_UNORM_sRGB : PIXELFORMAT_BGRA8_UNORM;
 				key.depthStencilFormat = backbufferDepthStencil->getPixelFormat();
 				key.depthStencilFormat = backbufferDepthStencil->getPixelFormat();
+				key.msaa = backbufferMSAA ? (uint8) backbufferMSAA->getMSAA() : 1;
 			}
 			}
 			else
 			else
 			{
 			{
 				const auto &rts = state.renderTargets.colors;
 				const auto &rts = state.renderTargets.colors;
+
 				for (size_t i = 0; i < rts.size(); i++)
 				for (size_t i = 0; i < rts.size(); i++)
 					key.colorRenderTargetFormats |= (rts[i].texture->getPixelFormat()) << (8 * i);
 					key.colorRenderTargetFormats |= (rts[i].texture->getPixelFormat()) << (8 * i);
 
 
 				// TODO: automatic depth/stencil (state doesn't store it).
 				// TODO: automatic depth/stencil (state doesn't store it).
 				if (state.renderTargets.depthStencil.texture.get())
 				if (state.renderTargets.depthStencil.texture.get())
 					key.depthStencilFormat = state.renderTargets.depthStencil.texture->getPixelFormat();
 					key.depthStencilFormat = state.renderTargets.depthStencil.texture->getPixelFormat();
+
+				key.msaa = (uint8) firsttarget.texture->getMSAA();
 			}
 			}
 
 
 			pipeline = shader->getCachedRenderPipeline(key);
 			pipeline = shader->getCachedRenderPipeline(key);
@@ -2052,19 +2060,19 @@ Graphics::RendererInfo Graphics::getRendererInfo() const
 	return info;
 	return info;
 }
 }
 
 
-void Graphics::initCapabilities()
+int Graphics::getClosestMSAASamples(int requestedsamples)
 {
 {
-	int msaa = 1;
 	const int checkmsaa[] = {32, 16, 8, 4, 2};
 	const int checkmsaa[] = {32, 16, 8, 4, 2};
 	for (int samples : checkmsaa)
 	for (int samples : checkmsaa)
 	{
 	{
-		if ([device supportsTextureSampleCount:samples])
-		{
-			msaa = samples;
-			break;
-		}
+		if (samples <= requestedsamples && [device supportsTextureSampleCount:samples])
+			return samples;
 	}
 	}
+	return 1;
+}
 
 
+void Graphics::initCapabilities()
+{
 	if (@available(macOS 10.15, iOS 13.0, *))
 	if (@available(macOS 10.15, iOS 13.0, *))
 	{
 	{
 		for (NSInteger i = 0; i < 7; i++)
 		for (NSInteger i = 0; i < 7; i++)
@@ -2161,7 +2169,7 @@ void Graphics::initCapabilities()
 		capabilities.limits[LIMIT_RENDER_TARGETS] = 8;
 		capabilities.limits[LIMIT_RENDER_TARGETS] = 8;
 	else
 	else
 		capabilities.limits[LIMIT_RENDER_TARGETS] = 4;
 		capabilities.limits[LIMIT_RENDER_TARGETS] = 4;
-	capabilities.limits[LIMIT_TEXTURE_MSAA] = msaa;
+	capabilities.limits[LIMIT_TEXTURE_MSAA] = getClosestMSAASamples(32);
 	capabilities.limits[LIMIT_ANISOTROPY] = 16.0f;
 	capabilities.limits[LIMIT_ANISOTROPY] = 16.0f;
 	static_assert(LIMIT_MAX_ENUM == 13, "Graphics::initCapabilities must be updated when adding a new system limit!");
 	static_assert(LIMIT_MAX_ENUM == 13, "Graphics::initCapabilities must be updated when adding a new system limit!");
 
 

+ 3 - 1
src/modules/graphics/metal/Texture.h

@@ -49,7 +49,7 @@ public:
 	ptrdiff_t getRenderTargetHandle() const override { return msaaTexture != nil ? (ptrdiff_t) msaaTexture : (ptrdiff_t) texture; }
 	ptrdiff_t getRenderTargetHandle() const override { return msaaTexture != nil ? (ptrdiff_t) msaaTexture : (ptrdiff_t) texture; }
 	ptrdiff_t getSamplerHandle() const override { return (ptrdiff_t) sampler; }
 	ptrdiff_t getSamplerHandle() const override { return (ptrdiff_t) sampler; }
 
 
-	int getMSAA() const override { return 1 /* TODO*/; }
+	int getMSAA() const override { return actualMSAASamples; }
 
 
 	id<MTLSamplerState> getMTLSampler() const { return sampler; }
 	id<MTLSamplerState> getMTLSampler() const { return sampler; }
 
 
@@ -63,6 +63,8 @@ private:
 	id<MTLTexture> msaaTexture;
 	id<MTLTexture> msaaTexture;
 	id<MTLSamplerState> sampler;
 	id<MTLSamplerState> sampler;
 
 
+	int actualMSAASamples;
+
 }; // Texture
 }; // Texture
 
 
 } // metal
 } // metal

+ 10 - 6
src/modules/graphics/metal/Texture.mm

@@ -41,12 +41,15 @@ static MTLTextureType getMTLTextureType(TextureType type, int msaa)
 	return MTLTextureType2D;
 	return MTLTextureType2D;
 }
 }
 
 
-Texture::Texture(love::graphics::Graphics *gfx, id<MTLDevice> device, const Settings &settings, const Slices *data)
-	: love::graphics::Texture(gfx, settings, data)
+Texture::Texture(love::graphics::Graphics *gfxbase, id<MTLDevice> device, const Settings &settings, const Slices *data)
+	: love::graphics::Texture(gfxbase, settings, data)
 	, texture(nil)
 	, texture(nil)
 	, msaaTexture(nil)
 	, msaaTexture(nil)
 	, sampler(nil)
 	, sampler(nil)
+	, actualMSAASamples(1)
 { @autoreleasepool {
 { @autoreleasepool {
+	auto gfx = (Graphics *) gfxbase;
+
 	MTLTextureDescriptor *desc = [MTLTextureDescriptor new];
 	MTLTextureDescriptor *desc = [MTLTextureDescriptor new];
 
 
 	int w = pixelWidth;
 	int w = pixelWidth;
@@ -81,11 +84,12 @@ Texture::Texture(love::graphics::Graphics *gfx, id<MTLDevice> device, const Sett
 	if (texture == nil)
 	if (texture == nil)
 		throw love::Exception("Out of graphics memory.");
 		throw love::Exception("Out of graphics memory.");
 
 
-	if (getRequestedMSAA() > 1)
+	actualMSAASamples = gfx->getClosestMSAASamples(getRequestedMSAA());
+
+	if (actualMSAASamples > 1)
 	{
 	{
-		// TODO: sampleCount validation
-		desc.sampleCount = getRequestedMSAA();
-		desc.textureType = getMTLTextureType(texType, (int)desc.sampleCount);
+		desc.sampleCount = actualMSAASamples;
+		desc.textureType = getMTLTextureType(texType, actualMSAASamples);
 		desc.usage &= ~MTLTextureUsageShaderRead;
 		desc.usage &= ~MTLTextureUsageShaderRead;
 
 
 		// TODO: This needs to be cleared, etc.
 		// TODO: This needs to be cleared, etc.