-/* xscreensaver, Copyright (c) 2006, 2007 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 2006-2011 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@implementation XScreenSaverGLView
+#if 0
- (void) dealloc
{
- if (agl_ctx)
- aglDestroyContext (agl_ctx);
+ /* #### Do we have to destroy ogl_ctx? */
[super dealloc];
}
+#endif
- (void)stopAnimation
// Without this, the GL frame stays on screen when switching tabs
// in System Preferences.
//
- if (agl_ctx) {
- aglSetCurrentContext (NULL);
- aglDestroyContext (agl_ctx);
- agl_ctx = 0;
- }
+ [NSOpenGLContext clearCurrentContext];
}
// #### maybe this could/should just be on 'lockFocus' instead?
- (void) prepareContext
{
- if (agl_ctx)
- if (!aglSetCurrentContext (agl_ctx)) {
- check_gl_error ("aglSetCurrentContext");
- abort();
- }
+ if (ogl_ctx) {
+ [ogl_ctx makeCurrentContext];
+// check_gl_error ("makeCurrentContext");
+ [ogl_ctx update];
+ }
}
-
+
+
- (void) resizeContext
{
- if (! agl_ctx)
- return;
-
- /* Constrain the AGL context to the rectangle of this view
- (not of our parent window).
- */
- GLint aglrect[4];
- NSRect rect = [[[self window] contentView] convertRect:[self frame]
- fromView:self];
- aglrect[0] = rect.origin.x;
- aglrect[1] = rect.origin.y;
- aglrect[2] = rect.size.width;
- aglrect[3] = rect.size.height;
- aglEnable (agl_ctx, AGL_BUFFER_RECT);
- aglSetInteger (agl_ctx, AGL_BUFFER_RECT, aglrect);
- aglUpdateContext (agl_ctx);
+ if (ogl_ctx)
+ [ogl_ctx setView:self];
}
- (void)drawRect:(NSRect)rect
{
- if (! agl_ctx)
+ if (! ogl_ctx)
[super drawRect:rect];
}
-- (AGLContext) aglContext
+- (NSOpenGLContext *) oglContext
{
- return agl_ctx;
+ return ogl_ctx;
}
-- (void) setAglContext: (AGLContext) ctx
+
+- (void) setOglContext: (NSOpenGLContext *) ctx
{
- if (agl_ctx)
- if (! aglDestroyContext (agl_ctx)) {
- check_gl_error("aglDestroyContext");
- abort();
- }
- agl_ctx = ctx;
+ ogl_ctx = ctx;
[self resizeContext];
}
@end
+
/* Utility functions...
*/
{
Window win = mi->window;
XScreenSaverGLView *view = (XScreenSaverGLView *) jwxyz_window_view (win);
-
- GLint agl_attrs[] = {
- AGL_RGBA,
- AGL_DOUBLEBUFFER,
- AGL_DEPTH_SIZE, 16,
- 0 };
- AGLPixelFormat aglpixf = aglChoosePixelFormat (NULL, 0, agl_attrs);
- AGLContext ctx = aglCreateContext (aglpixf, NULL);
- aglDestroyPixelFormat (aglpixf);
- if (! ctx) {
- check_gl_error("aglCreateContext");
- abort();
- }
-
- if (! aglSetDrawable (ctx, GetWindowPort ([[view window] windowRef]))) {
- check_gl_error("aglSetDrawable");
- abort();
- }
+ NSOpenGLContext *ctx = [view oglContext];
+
+ if (!ctx) {
+
+ NSOpenGLPixelFormatAttribute attrs[40];
+ int i = 0;
+ attrs[i++] = NSOpenGLPFAColorSize; attrs[i++] = 24;
+ attrs[i++] = NSOpenGLPFAAlphaSize; attrs[i++] = 8;
+ attrs[i++] = NSOpenGLPFADepthSize; attrs[i++] = 16;
+
+ if (get_boolean_resource (mi->dpy, "doubleBuffer", "DoubleBuffer"))
+ attrs[i++] = NSOpenGLPFADoubleBuffer;
+
+ Bool ms_p = get_boolean_resource (mi->dpy, "multiSample", "MultiSample");
+
+ /* Sometimes, turning on multisampling kills performance. At one point,
+ I thought the answer was, "only run multisampling on one screen, and
+ leave it turned off on other screens". That's what this code does,
+ but it turns out, that solution is insufficient. I can't really tell
+ what causes poor performance with multisampling, but it's not
+ predictable. Without changing the code, some times a given saver will
+ perform fine with multisampling on, and other times it will perform
+ very badly. Without multisampling, they always perform fine.
+ */
+// if (ms_p && [[view window] screen] != [[NSScreen screens] objectAtIndex:0])
+// ms_p = 0;
+
+ if (ms_p) {
+ attrs[i++] = NSOpenGLPFASampleBuffers; attrs[i++] = 1;
+ attrs[i++] = NSOpenGLPFASamples; attrs[i++] = 6;
+ // Don't really understand what this means:
+ // attrs[i++] = NSOpenGLPFANoRecovery;
+ }
- if (! aglSetCurrentContext (ctx)) {
- check_gl_error("aglSetCurrentContext");
- abort();
- }
+ attrs[i] = 0;
+
+ NSOpenGLPixelFormat *pixfmt =
+ [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
+
+ if (ms_p && !pixfmt) { // Retry without multisampling.
+ i -= 2;
+ attrs[i] = 0;
+ pixfmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
+ }
+
+ if (! pixfmt) {
+ NSLog (@"unable to create NSOpenGLPixelFormat");
+ exit (1);
+ }
- [view setAglContext:ctx];
+ ctx = [[NSOpenGLContext alloc]
+ initWithFormat:pixfmt
+ shareContext:nil];
+// [pixfmt release]; // #### ???
+ }
// Sync refreshes to the vertical blanking interval
GLint r = 1;
- aglSetInteger (ctx, AGL_SWAP_INTERVAL, &r);
+ [ctx setValues:&r forParameter:NSOpenGLCPSwapInterval];
+// check_gl_error ("NSOpenGLCPSwapInterval"); // SEGV sometimes. Too early?
+
+ // #### "Build and Analyze" says that ctx leaks, because it doesn't
+ // seem to realize that makeCurrentContext retains it (right?)
+ // Not sure what to do to make this warning go away.
+
+ [ctx makeCurrentContext];
+ check_gl_error ("makeCurrentContext");
+
+ [view setOglContext:ctx];
+
+ // Clear frame buffer ASAP, else there are bits left over from other apps.
+ glClearColor (0, 0, 0, 1);
+ glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+// glFinish ();
+// glXSwapBuffers (mi->dpy, mi->window);
+
// Enable multi-threading, if possible. This runs most OpenGL commands
// and GPU management on a second CPU.
}
}
+ check_gl_error ("init_GL");
+
// Caller expects a pointer to an opaque struct... which it dereferences.
// Don't ask me, it's historical...
static int blort = -1;
glXSwapBuffers (Display *dpy, Window window)
{
XScreenSaverGLView *view = (XScreenSaverGLView *) jwxyz_window_view (window);
- AGLContext ctx = [view aglContext];
- if (ctx) aglSwapBuffers (ctx);
+ NSOpenGLContext *ctx = [view oglContext];
+ if (ctx) [ctx flushBuffer]; // despite name, this actually swaps
}
-/* Does nothing.
+/* Does nothing - prepareContext already did the work.
*/
void
glXMakeCurrent (Display *dpy, Window window, GLXContext context)
{
while (glGetError() != GL_NO_ERROR)
;
- while (aglGetError() != AGL_NO_ERROR)
- ;
-}
-
-static void
-check_agl_error (const char *type)
-{
- char buf[100];
- GLenum i;
- const char *e;
- switch ((i = aglGetError())) {
- case AGL_NO_ERROR: return;
- case AGL_BAD_ATTRIBUTE: e = "bad attribute"; break;
- case AGL_BAD_PROPERTY: e = "bad propery"; break;
- case AGL_BAD_PIXELFMT: e = "bad pixelfmt"; break;
- case AGL_BAD_RENDINFO: e = "bad rendinfo"; break;
- case AGL_BAD_CONTEXT: e = "bad context"; break;
- case AGL_BAD_DRAWABLE: e = "bad drawable"; break;
- case AGL_BAD_GDEV: e = "bad gdev"; break;
- case AGL_BAD_STATE: e = "bad state"; break;
- case AGL_BAD_VALUE: e = "bad value"; break;
- case AGL_BAD_MATCH: e = "bad match"; break;
- case AGL_BAD_ENUM: e = "bad enum"; break;
- case AGL_BAD_OFFSCREEN: e = "bad offscreen"; break;
- case AGL_BAD_FULLSCREEN: e = "bad fullscreen";break;
- case AGL_BAD_WINDOW: e = "bad window"; break;
- case AGL_BAD_POINTER: e = "bad pointer"; break;
- case AGL_BAD_MODULE: e = "bad module"; break;
- case AGL_BAD_ALLOC: e = "bad alloc"; break;
- case AGL_BAD_CONNECTION: e = "bad connection";break;
- default:
- e = buf; sprintf (buf, "unknown AGL error %d", (int) i); break;
- }
- NSLog (@"%s AGL error: %s", type, e);
- exit (1);
}
void
check_gl_error (const char *type)
{
- check_agl_error (type);
-
char buf[100];
GLenum i;
const char *e;