OpenGL: software renderer for old Mac GPUs

We raised the minimum to GL 2.1 in Blender 2.77, and dropped support for older GPUs (pre-2012 Intel mostly). On Windows you get a popup message, but on Mac we simply crashed. Every Mac has a builtin software renderer for GL 2.1 so let's use that when the GPU is not capable!

Run blender --debug-gpu to see version detection & software fallback.
This commit is contained in:
Mike Erwin 2016-09-19 20:26:55 +02:00
parent 16ed49b26e
commit e12f5b699d
5 changed files with 74 additions and 28 deletions

View File

@ -136,6 +136,8 @@ private:
//static CGLEWContext *s_cglewContext;
const bool m_debug;
/** The first created OpenGL context (for sharing display lists) */
static NSOpenGLContext *s_sharedOpenGLContext;
static int s_sharedCount;

View File

@ -59,7 +59,8 @@ GHOST_ContextCGL::GHOST_ContextCGL(
int contextResetNotificationStrategy)
: GHOST_Context(stereoVisual, numOfAASamples),
m_openGLView(openGLView),
m_openGLContext(nil)
m_openGLContext(nil),
m_debug(contextFlags)
{
assert(openGLView != nil);
}
@ -172,20 +173,21 @@ static void makeAttribList(
bool stereoVisual,
int numOfAASamples,
bool needAlpha,
bool needStencil)
bool needStencil,
bool softwareGL)
{
attribs.clear();
// Pixel Format Attributes for the windowed NSOpenGLContext
attribs.push_back(NSOpenGLPFADoubleBuffer);
// Force software OpenGL, for debugging
/* XXX jwilkins: fixed this to work on Intel macs? useful feature for Windows and Linux too?
* Maybe a command line flag is better... */
if (getenv("BLENDER_SOFTWAREGL")) {
if (softwareGL) {
attribs.push_back(NSOpenGLPFARendererID);
attribs.push_back(kCGLRendererGenericFloatID);
}
else {
attribs.push_back(NSOpenGLPFAAccelerated);
attribs.push_back(NSOpenGLPFANoRecovery);
}
/* Removed to allow 10.4 builds, and 2 GPUs rendering is not used anyway */
@ -219,13 +221,21 @@ static void makeAttribList(
attribs.push_back(NSOpenGLPFASamples);
attribs.push_back((NSOpenGLPixelFormatAttribute) numOfAASamples);
attribs.push_back(NSOpenGLPFANoRecovery);
}
attribs.push_back((NSOpenGLPixelFormatAttribute) 0);
}
// TODO(merwin): make this available to all platforms
static void getVersion(int *major, int *minor)
{
#if 1 // legacy GL
sscanf((const char*)glGetString(GL_VERSION), "%d.%d", major, minor);
#else // 3.0+
glGetIntegerv(GL_MAJOR_VERSION, major);
glGetIntegerv(GL_MINOR_VERSION, minor);
#endif
}
GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
{
@ -248,9 +258,12 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
static const bool needStencil = false;
#endif
makeAttribList(attribs, m_stereoVisual, m_numOfAASamples, needAlpha, needStencil);
static bool softwareGL = getenv("BLENDER_SOFTWAREGL"); // command-line argument would be better
GLint major = 0, minor = 0;
NSOpenGLPixelFormat *pixelFormat;
// TODO: keep pixel format for subsequent windows/contexts instead of recreating each time
makeAttribList(attribs, m_stereoVisual, m_numOfAASamples, needAlpha, needStencil, softwareGL);
pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attribs[0]];
@ -261,7 +274,7 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
// (Now that I think about it, does WGL really require the code that it has for finding a lesser match?)
attribs.clear();
makeAttribList(attribs, m_stereoVisual, 0, needAlpha, needStencil);
makeAttribList(attribs, m_stereoVisual, 0, needAlpha, needStencil, softwareGL);
pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attribs[0]];
}
@ -282,25 +295,47 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
}
}
[m_openGLView setPixelFormat:pixelFormat];
m_openGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:s_sharedOpenGLContext];
[pixelFormat release];
m_openGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:s_sharedOpenGLContext]; // +1 refCount to pixelFormat
[m_openGLContext makeCurrentContext];
if (m_openGLContext == nil)
goto error;
getVersion(&major, &minor);
if (m_debug) {
fprintf(stderr, "OpenGL version %d.%d%s\n", major, minor, softwareGL ? " (software)" : "");
fprintf(stderr, "Renderer: %s\n", glGetString(GL_RENDERER));
}
if (s_sharedCount == 0)
s_sharedOpenGLContext = m_openGLContext;
[pixelFormat release]; // -1 refCount to pixelFormat
s_sharedCount++;
if (major < 2 || (major == 2 && minor < 1)) {
// fall back to software renderer if GL < 2.1
fprintf(stderr, "OpenGL 2.1 is not supported on your hardware, falling back to software");
softwareGL = true;
// discard hardware GL context
[NSOpenGLContext clearCurrentContext];
[m_openGLContext release];
// create software GL context
makeAttribList(attribs, m_stereoVisual, m_numOfAASamples, needAlpha, needStencil, softwareGL);
pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attribs[0]];
m_openGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:s_sharedOpenGLContext];
[pixelFormat release];
[m_openGLContext makeCurrentContext];
getVersion(&major, &minor);
if (m_debug) {
fprintf(stderr, "OpenGL version %d.%d%s\n", major, minor, softwareGL ? " (software)" : "");
fprintf(stderr, "Renderer: %s\n", glGetString(GL_RENDERER));
}
}
#ifdef GHOST_MULTITHREADED_OPENGL
//Switch openGL to multhreaded mode
CGLContextObj cglCtx = (CGLContextObj)[tmpOpenGLContext CGLContextObj];
if (CGLEnable(cglCtx, kCGLCEMPEngine) == kCGLNoError)
printf("\nSwitched openGL to multithreaded mode\n");
if (m_debug)
fprintf(stderr, "\nSwitched OpenGL to multithreaded mode\n");
#endif
#ifdef GHOST_WAIT_FOR_VSYNC
@ -311,10 +346,16 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
}
#endif
initContextGLEW();
[m_openGLView setOpenGLContext:m_openGLContext];
[m_openGLContext setView:m_openGLView];
initContextGLEW();
if (s_sharedCount == 0)
s_sharedOpenGLContext = m_openGLContext;
s_sharedCount++;
initClearGL();
[m_openGLContext flushBuffer];

