Browse Source

macOS: fix colors appearing oversaturated on P3 displays.

The fix only applies to macOS 11+ when using OpenGL.
slime 2 years ago
parent
commit
6173c1638d
4 changed files with 48 additions and 27 deletions
  1. 8 0
      src/common/macos.h
  2. 20 3
      src/common/macos.mm
  3. 0 6
      src/modules/graphics/metal/Graphics.mm
  4. 20 18
      src/modules/window/sdl/Window.cpp

+ 8 - 0
src/common/macos.h

@@ -26,6 +26,8 @@
 
 #include <string>
 
+typedef struct SDL_Window SDL_Window;
+
 namespace love
 {
 namespace macos
@@ -55,6 +57,12 @@ void requestAttention(bool continuous);
 void setMetalLayerVSync(void *metallayer, bool vsync);
 bool getMetalLayerVSync(void *metallayer);
 
+/**
+ * Explicitly sets the window's color space to be sRGB - which stops the OS
+ * from interpreting the backbuffer output as P3 on P3-capable displays.
+ **/
+void setWindowSRGBColorSpace(SDL_Window *window);
+
 } // macos
 } // love
 

+ 20 - 3
src/common/macos.mm

@@ -27,9 +27,11 @@
 #import <QuartzCore/CAMetalLayer.h>
 
 #ifdef LOVE_MACOSX_SDL_DIRECT_INCLUDE
-# include <SDL.h>
+#include <SDL.h>
+#include <SDL_syswm.h>
 #else
-# include <SDL2/SDL.h>
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_syswm.h>
 #endif
 
 namespace love
@@ -112,7 +114,22 @@ bool getMetalLayerVSync(void *metallayer)
 	return true;
 }
 
-} // osx
+void setWindowSRGBColorSpace(SDL_Window *window)
+{
+	@autoreleasepool
+	{
+		// This works on earlier macOS versions, but performance may be worse
+		// (at least, it was back when I tested in December 2016).
+		if (@available(macOS 11.0, *))
+		{
+			SDL_SysWMinfo info = {};
+			if (SDL_GetWindowWMInfo(window, &info))
+				info.info.cocoa.window.colorSpace = [NSColorSpace sRGBColorSpace];
+		}
+	}
+}
+
+} // macos
 } // love
 
 #endif // LOVE_MACOS

+ 0 - 6
src/modules/graphics/metal/Graphics.mm

@@ -479,12 +479,6 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int
 	metalLayer.device = device;
 	metalLayer.pixelFormat = isGammaCorrect() ? MTLPixelFormatBGRA8Unorm_sRGB : MTLPixelFormatBGRA8Unorm;
 
-	// Explicitly turn off color matching, for now (eg don't make sRGB content
-	// appear correct on P3 displays). It looks better with color matching, but
-	// having it off matches the OpenGL backend and there's some cost to it.
-	// TODO: revisit this?
-	metalLayer.colorspace = nil;
-
 	// This is set to NO when there are pending screen captures.
 	metalLayer.framebufferOnly = YES;
 

+ 20 - 18
src/modules/window/sdl/Window.cpp

@@ -366,27 +366,29 @@ bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowfla
 			return false;
 		}
 
-		if (renderer == love::graphics::Renderer::RENDERER_OPENGL) {
-			if (attribs != nullptr)
-			{
-				glcontext = SDL_GL_CreateContext(window);
+		if (attribs != nullptr && renderer == love::graphics::Renderer::RENDERER_OPENGL)
+		{
+#ifdef LOVE_MACOS
+			love::macos::setWindowSRGBColorSpace(window);
+#endif
 
-				if (!glcontext)
-					contexterror = std::string(SDL_GetError());
+			glcontext = SDL_GL_CreateContext(window);
 
-				// Make sure the context's version is at least what we requested.
-				if (glcontext && !checkGLVersion(*attribs, glversion))
-				{
-					SDL_GL_DeleteContext(glcontext);
-					glcontext = nullptr;
-				}
+			if (!glcontext)
+				contexterror = std::string(SDL_GetError());
 
-				if (!glcontext)
-				{
-					SDL_DestroyWindow(window);
-					window = nullptr;
-					return false;
-				}
+			// Make sure the context's version is at least what we requested.
+			if (glcontext && !checkGLVersion(*attribs, glversion))
+			{
+				SDL_GL_DeleteContext(glcontext);
+				glcontext = nullptr;
+			}
+
+			if (!glcontext)
+			{
+				SDL_DestroyWindow(window);
+				window = nullptr;
+				return false;
 			}
 		}