GHOST: Delete Mac OpenGL support

The maximum OpenGL versions supported on mac
doesn't meet the minimum required version (>=4.3) anymore.

This removes all the OpenGL paths in GHOST
Cocoa backend and from the drop down menu in
the user preferences.

Pull Request: https://projects.blender.org/blender/blender/pulls/110185
This commit is contained in:
Clément Foucault 2023-07-19 14:16:03 +02:00 committed by Jeroen Bakker
parent 940558f9ac
commit cdb8a8929c
8 changed files with 113 additions and 646 deletions

@ -650,8 +650,12 @@ mark_as_advanced(
)
# OpenGL
if(NOT APPLE)
option(WITH_OPENGL_BACKEND "Enable OpenGL support as graphic backend" ON)
mark_as_advanced(WITH_OPENGL_BACKEND)
else()
set(WITH_OPENGL_BACKEND OFF)
endif()
# Vulkan
option(WITH_VULKAN_BACKEND "Enable Vulkan as graphics backend (only for development)" OFF)

@ -44,11 +44,7 @@ class GHOST_ContextCGL : public GHOST_Context {
/**
* Constructor.
*/
GHOST_ContextCGL(bool stereoVisual,
NSView *metalView,
CAMetalLayer *metalLayer,
NSOpenGLView *openglView,
GHOST_TDrawingContextType type);
GHOST_ContextCGL(bool stereoVisual, NSView *metalView, CAMetalLayer *metalLayer, int debug);
/**
* Destructor.
@ -134,23 +130,11 @@ class GHOST_ContextCGL : public GHOST_Context {
private:
/** Metal state */
/* Set this flag to `true` when rendering with Metal API for Viewport.
* TODO(Metal): This should be assigned to externally. */
bool m_useMetalForRendering = false;
NSView *m_metalView;
CAMetalLayer *m_metalLayer;
MTLRenderPipelineState *m_metalRenderPipeline;
bool m_ownsMetalDevice;
/** OpenGL state, for GPUs that don't support Metal */
NSOpenGLView *m_openGLView;
/** The OpenGL drawing context */
NSOpenGLContext *m_openGLContext;
/** The virtualized default frame-buffer. */
unsigned int m_defaultFramebuffer;
/** The virtualized default frame-buffer's texture. */
/**
* Texture that you can render into with Metal. The texture will be
@ -191,5 +175,5 @@ class GHOST_ContextCGL : public GHOST_Context {
void metalInitFramebuffer();
void metalUpdateFramebuffer();
void metalSwapBuffers();
void initClear();
void initClear(){};
};

@ -27,9 +27,7 @@
static void ghost_fatal_error_dialog(const char *msg)
{
/* clang-format off */
@autoreleasepool {
/* clang-format on */
NSString *message = [NSString stringWithFormat:@"Error opening window:\n%s", msg];
NSAlert *alert = [[NSAlert alloc] init];
@ -50,17 +48,12 @@ int GHOST_ContextCGL::s_sharedCount = 0;
GHOST_ContextCGL::GHOST_ContextCGL(bool stereoVisual,
NSView *metalView,
CAMetalLayer *metalLayer,
NSOpenGLView *openGLView,
GHOST_TDrawingContextType type)
int debug)
: GHOST_Context(stereoVisual),
m_useMetalForRendering(type == GHOST_kDrawingContextTypeMetal),
m_metalView(metalView),
m_metalLayer(metalLayer),
m_metalRenderPipeline(nil),
m_openGLView(openGLView),
m_openGLContext(nil),
m_defaultFramebuffer(0),
m_debug(false)
m_debug(debug)
{
/* Initialize Metal Swap-chain. */
current_swapchain_index = 0;
@ -68,6 +61,7 @@ GHOST_ContextCGL::GHOST_ContextCGL(bool stereoVisual,
m_defaultFramebufferMetalTexture[i].texture = nil;
m_defaultFramebufferMetalTexture[i].index = i;
}
if (m_metalView) {
m_ownsMetalDevice = false;
metalInit();
@ -107,31 +101,6 @@ GHOST_ContextCGL::~GHOST_ContextCGL()
{
metalFree();
if (!m_useMetalForRendering) {
#ifdef WITH_OPENGL_BACKEND
if (m_openGLContext != nil) {
if (m_openGLContext == [NSOpenGLContext currentContext]) {
[NSOpenGLContext clearCurrentContext];
if (m_openGLView) {
[m_openGLView clearGLContext];
}
}
if (m_openGLContext != s_sharedOpenGLContext || s_sharedCount == 1) {
assert(s_sharedCount > 0);
s_sharedCount--;
if (s_sharedCount == 0)
s_sharedOpenGLContext = nil;
[m_openGLContext release];
}
}
#endif
}
if (m_ownsMetalDevice) {
if (m_metalLayer) {
[m_metalLayer release];
@ -142,166 +111,46 @@ GHOST_ContextCGL::~GHOST_ContextCGL()
GHOST_TSuccess GHOST_ContextCGL::swapBuffers()
{
GHOST_TSuccess return_value = GHOST_kFailure;
if (!m_useMetalForRendering) {
#ifdef WITH_OPENGL_BACKEND
if (m_openGLContext != nil) {
if (m_metalView) {
metalSwapBuffers();
}
else if (m_openGLView) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[m_openGLContext flushBuffer];
[pool drain];
}
return_value = GHOST_kSuccess;
}
else {
return_value = GHOST_kFailure;
}
#endif
}
else {
if (m_metalView) {
metalSwapBuffers();
}
return_value = GHOST_kSuccess;
}
return return_value;
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_ContextCGL::setSwapInterval(int interval)
{
if (!m_useMetalForRendering) {
#ifdef WITH_OPENGL_BACKEND
if (m_openGLContext != nil) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[m_openGLContext setValues:&interval forParameter:NSOpenGLCPSwapInterval];
[pool drain];
return GHOST_kSuccess;
}
else {
return GHOST_kFailure;
}
#endif
}
else {
mtl_SwapInterval = interval;
return GHOST_kSuccess;
}
}
GHOST_TSuccess GHOST_ContextCGL::getSwapInterval(int &intervalOut)
{
if (!m_useMetalForRendering) {
#ifdef WITH_OPENGL_BACKEND
if (m_openGLContext != nil) {
GLint interval;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[m_openGLContext getValues:&interval forParameter:NSOpenGLCPSwapInterval];
[pool drain];
intervalOut = static_cast<int>(interval);
return GHOST_kSuccess;
}
else {
return GHOST_kFailure;
}
#endif
}
else {
intervalOut = mtl_SwapInterval;
return GHOST_kSuccess;
}
}
GHOST_TSuccess GHOST_ContextCGL::activateDrawingContext()
{
if (!m_useMetalForRendering) {
#ifdef WITH_OPENGL_BACKEND
if (m_openGLContext != nil) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[m_openGLContext makeCurrentContext];
[pool drain];
return GHOST_kSuccess;
}
else {
return GHOST_kFailure;
}
#endif
}
else {
return GHOST_kSuccess;
}
}
GHOST_TSuccess GHOST_ContextCGL::releaseDrawingContext()
{
if (!m_useMetalForRendering) {
#ifdef WITH_OPENGL_BACKEND
if (m_openGLContext != nil) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[NSOpenGLContext clearCurrentContext];
[pool drain];
return GHOST_kSuccess;
}
else {
return GHOST_kFailure;
}
#endif
}
else {
return GHOST_kSuccess;
}
}
unsigned int GHOST_ContextCGL::getDefaultFramebuffer()
{
if (!m_useMetalForRendering) {
return m_defaultFramebuffer;
}
/* NOTE(Metal): This is not valid. */
return 0;
}
GHOST_TSuccess GHOST_ContextCGL::updateDrawingContext()
{
if (!m_useMetalForRendering) {
#ifdef WITH_OPENGL_BACKEND
if (m_openGLContext != nil) {
if (m_metalView) {
metalUpdateFramebuffer();
}
else if (m_openGLView) {
@autoreleasepool {
[m_openGLContext update];
}
}
return GHOST_kSuccess;
}
else {
return GHOST_kFailure;
}
#endif
}
else {
if (m_metalView) {
metalUpdateFramebuffer();
return GHOST_kSuccess;
}
}
return GHOST_kFailure;
}
@ -333,202 +182,28 @@ void GHOST_ContextCGL::metalRegisterPresentCallback(void (*callback)(
this->contextPresentCallback = callback;
}
static void makeAttribList(std::vector<NSOpenGLPixelFormatAttribute> &attribs,
bool stereoVisual,
bool needAlpha,
bool softwareGL,
bool increasedSamplerLimit)
{
attribs.clear();
attribs.push_back(NSOpenGLPFAOpenGLProfile);
attribs.push_back(NSOpenGLProfileVersion3_2Core);
/* Pixel Format Attributes for the windowed #NSOpenGLContext. */
attribs.push_back(NSOpenGLPFADoubleBuffer);
if (softwareGL) {
attribs.push_back(NSOpenGLPFARendererID);
attribs.push_back(kCGLRendererGenericFloatID);
}
else {
attribs.push_back(NSOpenGLPFAAccelerated);
attribs.push_back(NSOpenGLPFANoRecovery);
/* Attempt to initialize device with extended sampler limit.
* Resolves EEVEE purple rendering artifacts on macOS. */
if (increasedSamplerLimit) {
attribs.push_back((NSOpenGLPixelFormatAttribute)400);
}
}
if (stereoVisual)
attribs.push_back(NSOpenGLPFAStereo);
if (needAlpha) {
attribs.push_back(NSOpenGLPFAAlphaSize);
attribs.push_back((NSOpenGLPixelFormatAttribute)8);
}
attribs.push_back((NSOpenGLPixelFormatAttribute)0);
}
GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
{
@autoreleasepool {
#ifdef GHOST_OPENGL_ALPHA
static const bool needAlpha = true;
#else
static const bool needAlpha = false;
#endif
/* Command-line argument would be better. */
if (!m_useMetalForRendering) {
#ifdef WITH_OPENGL_BACKEND
/* 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 initialization again with feature disabled, otherwise, fail. */
if (increasedSamplerLimit) {
increasedSamplerLimit = false;
continue;
}
return GHOST_kFailure;
}
/* 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;
}
/* Created GL context successfully, activate. */
[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));
}
# ifdef GHOST_WAIT_FOR_VSYNC
{
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();
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;
s_sharedCount++;
#endif
}
else {
/* NOTE(Metal): Metal-only path. */
if (m_metalView) {
metalInitFramebuffer();
}
}
}
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_ContextCGL::releaseNativeHandles()
{
#ifdef WITH_OPENGL_BACKEND
m_openGLContext = nil;
m_openGLView = nil;
#endif
m_metalView = nil;
return GHOST_kSuccess;
}
/* OpenGL on Metal
*
* Use Metal layer to avoid Viewport lagging on macOS, see #60043. */
static const MTLPixelFormat METAL_FRAMEBUFFERPIXEL_FORMAT = MTLPixelFormatBGRA8Unorm;
static const OSType METAL_CORE_VIDEO_PIXEL_FORMAT = kCVPixelFormatType_32BGRA;
void GHOST_ContextCGL::metalInit()
{
/* clang-format off */
@autoreleasepool {
/* clang-format on */
id<MTLDevice> device = m_metalLayer.device;
/* Create a command queue for blit/present operation. Note: All context should share a single
@ -634,128 +309,16 @@ void GHOST_ContextCGL::metalFree()
void GHOST_ContextCGL::metalInitFramebuffer()
{
if (!m_useMetalForRendering) {
#ifdef WITH_OPENGL_BACKEND
glGenFramebuffers(1, &m_defaultFramebuffer);
#endif
}
updateDrawingContext();
if (!m_useMetalForRendering) {
#ifdef WITH_OPENGL_BACKEND
glBindFramebuffer(GL_FRAMEBUFFER, m_defaultFramebuffer);
#endif
}
}
void GHOST_ContextCGL::metalUpdateFramebuffer()
{
if (!m_useMetalForRendering) {
#ifdef WITH_OPENGL_BACKEND
assert(m_defaultFramebuffer != 0);
#endif
}
NSRect bounds = [m_metalView bounds];
NSSize backingSize = [m_metalView convertSizeToBacking:bounds.size];
size_t width = (size_t)backingSize.width;
size_t height = (size_t)backingSize.height;
#ifdef WITH_OPENGL_BACKEND
unsigned int glTex;
CVPixelBufferRef cvPixelBuffer = nil;
CVOpenGLTextureCacheRef cvGLTexCache = nil;
CVOpenGLTextureRef cvGLTex = nil;
CVMetalTextureCacheRef cvMetalTexCache = nil;
CVMetalTextureRef cvMetalTex = nil;
#endif
if (!m_useMetalForRendering) {
#ifdef WITH_OPENGL_BACKEND
/* OPENGL path */
{
/* Test if there is anything to update */
id<MTLTexture> tex = m_defaultFramebufferMetalTexture[current_swapchain_index].texture;
if (tex && tex.width == width && tex.height == height) {
return;
}
}
activateDrawingContext();
NSDictionary *cvPixelBufferProps = @{
(__bridge NSString *)kCVPixelBufferOpenGLCompatibilityKey : @YES,
(__bridge NSString *)kCVPixelBufferMetalCompatibilityKey : @YES,
};
CVReturn cvret = CVPixelBufferCreate(kCFAllocatorDefault,
width,
height,
METAL_CORE_VIDEO_PIXEL_FORMAT,
(__bridge CFDictionaryRef)cvPixelBufferProps,
&cvPixelBuffer);
if (cvret != kCVReturnSuccess) {
ghost_fatal_error_dialog(
"GHOST_ContextCGL::metalUpdateFramebuffer: CVPixelBufferCreate failed!");
}
/* Create an OpenGL texture. */
cvret = CVOpenGLTextureCacheCreate(kCFAllocatorDefault,
nil,
m_openGLContext.CGLContextObj,
m_openGLContext.pixelFormat.CGLPixelFormatObj,
nil,
&cvGLTexCache);
if (cvret != kCVReturnSuccess) {
ghost_fatal_error_dialog(
"GHOST_ContextCGL::metalUpdateFramebuffer: CVOpenGLTextureCacheCreate failed!");
}
cvret = CVOpenGLTextureCacheCreateTextureFromImage(
kCFAllocatorDefault, cvGLTexCache, cvPixelBuffer, nil, &cvGLTex);
if (cvret != kCVReturnSuccess) {
ghost_fatal_error_dialog(
"GHOST_ContextCGL::metalUpdateFramebuffer: "
"CVOpenGLTextureCacheCreateTextureFromImage failed!");
}
glTex = CVOpenGLTextureGetName(cvGLTex);
/* Create a Metal texture. */
cvret = CVMetalTextureCacheCreate(
kCFAllocatorDefault, nil, m_metalLayer.device, nil, &cvMetalTexCache);
if (cvret != kCVReturnSuccess) {
ghost_fatal_error_dialog(
"GHOST_ContextCGL::metalUpdateFramebuffer: CVMetalTextureCacheCreate failed!");
}
cvret = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
cvMetalTexCache,
cvPixelBuffer,
nil,
METAL_FRAMEBUFFERPIXEL_FORMAT,
width,
height,
0,
&cvMetalTex);
if (cvret != kCVReturnSuccess) {
ghost_fatal_error_dialog(
"GHOST_ContextCGL::metalUpdateFramebuffer: "
"CVMetalTextureCacheCreateTextureFromImage failed!");
}
id<MTLTexture> tex = CVMetalTextureGetTexture(cvMetalTex);
if (!tex) {
ghost_fatal_error_dialog(
"GHOST_ContextCGL::metalUpdateFramebuffer: CVMetalTextureGetTexture failed!");
}
[m_defaultFramebufferMetalTexture[current_swapchain_index].texture release];
m_defaultFramebufferMetalTexture[current_swapchain_index].texture = [tex retain];
#endif
}
else {
/* NOTE(Metal): Metal API Path. */
if (m_defaultFramebufferMetalTexture[current_swapchain_index].texture &&
m_defaultFramebufferMetalTexture[current_swapchain_index].texture.width == width &&
m_defaultFramebufferMetalTexture[current_swapchain_index].texture.height == height)
@ -806,41 +369,15 @@ void GHOST_ContextCGL::metalUpdateFramebuffer()
[enc endEncoding];
}
[cmdBuffer commit];
}
if (!m_useMetalForRendering) {
#ifdef WITH_OPENGL_BACKEND
glBindFramebuffer(GL_FRAMEBUFFER, m_defaultFramebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, glTex, 0);
#endif
}
[m_metalLayer setDrawableSize:CGSizeMake((CGFloat)width, (CGFloat)height)];
if (!m_useMetalForRendering) {
#ifdef WITH_OPENGL_BACKEND
CVPixelBufferRelease(cvPixelBuffer);
CVOpenGLTextureCacheRelease(cvGLTexCache);
CVOpenGLTextureRelease(cvGLTex);
CFRelease(cvMetalTexCache);
CFRelease(cvMetalTex);
#endif
}
}
void GHOST_ContextCGL::metalSwapBuffers()
{
/* clang-format off */
@autoreleasepool {
/* clang-format on */
updateDrawingContext();
if (!m_useMetalForRendering) {
#ifdef WITH_OPENGL_BACKEND
glFlush();
assert(m_defaultFramebufferMetalTexture[current_swapchain_index].texture != nil);
#endif
}
id<CAMetalDrawable> drawable = [m_metalLayer nextDrawable];
if (!drawable) {
return;
@ -855,25 +392,6 @@ void GHOST_ContextCGL::metalSwapBuffers()
attachment.storeAction = MTLStoreActionStore;
}
if (!m_useMetalForRendering) {
id<MTLCommandBuffer> cmdBuffer = [s_sharedMetalCommandQueue commandBuffer];
{
assert(m_defaultFramebufferMetalTexture[current_swapchain_index].texture != nil);
id<MTLRenderCommandEncoder> enc = [cmdBuffer
renderCommandEncoderWithDescriptor:passDescriptor];
[enc setRenderPipelineState:(id<MTLRenderPipelineState>)m_metalRenderPipeline];
[enc setFragmentTexture:m_defaultFramebufferMetalTexture[current_swapchain_index].texture
atIndex:0];
[enc drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3];
[enc endEncoding];
}
[cmdBuffer presentDrawable:drawable];
/* Submit command buffer */
[cmdBuffer commit];
}
else {
assert(contextPresentCallback);
assert(m_defaultFramebufferMetalTexture[current_swapchain_index].texture != nil);
(*contextPresentCallback)(passDescriptor,
@ -882,16 +400,3 @@ void GHOST_ContextCGL::metalSwapBuffers()
drawable);
}
}
}
void GHOST_ContextCGL::initClear()
{
if (!m_useMetalForRendering) {
#ifdef WITH_OPENGL_BACKEND
glClearColor(0.294, 0.294, 0.294, 0.000);
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.000, 0.000, 0.000, 0.000);
#endif
}
}