View File

@ -562,7 +562,7 @@ GHOST_IWindow* GHOST_SystemCocoa::createWindow(
// Add contentRect.origin.y to respect docksize
bottom = bottom > contentRect.origin.y ? bottom + contentRect.origin.y : contentRect.origin.y;
window = new GHOST_WindowCocoa (this, title, left, bottom, width, height, state, type, ((glSettings.flags & GHOST_glStereoVisual) != 0), glSettings.numOfAASamples);
window = new GHOST_WindowCocoa(this, title, left, bottom, width, height, state, type, glSettings.flags & GHOST_glStereoVisual, glSettings.numOfAASamples, glSettings.flags & GHOST_glDebugContext);
if (window->getValid()) {
// Store the pointer to the window

View File

@ -74,7 +74,8 @@ public:
GHOST_TWindowState state,
GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone,
const bool stereoVisual = false,
const GHOST_TUns16 numOfAASamples = 0
const GHOST_TUns16 numOfAASamples = 0,
bool is_debug = false
);
/**
@ -305,6 +306,7 @@ protected:
bool m_lionStyleFullScreen;
bool m_immediateDraw;
bool m_debug_context; // for debug messages during context setup
};
#endif // __GHOST_WINDOWCOCOA_H__

View File

@ -528,10 +528,11 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(
GHOST_TUns32 height,
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
const bool stereoVisual, const GHOST_TUns16 numOfAASamples
const bool stereoVisual, const GHOST_TUns16 numOfAASamples, bool is_debug
) :
GHOST_Window(width, height, state, stereoVisual, false, numOfAASamples),
m_customCursor(0)
m_customCursor(0),
m_debug_context(is_debug)
{
m_systemCocoa = systemCocoa;
m_fullScreen = false;
@ -1115,7 +1116,7 @@ GHOST_Context *GHOST_WindowCocoa::newDrawingContext(GHOST_TDrawingContextType ty
m_openGLView,
0, // profile bit
0, 0,
GHOST_OPENGL_CGL_CONTEXT_FLAGS,
m_debug_context,
GHOST_OPENGL_CGL_RESET_NOTIFICATION_STRATEGY);
#else
# error