1 /* xscreensaver, Copyright (c) 2006-2011 Jamie Zawinski <jwz@jwz.org>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
12 /* This is a subclass of Apple's ScreenSaverView that knows how to run
13 xscreensaver programs without X11 via the dark magic of the "jwxyz"
14 library. In xscreensaver terminology, this is the replacement for
15 the "screenhack.c" module.
18 #import "XScreenSaverGLView.h"
19 #import "XScreenSaverConfigSheet.h"
20 #import "screenhackI.h"
21 #import "xlockmoreI.h"
23 #import <OpenGL/OpenGL.h>
25 /* used by the OpenGL screen savers
27 extern GLXContext *init_GL (ModeInfo *);
28 extern void glXSwapBuffers (Display *, Window);
29 extern void glXMakeCurrent (Display *, Window, GLXContext);
30 extern void clear_gl_error (void);
31 extern void check_gl_error (const char *type);
34 @implementation XScreenSaverGLView
39 /* #### Do we have to destroy ogl_ctx? */
47 [super stopAnimation];
49 // Without this, the GL frame stays on screen when switching tabs
50 // in System Preferences.
52 [NSOpenGLContext clearCurrentContext];
56 // #### maybe this could/should just be on 'lockFocus' instead?
57 - (void) prepareContext
60 [ogl_ctx makeCurrentContext];
61 // check_gl_error ("makeCurrentContext");
67 - (void) resizeContext
70 [ogl_ctx setView:self];
74 - (void)drawRect:(NSRect)rect
77 [super drawRect:rect];
81 - (NSOpenGLContext *) oglContext
87 - (void) setOglContext: (NSOpenGLContext *) ctx
96 /* Utility functions...
100 /* Called by OpenGL savers using the XLockmore API.
103 init_GL (ModeInfo *mi)
105 Window win = mi->window;
106 XScreenSaverGLView *view = (XScreenSaverGLView *) jwxyz_window_view (win);
107 NSOpenGLContext *ctx = [view oglContext];
111 NSOpenGLPixelFormatAttribute attrs[40];
113 attrs[i++] = NSOpenGLPFAColorSize; attrs[i++] = 24;
114 attrs[i++] = NSOpenGLPFAAlphaSize; attrs[i++] = 8;
115 attrs[i++] = NSOpenGLPFADepthSize; attrs[i++] = 16;
117 if (get_boolean_resource (mi->dpy, "doubleBuffer", "DoubleBuffer"))
118 attrs[i++] = NSOpenGLPFADoubleBuffer;
120 Bool ms_p = get_boolean_resource (mi->dpy, "multiSample", "MultiSample");
122 /* Sometimes, turning on multisampling kills performance. At one point,
123 I thought the answer was, "only run multisampling on one screen, and
124 leave it turned off on other screens". That's what this code does,
125 but it turns out, that solution is insufficient. I can't really tell
126 what causes poor performance with multisampling, but it's not
127 predictable. Without changing the code, some times a given saver will
128 perform fine with multisampling on, and other times it will perform
129 very badly. Without multisampling, they always perform fine.
131 // if (ms_p && [[view window] screen] != [[NSScreen screens] objectAtIndex:0])
135 attrs[i++] = NSOpenGLPFASampleBuffers; attrs[i++] = 1;
136 attrs[i++] = NSOpenGLPFASamples; attrs[i++] = 6;
137 // Don't really understand what this means:
138 // attrs[i++] = NSOpenGLPFANoRecovery;
143 NSOpenGLPixelFormat *pixfmt =
144 [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
146 if (ms_p && !pixfmt) { // Retry without multisampling.
149 pixfmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
153 NSLog (@"unable to create NSOpenGLPixelFormat");
157 ctx = [[NSOpenGLContext alloc]
158 initWithFormat:pixfmt
160 // [pixfmt release]; // #### ???
163 // Sync refreshes to the vertical blanking interval
165 [ctx setValues:&r forParameter:NSOpenGLCPSwapInterval];
166 // check_gl_error ("NSOpenGLCPSwapInterval"); // SEGV sometimes. Too early?
168 // #### "Build and Analyze" says that ctx leaks, because it doesn't
169 // seem to realize that makeCurrentContext retains it (right?)
170 // Not sure what to do to make this warning go away.
172 [ctx makeCurrentContext];
173 check_gl_error ("makeCurrentContext");
175 [view setOglContext:ctx];
177 // Clear frame buffer ASAP, else there are bits left over from other apps.
178 glClearColor (0, 0, 0, 1);
179 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
181 // glXSwapBuffers (mi->dpy, mi->window);
184 // Enable multi-threading, if possible. This runs most OpenGL commands
185 // and GPU management on a second CPU.
187 # ifndef kCGLCEMPEngine
188 # define kCGLCEMPEngine 313 // Added in MacOS 10.4.8 + XCode 2.4.
190 CGLContextObj cctx = CGLGetCurrentContext();
191 CGLError err = CGLEnable (cctx, kCGLCEMPEngine);
192 if (err != kCGLNoError) {
193 NSLog (@"enabling multi-threaded OpenGL failed: %d", err);
197 check_gl_error ("init_GL");
199 // Caller expects a pointer to an opaque struct... which it dereferences.
200 // Don't ask me, it's historical...
201 static int blort = -1;
202 return (void *) &blort;
206 /* Copy the back buffer to the front buffer.
209 glXSwapBuffers (Display *dpy, Window window)
211 XScreenSaverGLView *view = (XScreenSaverGLView *) jwxyz_window_view (window);
212 NSOpenGLContext *ctx = [view oglContext];
213 if (ctx) [ctx flushBuffer]; // despite name, this actually swaps
216 /* Does nothing - prepareContext already did the work.
219 glXMakeCurrent (Display *dpy, Window window, GLXContext context)
224 /* clear away any lingering error codes */
226 clear_gl_error (void)
228 while (glGetError() != GL_NO_ERROR)
233 /* report a GL error. */
235 check_gl_error (const char *type)
240 switch ((i = glGetError())) {
241 case GL_NO_ERROR: return;
242 case GL_INVALID_ENUM: e = "invalid enum"; break;
243 case GL_INVALID_VALUE: e = "invalid value"; break;
244 case GL_INVALID_OPERATION: e = "invalid operation"; break;
245 case GL_STACK_OVERFLOW: e = "stack overflow"; break;
246 case GL_STACK_UNDERFLOW: e = "stack underflow"; break;
247 case GL_OUT_OF_MEMORY: e = "out of memory"; break;
248 #ifdef GL_TABLE_TOO_LARGE_EXT
249 case GL_TABLE_TOO_LARGE_EXT: e = "table too large"; break;
251 #ifdef GL_TEXTURE_TOO_LARGE_EXT
252 case GL_TEXTURE_TOO_LARGE_EXT: e = "texture too large"; break;
255 e = buf; sprintf (buf, "unknown GL error %d", (int) i); break;
257 NSLog (@"%s GL error: %s", type, e);