@ -23,7 +23,7 @@
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
#if defined(WITH_OPENGL_BACKEND) || defined(WITH_METAL_BACKEND)
#ifdef WITH_METAL_BACKEND
# include "GHOST_ContextCGL.hh"
#endif
@ -763,10 +763,11 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const char *title,
*/
GHOST_IContext *GHOST_SystemCocoa::createOffscreenContext(GHOST_GPUSettings gpuSettings)
{
const bool debug_context = (gpuSettings.flags & GHOST_gpuDebugContext) != 0;
switch (gpuSettings.context_type) {
#ifdef WITH_VULKAN_BACKEND
case GHOST_kDrawingContextTypeVulkan: {
const bool debug_context = (gpuSettings.flags & GHOST_gpuDebugContext) != 0;
GHOST_Context *context = new GHOST_ContextVK(false, NULL, 1, 2, debug_context);
if (context->initializeDrawingContext()) {
return context;
@ -775,17 +776,11 @@ GHOST_IContext *GHOST_SystemCocoa::createOffscreenContext(GHOST_GPUSettings gpuS
return nullptr;
}
#endif
#ifdef WITH_OPENGL_BACKEND
case GHOST_kDrawingContextTypeOpenGL:
#endif
#ifdef WITH_METAL_BACKEND
case GHOST_kDrawingContextTypeMetal:
#endif
#if defined(WITH_OPENGL_BACKEND) || defined(WITH_METAL_BACKEND)
{
case GHOST_kDrawingContextTypeMetal: {
/* TODO(fclem): Remove OpenGL support and rename context to ContextMTL */
GHOST_Context *context = new GHOST_ContextCGL(
false, NULL, NULL, NULL, gpuSettings.context_type);
GHOST_Context *context = new GHOST_ContextCGL(false, NULL, NULL, debug_context);
if (context->initializeDrawingContext()) {
return context;
}

@ -13,7 +13,9 @@
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
#ifdef WITH_METAL_BACKEND
# include "GHOST_ContextCGL.hh"
#endif
#ifdef WITH_VULKAN_BACKEND
# include "GHOST_ContextVK.hh"
@ -816,37 +818,34 @@ GHOST_TSuccess GHOST_WindowCocoa::setOrder(GHOST_TWindowOrder order)
GHOST_Context *GHOST_WindowCocoa::newDrawingContext(GHOST_TDrawingContextType type)
{
switch (type) {
#ifdef WITH_VULKAN_BACKEND
if (type == GHOST_kDrawingContextTypeVulkan) {
case GHOST_kDrawingContextTypeVulkan: {
GHOST_Context *context = new GHOST_ContextVK(m_wantStereoVisual, m_metalLayer, 1, 2, true);
if (!context->initializeDrawingContext()) {
delete context;
return NULL;
}
if (context->initializeDrawingContext()) {
return context;
}
delete context;
return nullptr;
}
#endif
if (true
#if defined(WITH_OPENGL_BACKEND)
|| type == GHOST_kDrawingContextTypeOpenGL
#elif defined(WITH_METAL_BACKEND)
|| type == GHOST_kDrawingContextTypeMetal
#endif
)
{
#ifdef WITH_METAL_BACKEND
case GHOST_kDrawingContextTypeMetal: {
GHOST_Context *context = new GHOST_ContextCGL(
m_wantStereoVisual, m_metalView, m_metalLayer, m_openGLView, type);
if (context->initializeDrawingContext())
m_wantStereoVisual, m_metalView, m_metalLayer, false);
if (context->initializeDrawingContext()) {
return context;
else
delete context;
}
delete context;
return nullptr;
}
#endif
return NULL;
default:
/* Unsupported backend. */
return nullptr;
}
}
#pragma mark invalidate

@ -611,27 +611,6 @@ class USERPREF_PT_system_cycles_devices(SystemPanel, CenterAlignMixIn, Panel):
del addon
class USERPREF_PT_system_gpu_backend(SystemPanel, CenterAlignMixIn, Panel):
bl_label = "GPU Backend"
@classmethod
def poll(cls, _context):
# Only for Apple so far
import sys
return sys.platform == "darwin"
def draw_centered(self, context, layout):
import gpu
prefs = context.preferences
system = prefs.system
col = layout.column()
col.prop(system, "gpu_backend")
if system.gpu_backend != gpu.platform.backend_type_get():
layout.label(text="Requires a restart of Blender to take effect", icon='INFO')
class USERPREF_PT_system_os_settings(SystemPanel, CenterAlignMixIn, Panel):
bl_label = "Operating System Settings"
@ -2525,7 +2504,6 @@ classes = (
USERPREF_PT_animation_fcurves,
USERPREF_PT_system_cycles_devices,
USERPREF_PT_system_gpu_backend,
USERPREF_PT_system_os_settings,
USERPREF_PT_system_memory,
USERPREF_PT_system_video_sequencer,

@ -845,6 +845,13 @@ void blo_do_versions_userdef(UserDef *userdef)
*/
{
/* Keep this block, even when empty. */
#ifdef __APPLE__
/* Drop OpenGL support on MAC devices as they don't support OpenGL 4.3. */
if (userdef->gpu_backend == GPU_BACKEND_OPENGL) {
userdef->gpu_backend = GPU_BACKEND_METAL;
}
#endif
}
LISTBASE_FOREACH (bTheme *, btheme, &userdef->themes) {

@ -219,9 +219,6 @@ void GPU_render_step()
/** \name Backend selection
* \{ */
/* NOTE: To enable Metal API, we need to temporarily change this to `GPU_BACKEND_METAL`.
* Until a global switch is added, Metal also needs to be enabled in GHOST_ContextCGL:
* `m_useMetalForRendering = true`. */
static eGPUBackendType g_backend_type = GPU_BACKEND_OPENGL;
static std::optional<eGPUBackendType> g_backend_type_override = std::nullopt;
static std::optional<bool> g_backend_type_supported = std::nullopt;
@ -255,13 +252,11 @@ bool GPU_backend_type_selection_detect()
backends_to_check.append(*g_backend_type_override);
}
else {
#if defined(WITH_OPENGL_BACKEND)
backends_to_check.append(GPU_BACKEND_OPENGL);
}
/* Add fallback to OpenGL when Metal backend is requested on a platform that doesn't support
* metal. */
if (backends_to_check[0] == GPU_BACKEND_METAL) {
backends_to_check.append(GPU_BACKEND_OPENGL);
#elif defined(WITH_METAL_BACKEND)
backends_to_check.append(GPU_BACKEND_METAL);
#endif
}
for (const eGPUBackendType backend_type : backends_to_check) {