Commit: 32d19f7317e9f2d726230a67ba9fed623fee337e
Author: Jason Fielder
Date:   Tue Sep 6 07:55:21 2022 +0200
Branches: master
https://developer.blender.org/rB32d19f7317e9f2d726230a67ba9fed623fee337e

MacOS: Resolve purple rendering artifacts in EEVEE materials by increasing 
sampler limit.

Enables a feature flag during OpenGL device initialisation on macOS, which 
increases the available number of texture samplers available for use within 
shaders. Enabling this flag removes purple rendering artifacts present in 
certain EEVEE materials, when the existing limit of 16 is exceeded.

This feature flag is supported on Apple Silicon and AMD GPUs, for devices 
supporting macOS 11.0+. Device initialisation first tests whether GL device 
creation with the flag is supported, if not, we fall back to standard 
initialisation.

Other solutions would not be trivial or incur additional performance overhead 
or feature limitations. Other workarounds, such as texture atlas's, could 
already be created by artists.

{F13245498}

{F13245497}

Reviewed By: jbakker

Maniphest Tasks: T57759, T63935

Differential Revision: https://developer.blender.org/D15336

===================================================================

M       intern/ghost/intern/GHOST_ContextCGL.mm

===================================================================

diff --git a/intern/ghost/intern/GHOST_ContextCGL.mm 
b/intern/ghost/intern/GHOST_ContextCGL.mm
index 6da44ec481c..eb84f901d80 100644
--- a/intern/ghost/intern/GHOST_ContextCGL.mm
+++ b/intern/ghost/intern/GHOST_ContextCGL.mm
@@ -193,7 +193,8 @@ GHOST_TSuccess GHOST_ContextCGL::updateDrawingContext()
 static void makeAttribList(std::vector<NSOpenGLPixelFormatAttribute> &attribs,
                            bool stereoVisual,
                            bool needAlpha,
-                           bool softwareGL)
+                           bool softwareGL,
+                           bool increasedSamplerLimit)
 {
   attribs.clear();
 
@@ -210,6 +211,12 @@ static void 
makeAttribList(std::vector<NSOpenGLPixelFormatAttribute> &attribs,
   else {
     attribs.push_back(NSOpenGLPFAAccelerated);
     attribs.push_back(NSOpenGLPFANoRecovery);
+
+    /* Attempt to initialise device with extended sampler limit.
+     * Resolves EEVEE purple rendering artifacts on macOS. */
+    if (increasedSamplerLimit) {
+      attribs.push_back((NSOpenGLPixelFormatAttribute)400);
+    }
   }
 
   if (stereoVisual)
@@ -225,80 +232,123 @@ static void 
makeAttribList(std::vector<NSOpenGLPixelFormatAttribute> &attribs,
 
 GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
 {
-  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+  @autoreleasepool {
 
 #ifdef GHOST_OPENGL_ALPHA
-  static const bool needAlpha = true;
+    static const bool needAlpha = true;
 #else
-  static const bool needAlpha = false;
+    static const bool needAlpha = false;
 #endif
 
-  /* Command-line argument would be better. */
-  static bool softwareGL = getenv("BLENDER_SOFTWAREGL");
-
-  std::vector<NSOpenGLPixelFormatAttribute> attribs;
-  attribs.reserve(40);
-  makeAttribList(attribs, m_stereoVisual, needAlpha, softwareGL);
+    /* Command-line argument would be better. */
+    static bool softwareGL = getenv("BLENDER_SOFTWAREGL");
+
+    NSOpenGLPixelFormat *pixelFormat = nil;
+    std::vector<NSOpenGLPixelFormatAttribute> attribs;
+    bool increasedSamplerLimit = false;
+
+    /* Attempt to initialize device with increased sampler limit.
+     * If this is unsupported and initialization fails, initialize GL Context 
as normal.
+     *
+     * NOTE: This is not available when using the SoftwareGL path, or for 
Intel-based
+     * platforms. */
+    if (!softwareGL) {
+      if (@available(macos 11.0, *)) {
+        increasedSamplerLimit = true;
+      }
+    }
+    const int max_ctx_attempts = increasedSamplerLimit ? 2 : 1;
+    for (int ctx_create_attempt = 0; ctx_create_attempt < max_ctx_attempts; 
ctx_create_attempt++) {
+
+      attribs.clear();
+      attribs.reserve(40);
+      makeAttribList(attribs, m_stereoVisual, needAlpha, softwareGL, 
increasedSamplerLimit);
+
+      pixelFormat = [[NSOpenGLPixelFormat alloc] 
initWithAttributes:&attribs[0]];
+      if (pixelFormat == nil) {
+        /* If pixel format creation fails when testing increased sampler limit,
+         * attempt intialisation again with feature disabled, otherwise, fail. 
*/
+        if (increasedSamplerLimit) {
+          increasedSamplerLimit = false;
+          continue;
+        }
+        return GHOST_kFailure;
+      }
 
-  NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] 
initWithAttributes:&attribs[0]];
-  if (pixelFormat == nil) {
-    goto error;
-  }
+      /* Attempt to create context. */
+      m_openGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat
+                                                   
shareContext:s_sharedOpenGLContext];
+      [pixelFormat release];
+
+      if (m_openGLContext == nil) {
+        /* If context creation fails when testing increased sampler limit,
+         * attempt re-creation with feature disabled. Otherwise, error. */
+        if (increasedSamplerLimit) {
+          increasedSamplerLimit = false;
+          continue;
+        }
+
+        /* Default context creation attempt failed. */
+        return GHOST_kFailure;
+      }
 
-  m_openGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat
-                                               
shareContext:s_sharedOpenGLContext];
-  [pixelFormat release];
+      /* Created GL context successfully, activate. */
+      [m_openGLContext makeCurrentContext];
 
-  [m_openGLContext makeCurrentContext];
+      /* When increasing sampler limit, verify created context is a supported 
configuration. */
+      if (increasedSamplerLimit) {
+        const char *vendor = (const char *)glGetString(GL_VENDOR);
+        const char *renderer = (const char *)glGetString(GL_RENDERER);
+
+        /* If generated context type is unsupported, release existing context 
and
+         * fallback to creating a normal context below. */
+        if (strstr(vendor, "Intel") || strstr(renderer, "Software")) {
+          [m_openGLContext release];
+          m_openGLContext = nil;
+          increasedSamplerLimit = false;
+          continue;
+        }
+      }
+    }
 
-  if (m_debug) {
-    GLint major = 0, minor = 0;
-    glGetIntegerv(GL_MAJOR_VERSION, &major);
-    glGetIntegerv(GL_MINOR_VERSION, &minor);
-    fprintf(stderr, "OpenGL version %d.%d%s\n", major, minor, softwareGL ? " 
(software)" : "");
-    fprintf(stderr, "Renderer: %s\n", glGetString(GL_RENDERER));
-  }
+    if (m_debug) {
+      GLint major = 0, minor = 0;
+      glGetIntegerv(GL_MAJOR_VERSION, &major);
+      glGetIntegerv(GL_MINOR_VERSION, &minor);
+      fprintf(stderr, "OpenGL version %d.%d%s\n", major, minor, softwareGL ? " 
(software)" : "");
+      fprintf(stderr, "Renderer: %s\n", glGetString(GL_RENDERER));
+    }
 
 #ifdef GHOST_WAIT_FOR_VSYNC
-  {
-    GLint swapInt = 1;
-    /* Wait for vertical-sync, to avoid tearing artifacts. */
-    [m_openGLContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
-  }
+    {
+      GLint swapInt = 1;
+      /* Wait for vertical-sync, to avoid tearing artifacts. */
+      [m_openGLContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
+    }
 #endif
 
-  if (m_metalView) {
-    if (m_defaultFramebuffer == 0) {
-      /* Create a virtual frame-buffer. */
-      [m_openGLContext makeCurrentContext];
-      metalInitFramebuffer();
+    if (m_metalView) {
+      if (m_defaultFramebuffer == 0) {
+        /* Create a virtual frame-buffer. */
+        [m_openGLContext makeCurrentContext];
+        metalInitFramebuffer();
+        initClearGL();
+      }
+    }
+    else if (m_openGLView) {
+      [m_openGLView setOpenGLContext:m_openGLContext];
+      [m_openGLContext setView:m_openGLView];
       initClearGL();
     }
-  }
-  else if (m_openGLView) {
-    [m_openGLView setOpenGLContext:m_openGLContext];
-    [m_openGLContext setView:m_openGLView];
-    initClearGL();
-  }
-
-  [m_openGLContext flushBuffer];
 
-  if (s_sharedCount == 0)
-    s_sharedOpenGLContext = m_openGLContext;
+    [m_openGLContext flushBuffer];
 
-  s_sharedCount++;
-
-  [pool drain];
+    if (s_sharedCount == 0)
+      s_sharedOpenGLContext = m_openGLContext;
 
+    s_sharedCount++;
+  }
   return GHOST_kSuccess;
-
-error:
-
-  [pixelFormat release];
-
-  [pool drain];
-
-  return GHOST_kFailure;
 }
 
 GHOST_TSuccess GHOST_ContextCGL::releaseNativeHandles()

_______________________________________________
Bf-blender-cvs mailing list
Bf-blender-cvs@blender.org
List details, subscription details or unsubscribe:
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to