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:
@@ -136,6 +136,8 @@ private:
|
|||||||
|
|
||||||
//static CGLEWContext *s_cglewContext;
|
//static CGLEWContext *s_cglewContext;
|
||||||
|
|
||||||
|
const bool m_debug;
|
||||||
|
|
||||||
/** The first created OpenGL context (for sharing display lists) */
|
/** The first created OpenGL context (for sharing display lists) */
|
||||||
static NSOpenGLContext *s_sharedOpenGLContext;
|
static NSOpenGLContext *s_sharedOpenGLContext;
|
||||||
static int s_sharedCount;
|
static int s_sharedCount;
|
||||||
|
@@ -59,7 +59,8 @@ GHOST_ContextCGL::GHOST_ContextCGL(
|
|||||||
int contextResetNotificationStrategy)
|
int contextResetNotificationStrategy)
|
||||||
: GHOST_Context(stereoVisual, numOfAASamples),
|
: GHOST_Context(stereoVisual, numOfAASamples),
|
||||||
m_openGLView(openGLView),
|
m_openGLView(openGLView),
|
||||||
m_openGLContext(nil)
|
m_openGLContext(nil),
|
||||||
|
m_debug(contextFlags)
|
||||||
{
|
{
|
||||||
assert(openGLView != nil);
|
assert(openGLView != nil);
|
||||||
}
|
}
|
||||||
@@ -172,20 +173,21 @@ static void makeAttribList(
|
|||||||
bool stereoVisual,
|
bool stereoVisual,
|
||||||
int numOfAASamples,
|
int numOfAASamples,
|
||||||
bool needAlpha,
|
bool needAlpha,
|
||||||
bool needStencil)
|
bool needStencil,
|
||||||
|
bool softwareGL)
|
||||||
{
|
{
|
||||||
|
attribs.clear();
|
||||||
|
|
||||||
// Pixel Format Attributes for the windowed NSOpenGLContext
|
// Pixel Format Attributes for the windowed NSOpenGLContext
|
||||||
attribs.push_back(NSOpenGLPFADoubleBuffer);
|
attribs.push_back(NSOpenGLPFADoubleBuffer);
|
||||||
|
|
||||||
// Force software OpenGL, for debugging
|
if (softwareGL) {
|
||||||
/* 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")) {
|
|
||||||
attribs.push_back(NSOpenGLPFARendererID);
|
attribs.push_back(NSOpenGLPFARendererID);
|
||||||
attribs.push_back(kCGLRendererGenericFloatID);
|
attribs.push_back(kCGLRendererGenericFloatID);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
attribs.push_back(NSOpenGLPFAAccelerated);
|
attribs.push_back(NSOpenGLPFAAccelerated);
|
||||||
|
attribs.push_back(NSOpenGLPFANoRecovery);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Removed to allow 10.4 builds, and 2 GPUs rendering is not used anyway */
|
/* 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(NSOpenGLPFASamples);
|
||||||
attribs.push_back((NSOpenGLPixelFormatAttribute) numOfAASamples);
|
attribs.push_back((NSOpenGLPixelFormatAttribute) numOfAASamples);
|
||||||
|
|
||||||
attribs.push_back(NSOpenGLPFANoRecovery);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
attribs.push_back((NSOpenGLPixelFormatAttribute) 0);
|
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()
|
GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
|
||||||
{
|
{
|
||||||
@@ -248,9 +258,12 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
|
|||||||
static const bool needStencil = false;
|
static const bool needStencil = false;
|
||||||
#endif
|
#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;
|
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]];
|
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?)
|
// (Now that I think about it, does WGL really require the code that it has for finding a lesser match?)
|
||||||
|
|
||||||
attribs.clear();
|
attribs.clear();
|
||||||
makeAttribList(attribs, m_stereoVisual, 0, needAlpha, needStencil);
|
makeAttribList(attribs, m_stereoVisual, 0, needAlpha, needStencil, softwareGL);
|
||||||
pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attribs[0]];
|
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)
|
getVersion(&major, &minor);
|
||||||
goto error;
|
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)
|
if (major < 2 || (major == 2 && minor < 1)) {
|
||||||
s_sharedOpenGLContext = m_openGLContext;
|
// fall back to software renderer if GL < 2.1
|
||||||
|
fprintf(stderr, "OpenGL 2.1 is not supported on your hardware, falling back to software");
|
||||||
[pixelFormat release]; // -1 refCount to pixelFormat
|
softwareGL = true;
|
||||||
|
|
||||||
s_sharedCount++;
|
// 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
|
#ifdef GHOST_MULTITHREADED_OPENGL
|
||||||
//Switch openGL to multhreaded mode
|
//Switch openGL to multhreaded mode
|
||||||
CGLContextObj cglCtx = (CGLContextObj)[tmpOpenGLContext CGLContextObj];
|
CGLContextObj cglCtx = (CGLContextObj)[tmpOpenGLContext CGLContextObj];
|
||||||
if (CGLEnable(cglCtx, kCGLCEMPEngine) == kCGLNoError)
|
if (CGLEnable(cglCtx, kCGLCEMPEngine) == kCGLNoError)
|
||||||
printf("\nSwitched openGL to multithreaded mode\n");
|
if (m_debug)
|
||||||
|
fprintf(stderr, "\nSwitched OpenGL to multithreaded mode\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef GHOST_WAIT_FOR_VSYNC
|
#ifdef GHOST_WAIT_FOR_VSYNC
|
||||||
@@ -311,10 +346,16 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
initContextGLEW();
|
||||||
|
|
||||||
[m_openGLView setOpenGLContext:m_openGLContext];
|
[m_openGLView setOpenGLContext:m_openGLContext];
|
||||||
[m_openGLContext setView:m_openGLView];
|
[m_openGLContext setView:m_openGLView];
|
||||||
|
|
||||||
initContextGLEW();
|
if (s_sharedCount == 0)
|
||||||
|
s_sharedOpenGLContext = m_openGLContext;
|
||||||
|
|
||||||
|
s_sharedCount++;
|
||||||
|
|
||||||
|
|
||||||
initClearGL();
|
initClearGL();
|
||||||
[m_openGLContext flushBuffer];
|
[m_openGLContext flushBuffer];
|
||||||
|
@@ -562,7 +562,7 @@ GHOST_IWindow* GHOST_SystemCocoa::createWindow(
|
|||||||
// Add contentRect.origin.y to respect docksize
|
// Add contentRect.origin.y to respect docksize
|
||||||
bottom = bottom > contentRect.origin.y ? bottom + contentRect.origin.y : contentRect.origin.y;
|
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()) {
|
if (window->getValid()) {
|
||||||
// Store the pointer to the window
|
// Store the pointer to the window
|
||||||
|
@@ -74,7 +74,8 @@ public:
|
|||||||
GHOST_TWindowState state,
|
GHOST_TWindowState state,
|
||||||
GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone,
|
GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone,
|
||||||
const bool stereoVisual = false,
|
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_lionStyleFullScreen;
|
||||||
|
|
||||||
bool m_immediateDraw;
|
bool m_immediateDraw;
|
||||||
|
bool m_debug_context; // for debug messages during context setup
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __GHOST_WINDOWCOCOA_H__
|
#endif // __GHOST_WINDOWCOCOA_H__
|
||||||
|
@@ -528,10 +528,11 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(
|
|||||||
GHOST_TUns32 height,
|
GHOST_TUns32 height,
|
||||||
GHOST_TWindowState state,
|
GHOST_TWindowState state,
|
||||||
GHOST_TDrawingContextType type,
|
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),
|
GHOST_Window(width, height, state, stereoVisual, false, numOfAASamples),
|
||||||
m_customCursor(0)
|
m_customCursor(0),
|
||||||
|
m_debug_context(is_debug)
|
||||||
{
|
{
|
||||||
m_systemCocoa = systemCocoa;
|
m_systemCocoa = systemCocoa;
|
||||||
m_fullScreen = false;
|
m_fullScreen = false;
|
||||||
@@ -1115,7 +1116,7 @@ GHOST_Context *GHOST_WindowCocoa::newDrawingContext(GHOST_TDrawingContextType ty
|
|||||||
m_openGLView,
|
m_openGLView,
|
||||||
0, // profile bit
|
0, // profile bit
|
||||||
0, 0,
|
0, 0,
|
||||||
GHOST_OPENGL_CGL_CONTEXT_FLAGS,
|
m_debug_context,
|
||||||
GHOST_OPENGL_CGL_RESET_NOTIFICATION_STRATEGY);
|
GHOST_OPENGL_CGL_RESET_NOTIFICATION_STRATEGY);
|
||||||
#else
|
#else
|
||||||
# error
|
# error
|
||||||
|
Reference in New Issue
Block a user