2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
26 ===========================================================================
30 #import "../../idlib/precompiled.h"
32 #import "../../renderer/tr_local.h"
34 #import "macosx_glimp.h"
36 #import "macosx_local.h"
37 #import "macosx_sys.h"
38 #import "macosx_display.h"
40 #import <AppKit/AppKit.h>
41 #import <Foundation/Foundation.h>
43 #import <mach-o/dyld.h>
45 #import <mach/mach_error.h>
47 static idCVar r_minDisplayRefresh( "r_minDisplayRefresh", "0", CVAR_ARCHIVE | CVAR_INTEGER, "" );
48 static idCVar r_maxDisplayRefresh( "r_maxDisplayRefresh", "0", CVAR_ARCHIVE | CVAR_INTEGER, "" );
49 static idCVar r_screen( "r_screen", "-1", CVAR_ARCHIVE | CVAR_INTEGER, "which display to use" );
51 static void GLW_InitExtensions( void );
52 static bool CreateGameWindow( glimpParms_t parms );
53 static unsigned long Sys_QueryVideoMemory();
54 CGDisplayErr Sys_CaptureActiveDisplays(void);
57 static bool isHidden = false;
59 @interface NSOpenGLContext (CGLContextAccess)
60 - (CGLContextObj) cglContext;
63 @implementation NSOpenGLContext (CGLContextAccess)
64 - (CGLContextObj) cglContext;
66 return _contextAuxiliary;
75 void CheckErrors( void ) {
79 if ( err != GL_NO_ERROR ) {
80 common->Error( "glGetError: %s\n", qglGetString( err ) );
84 #if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS)
86 unsigned int QGLBeginStarted = 0;
88 void QGLErrorBreak(void) { }
90 void QGLCheckError( const char *message ) {
92 static unsigned int errorCount = 0;
94 error = _glGetError();
95 if (error != GL_NO_ERROR) {
96 if (errorCount == 100) {
97 common->Printf("100 GL errors printed ... disabling further error reporting.\n");
98 } else if (errorCount < 100) {
99 if (errorCount == 0) {
100 common->Warning("BREAK ON QGLErrorBreak to stop at the GL errors\n");
102 common->Warning("OpenGL Error(%s): 0x%04x -- %s\n", message, (int)error, gluErrorString(error));
114 bool GLimp_SetMode( glimpParms_t parms ) {
115 if ( !CreateGameWindow( parms ) ) {
116 common->Printf( "GLimp_SetMode: window could not be created!\n" );
120 glConfig.vidWidth = parms.width;
121 glConfig.vidHeight = parms.height;
122 glConfig.isFullscreen = parms.fullScreen;
124 // draw something to show that GL is alive
125 qglClearColor( 0.5, 0.5, 0.7, 0 );
126 qglClear( GL_COLOR_BUFFER_BIT );
129 qglClearColor( 0.5, 0.5, 0.7, 0 );
130 qglClear( GL_COLOR_BUFFER_BIT );
133 Sys_UnfadeScreen( Sys_DisplayToUse(), NULL );
146 #define ADD_ATTR(x) \
148 if (attributeIndex >= attributeSize) { \
149 attributeSize *= 2; \
150 pixelAttributes = (NSOpenGLPixelFormatAttribute *)NSZoneRealloc(NULL, pixelAttributes, sizeof(*pixelAttributes) * attributeSize); \
152 pixelAttributes[attributeIndex] = (NSOpenGLPixelFormatAttribute)x; \
155 common->Printf( "Adding pixel attribute: %d (%s)\n", x, #x); \
159 static NSOpenGLPixelFormatAttribute *GetPixelAttributes( unsigned int multisamples ) {
160 NSOpenGLPixelFormatAttribute *pixelAttributes;
161 unsigned int attributeIndex = 0;
162 unsigned int attributeSize = 128;
164 unsigned int colorDepth;
165 unsigned int desktopColorDepth;
166 unsigned int depthBits;
167 unsigned int stencilBits;
168 unsigned int buffers;
172 pixelAttributes = (NSOpenGLPixelFormatAttribute *)NSZoneMalloc(NULL, sizeof(*pixelAttributes) * attributeSize);
174 // only greater or equal attributes will be selected
175 ADD_ATTR( NSOpenGLPFAMinimumPolicy );
178 if ( cvarSystem->GetCVarBool( "r_fullscreen" ) ) {
179 ADD_ATTR(NSOpenGLPFAFullScreen);
182 ADD_ATTR(NSOpenGLPFAScreenMask);
183 ADD_ATTR(CGDisplayIDToOpenGLDisplayMask(Sys_DisplayToUse()));
185 // Require hardware acceleration
186 ADD_ATTR(NSOpenGLPFAAccelerated);
188 // Require double-buffer
189 ADD_ATTR(NSOpenGLPFADoubleBuffer);
192 ADD_ATTR(NSOpenGLPFAColorSize);
194 if ( !cvarSystem->GetCVarBool( "r_fullscreen" ) ) {
195 desktopColorDepth = [[glw_state.desktopMode objectForKey: (id)kCGDisplayBitsPerPixel] intValue];
196 if ( desktopColorDepth != 32 ) {
197 common->Warning( "Desktop display colors should be 32 bits for window rendering" );
200 ADD_ATTR(colorDepth);
202 // Specify the number of depth bits
203 ADD_ATTR( NSOpenGLPFADepthSize );
205 ADD_ATTR( depthBits );
207 // Specify the number of stencil bits
209 ADD_ATTR( NSOpenGLPFAStencilSize );
210 ADD_ATTR( stencilBits );
212 // Specify destination alpha
213 ADD_ATTR( NSOpenGLPFAAlphaSize );
216 if ( multisamples ) {
218 ADD_ATTR( NSOpenGLPFASampleBuffers );
220 ADD_ATTR( NSOpenGLPFASamples );
221 ADD_ATTR( multisamples );
224 // Terminate the list
227 return pixelAttributes;
230 void Sys_UpdateWindowMouseInputRect(void) {
231 NSRect windowRect, screenRect;
236 // TTimo - I guess glw_state.window is bogus .. getting crappy data out of this
238 // It appears we need to flip the coordinate system here. This means we need
239 // to know the size of the screen.
240 screen = [glw_state.window screen];
241 screenRect = [screen frame];
242 windowRect = [glw_state.window frame];
243 windowRect.origin.y = screenRect.size.height - (windowRect.origin.y + windowRect.size.height);
245 Sys_SetMouseInputRect( CGRectMake( windowRect.origin.x, windowRect.origin.y, windowRect.size.width, windowRect.size.height ) );
248 Sys_SetMouseInputRect( CGDisplayBounds( glw_state.display ) );
251 // This is needed since CGReleaseAllDisplays() restores the gamma on the displays and we want to fade it up rather than just flickering all the displays
252 static void ReleaseAllDisplays() {
253 CGDisplayCount displayIndex;
255 common->Printf("Releasing displays\n");
256 for (displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++) {
257 CGDisplayRelease(glw_state.originalDisplayGammaTables[displayIndex].display);
266 static bool CreateGameWindow( glimpParms_t parms ) {
267 const char *windowed[] = { "Windowed", "Fullscreen" };
268 NSOpenGLPixelFormatAttribute *pixelAttributes;
269 NSOpenGLPixelFormat *pixelFormat;
271 unsigned int multisamples;
272 const long swap_limit = false;
273 int nsOpenGLCPSwapLimit = 203;
275 glw_state.display = Sys_DisplayToUse();
276 glw_state.desktopMode = (NSDictionary *)CGDisplayCurrentMode( glw_state.display );
277 if ( !glw_state.desktopMode ) {
278 common->Error( "Could not get current graphics mode for display 0x%08x\n", glw_state.display );
281 common->Printf( " %d %d %s\n", parms.width, parms.height, windowed[ parms.fullScreen ] );
283 if (parms.fullScreen) {
285 // We'll set up the screen resolution first in case that effects the list of pixel
286 // formats that are available (for example, a smaller frame buffer might mean more
287 // bits for depth/stencil buffers). Allow stretched video modes if we are in fallback mode.
288 glw_state.gameMode = Sys_GetMatchingDisplayMode(parms);
289 if (!glw_state.gameMode) {
290 common->Printf( "Unable to find requested display mode.\n");
294 // Fade all screens to black
295 // Sys_FadeScreens();
297 err = Sys_CaptureActiveDisplays();
298 if ( err != CGDisplayNoErr ) {
299 CGDisplayRestoreColorSyncSettings();
300 common->Printf( " Unable to capture displays err = %d\n", err );
304 err = CGDisplaySwitchToMode(glw_state.display, (CFDictionaryRef)glw_state.gameMode);
305 if ( err != CGDisplayNoErr ) {
306 CGDisplayRestoreColorSyncSettings();
307 ReleaseAllDisplays();
308 common->Printf( " Unable to set display mode, err = %d\n", err );
312 glw_state.gameMode = glw_state.desktopMode;
315 // Get the GL pixel format
317 multisamples = cvarSystem->GetCVarInteger( "r_multiSamples" );
318 while ( !pixelFormat ) {
319 pixelAttributes = GetPixelAttributes( multisamples );
320 pixelFormat = [[[NSOpenGLPixelFormat alloc] initWithAttributes: pixelAttributes] autorelease];
321 NSZoneFree(NULL, pixelAttributes);
322 if ( pixelFormat || multisamples == 0 )
326 cvarSystem->SetCVarInteger( "r_multiSamples", multisamples );
329 CGDisplayRestoreColorSyncSettings();
330 CGDisplaySwitchToMode(glw_state.display, (CFDictionaryRef)glw_state.desktopMode);
331 ReleaseAllDisplays();
332 common->Printf( " No pixel format found\n");
336 // Create a context with the desired pixel attributes
337 OSX_SetGLContext([[NSOpenGLContext alloc] initWithFormat: pixelFormat shareContext: nil]);
338 if ( !OSX_GetNSGLContext() ) {
339 CGDisplayRestoreColorSyncSettings();
340 CGDisplaySwitchToMode(glw_state.display, (CFDictionaryRef)glw_state.desktopMode);
341 ReleaseAllDisplays();
342 common->Printf( "... +[NSOpenGLContext createWithFormat:share:] failed.\n" );
346 long system_version = 0;
347 Gestalt( gestaltSystemVersion, &system_version );
348 if ( parms.width <= 1024 && parms.height <= 768 && system_version <= 0x1045 ) {
349 [ OSX_GetNSGLContext() setValues: &swap_limit forParameter: (NSOpenGLContextParameter)nsOpenGLCPSwapLimit ];
353 if ( !parms.fullScreen ) {
359 displayIndex = r_screen.GetInteger();
360 displayCount = [[NSScreen screens] count];
361 if ( displayIndex < 0 || displayIndex >= displayCount ) {
362 screen = [NSScreen mainScreen];
364 screen = [[NSScreen screens] objectAtIndex:displayIndex];
367 NSRect r = [screen frame];
368 windowRect.origin.x = ((short)r.size.width - parms.width) / 2;
369 windowRect.origin.y = ((short)r.size.height - parms.height) / 2;
370 windowRect.size.width = parms.width;
371 windowRect.size.height = parms.height;
373 glw_state.window = [NSWindow alloc];
374 [glw_state.window initWithContentRect:windowRect styleMask:NSTitledWindowMask backing:NSBackingStoreRetained defer:NO screen:screen];
376 [glw_state.window setTitle: @GAME_NAME];
378 [glw_state.window orderFront: nil];
380 // Always get mouse moved events (if mouse support is turned off (rare)
381 // the event system will filter them out.
382 [glw_state.window setAcceptsMouseMovedEvents: YES];
384 // Direct the context to draw in this window
385 [OSX_GetNSGLContext() setView: [glw_state.window contentView]];
387 // Sync input rect with where the window actually is...
388 Sys_UpdateWindowMouseInputRect();
392 glw_state.window = NULL;
394 err = CGLSetFullScreen(OSX_GetCGLContext());
396 CGDisplayRestoreColorSyncSettings();
397 CGDisplaySwitchToMode(glw_state.display, (CFDictionaryRef)glw_state.desktopMode);
398 ReleaseAllDisplays();
399 common->Printf("CGLSetFullScreen -> %d (%s)\n", err, CGLErrorString(err));
403 Sys_SetMouseInputRect( CGDisplayBounds( glw_state.display ) );
406 #ifndef USE_CGLMACROS
407 // Make this the current context
408 OSX_GLContextSetCurrent();
411 // Store off the pixel format attributes that we actually got
412 [pixelFormat getValues: (long *) &glConfig.colorBits forAttribute: NSOpenGLPFAColorSize forVirtualScreen: 0];
413 [pixelFormat getValues: (long *) &glConfig.depthBits forAttribute: NSOpenGLPFADepthSize forVirtualScreen: 0];
414 [pixelFormat getValues: (long *) &glConfig.stencilBits forAttribute: NSOpenGLPFAStencilSize forVirtualScreen: 0];
416 glConfig.displayFrequency = [[glw_state.gameMode objectForKey: (id)kCGDisplayRefreshRate] intValue];
418 common->Printf( "ok\n" );
423 // This can be used to temporarily disassociate the GL context from the screen so that CoreGraphics can be used to draw to the screen.
424 void Sys_PauseGL () {
425 if (!glw_state.glPauseCount) {
426 qglFinish (); // must do this to ensure the queue is complete
428 // Have to call both to actually deallocate kernel resources and free the NSSurface
429 CGLClearDrawable(OSX_GetCGLContext());
430 [OSX_GetNSGLContext() clearDrawable];
432 glw_state.glPauseCount++;
435 // This can be used to reverse the pausing caused by Sys_PauseGL()
436 void Sys_ResumeGL () {
437 if (glw_state.glPauseCount) {
438 glw_state.glPauseCount--;
439 if (!glw_state.glPauseCount) {
440 if (!glConfig.isFullscreen) {
441 [OSX_GetNSGLContext() setView: [glw_state.window contentView]];
445 err = CGLSetFullScreen(OSX_GetCGLContext());
447 common->Printf("CGLSetFullScreen -> %d (%s)\n", err, CGLErrorString(err));
457 Don't return unless OpenGL has been properly initialized
462 static void GLImp_Dump_Stamp_List_f(void) {
463 OTStampListDumpToFile(glThreadStampList, "/tmp/gl_stamps");
467 bool GLimp_Init( glimpParms_t parms ) {
470 common->Printf( "Initializing OpenGL subsystem\n" );
471 common->Printf( " fullscreen: %s\n", cvarSystem->GetCVarBool( "r_fullscreen" ) ? "yes" : "no" );
473 Sys_StoreGammaTables();
475 if ( !Sys_QueryVideoMemory() ) {
476 common->Error( "Could not initialize OpenGL. There does not appear to be an OpenGL-supported video card in your system.\n" );
479 if ( !GLimp_SetMode( parms ) ) {
480 common->Warning( "Could not initialize OpenGL\n" );
484 common->Printf( "------------------\n" );
486 // get our config strings
487 glConfig.vendor_string = (const char *)qglGetString( GL_VENDOR );
488 glConfig.renderer_string = (const char *)qglGetString( GL_RENDERER );
489 glConfig.version_string = (const char *)qglGetString( GL_VERSION );
490 glConfig.extensions_string = (const char *)qglGetString( GL_EXTENSIONS );
493 // chipset specific configuration
495 buf = (char *)malloc(strlen(glConfig.renderer_string) + 1);
496 strcpy( buf, glConfig.renderer_string );
498 // Cvar_Set( "r_lastValidRenderer", glConfig.renderer_string );
501 GLW_InitExtensions();
504 #ifndef USE_CGLMACROS
505 if (!r_enablerender->integer)
506 OSX_GLContextClearCurrent();
516 ** Responsible for doing a swapbuffers and possibly for other stuff
517 ** as yet to be determined. Probably better not to make this a GLimp
518 ** function and instead do a call to GLimp_SwapBuffers.
520 void GLimp_SwapBuffers( void ) {
521 if ( r_swapInterval.IsModified() ) {
522 r_swapInterval.ClearModified();
525 #if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS)
526 QGLCheckError("GLimp_EndFrame");
529 if (!glw_state.glPauseCount && !isHidden) {
530 glw_state.bufferSwapCount++;
531 [OSX_GetNSGLContext() flushBuffer];
535 // Enable turning off GL at any point for performance testing
536 if (OSX_GLContextIsCurrent() != r_enablerender->integer) {
537 if (r_enablerender->integer) {
538 common->Printf("--- Enabling Renderer ---\n");
539 OSX_GLContextSetCurrent();
541 common->Printf("--- Disabling Renderer ---\n");
542 OSX_GLContextClearCurrent();
551 ** This routine does all OS specific shutdown procedures for the OpenGL
552 ** subsystem. Under OpenGL this means NULLing out the current DC and
553 ** HGLRC, deleting the rendering context, and releasing the DC acquired
554 ** for the window. The state structure is also nulled out.
558 static void _GLimp_RestoreOriginalVideoSettings() {
561 // CGDisplayCurrentMode lies because we've captured the display and thus we won't
562 // get any notifications about what the current display mode really is. For now,
563 // we just always force it back to what mode we remember the desktop being in.
564 if (glConfig.isFullscreen) {
565 err = CGDisplaySwitchToMode(glw_state.display, (CFDictionaryRef)glw_state.desktopMode);
566 if ( err != CGDisplayNoErr )
567 common->Printf( " Unable to restore display mode!\n" );
569 ReleaseAllDisplays();
573 void GLimp_Shutdown( void ) {
574 CGDisplayCount displayIndex;
576 common->Printf("----- Shutting down GL -----\n");
578 Sys_FadeScreen(Sys_DisplayToUse());
580 if (OSX_GetNSGLContext()) {
581 #ifndef USE_CGLMACROS
582 OSX_GLContextClearCurrent();
584 // Have to call both to actually deallocate kernel resources and free the NSSurface
585 CGLClearDrawable(OSX_GetCGLContext());
586 [OSX_GetNSGLContext() clearDrawable];
588 [OSX_GetNSGLContext() release];
589 OSX_SetGLContext((id)nil);
592 _GLimp_RestoreOriginalVideoSettings();
596 // Restore the original gamma if needed.
597 // if (glConfig.deviceSupportsGamma) {
598 // common->Printf("Restoring ColorSync settings\n");
599 // CGDisplayRestoreColorSyncSettings();
602 if (glw_state.window) {
603 [glw_state.window release];
604 glw_state.window = nil;
607 if (glw_state.log_fp) {
608 fclose(glw_state.log_fp);
609 glw_state.log_fp = 0;
612 for (displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++) {
613 free(glw_state.originalDisplayGammaTables[displayIndex].red);
614 free(glw_state.originalDisplayGammaTables[displayIndex].blue);
615 free(glw_state.originalDisplayGammaTables[displayIndex].green);
617 free(glw_state.originalDisplayGammaTables);
618 if (glw_state.tempTable.red) {
619 free(glw_state.tempTable.red);
620 free(glw_state.tempTable.blue);
621 free(glw_state.tempTable.green);
623 if (glw_state.inGameTable.red) {
624 free(glw_state.inGameTable.red);
625 free(glw_state.inGameTable.blue);
626 free(glw_state.inGameTable.green);
629 memset(&glConfig, 0, sizeof(glConfig));
630 // memset(&glState, 0, sizeof(glState));
631 memset(&glw_state, 0, sizeof(glw_state));
633 common->Printf("----- Done shutting down GL -----\n");
641 void GLimp_LogComment( char *comment ) { }
648 void GLimp_SetGamma(unsigned short red[256],
649 unsigned short green[256],
650 unsigned short blue[256]) {
651 CGGammaValue redGamma[256], greenGamma[256], blueGamma[256];
655 for (i = 0; i < 256; i++) {
656 redGamma[i] = red[i] / 65535.0;
657 greenGamma[i] = green[i] / 65535.0;
658 blueGamma[i] = blue[i] / 65535.0;
661 err = CGSetDisplayTransferByTable(glw_state.display, 256, redGamma, greenGamma, blueGamma);
662 if (err != CGDisplayNoErr) {
663 common->Printf("GLimp_SetGamma: CGSetDisplayTransferByByteTable returned %d.\n", err);
666 // Store the gamma table that we ended up using so we can reapply it later when unhiding or to work around the bug where if you leave the game sitting and the monitor sleeps, when it wakes, the gamma isn't reset.
667 glw_state.inGameTable.display = glw_state.display;
668 Sys_GetGammaTable(&glw_state.inGameTable);
671 /*****************************************************************************/
674 #pragma mark ¥ ATI_fragment_shader
676 static GLuint sGeneratingProgram = 0;
677 static int sCurrentPass;
678 static char sConstString[4096];
679 static char sPassString[2][4096];
681 static int sConstUsed;
682 static int sConst[8];
683 static GLfloat sConstVal[8][4];
685 static void _endPass (void) {
686 if (!sOpUsed) return;
691 GLuint glGenFragmentShadersATI (GLuint ID) {
692 qglGenProgramsARB(1, &ID);
696 void glBindFragmentShaderATI (GLuint ID) {
697 qglBindProgramARB(GL_TEXT_FRAGMENT_SHADER_ATI, ID);
700 void glDeleteFragmentShaderATI (GLuint ID) {
701 // qglDeleteProgramsARB(1, &ID);
704 void glBeginFragmentShaderATI (void) {
708 for (i = 0; i < 8; i ++)
712 sPassString[0][0] = 0;
713 sPassString[1][0] = 0;
716 sGeneratingProgram = 1;
719 void glEndFragmentShaderATI (void) {
722 char fragString[4096];
724 sGeneratingProgram = 0;
727 strcpy(fragString, "!!ATIfs1.0\n");
730 if (sConstString[0] || sConstUsed) {
731 strcat (fragString, "StartConstants;\n");
733 for (i = 0; i < 8; i ++) {
734 if (sConst[i] == 1) {
736 sprintf (str, " CONSTANT c%d = program.env[%d];\n", i, i);
737 strcat (fragString, str);
741 if (sConstString[0]) {
742 strcat (fragString, sConstString);
744 strcat (fragString, "EndConstants;\n\n");
747 if (sCurrentPass == 0) {
748 strcat(fragString, "StartOutputPass;\n");
749 strcat(fragString, sPassString[0]);
750 strcat(fragString, "EndPass;\n");
752 strcat(fragString, "StartPrelimPass;\n");
753 strcat(fragString, sPassString[0]);
754 strcat(fragString, "EndPass;\n\n");
756 strcat(fragString, "StartOutputPass;\n");
757 strcat(fragString, sPassString[1]);
758 strcat(fragString, "EndPass;\n");
761 qglProgramStringARB(GL_TEXT_FRAGMENT_SHADER_ATI, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(fragString), fragString);
762 qglGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &errPos );
764 const GLubyte *errString = glGetString(GL_PROGRAM_ERROR_STRING_ARB);
765 common->Warning("WARNING: glError at %d:%s when compiling atiFragmentShader %s", errPos, errString, fragString);
770 void glSetFragmentShaderConstantATI (GLuint num, const GLfloat *val) {
771 int constNum = num-GL_CON_0_ATI;
772 if (sGeneratingProgram) {
774 sprintf (str, " CONSTANT c%d = { %f, %f, %f, %f };\n", constNum, val[0], val[1], val[2], val[3]);
775 strcat (sConstString, str);
776 sConst[constNum] = 2;
779 // According to Duane, frequent setting of fragment shader constants, even if they contain
780 // the same value, will cause a performance hit.
781 // According to Chris Bentley at ATI, this performance hit appears if you are using
782 // many different fragment shaders in each scene.
783 // So, we cache those values and only set the constants if they are different.
784 if (memcmp (val, sConstVal[constNum], sizeof(GLfloat)*8*4) != 0)
786 qglProgramEnvParameter4fvARB (GL_TEXT_FRAGMENT_SHADER_ATI, num-GL_CON_0_ATI, val);
787 memcpy (sConstVal[constNum], val, sizeof(GLfloat)*8*4);
792 char *makeArgStr(GLuint arg) {
793 // Since we return "str", it needs to be static to ensure that it retains
794 // its value outside this routine.
795 static char str[128];
799 if ( arg >= GL_REG_0_ATI && arg <= GL_REG_5_ATI ) {
800 sprintf(str, "r%d", arg - GL_REG_0_ATI);
801 } else if(arg >= GL_CON_0_ATI && arg <= GL_CON_7_ATI) {
802 if(!sConst[arg - GL_CON_0_ATI]) {
804 sConst[arg - GL_CON_0_ATI] = 1;
806 sprintf(str, "c%d", arg - GL_CON_0_ATI);
807 } else if( arg >= GL_TEXTURE0_ARB && arg <= GL_TEXTURE31_ARB ) {
808 sprintf(str, "t%d", arg - GL_TEXTURE0_ARB);
809 } else if( arg == GL_PRIMARY_COLOR_ARB ) {
810 strcpy(str, "color0");
811 } else if(arg == GL_SECONDARY_INTERPOLATOR_ATI) {
812 strcpy(str, "color1");
813 } else if (arg == GL_ZERO) {
815 } else if (arg == GL_ONE) {
818 common->Warning("makeArgStr: bad arg value\n");
823 void glPassTexCoordATI (GLuint dst, GLuint coord, GLenum swizzle) {
824 char str[128] = "\0";
828 case GL_SWIZZLE_STR_ATI:
829 sprintf(str, " PassTexCoord r%d, %s.str;\n", dst - GL_REG_0_ATI, makeArgStr(coord));
831 case GL_SWIZZLE_STQ_ATI:
832 sprintf(str, " PassTexCoord r%d, %s.stq;\n", dst - GL_REG_0_ATI, makeArgStr(coord));
834 case GL_SWIZZLE_STR_DR_ATI:
835 sprintf(str, " PassTexCoord r%d, %s.str_dr;\n", dst - GL_REG_0_ATI, makeArgStr(coord));
837 case GL_SWIZZLE_STQ_DQ_ATI:
838 sprintf(str, " PassTexCoord r%d, %s.stq_dq;\n", dst - GL_REG_0_ATI, makeArgStr(coord));
841 common->Warning("glPassTexCoordATI invalid swizzle;");
844 strcat(sPassString[sCurrentPass], str);
847 void glSampleMapATI (GLuint dst, GLuint interp, GLenum swizzle) {
848 char str[128] = "\0";
852 case GL_SWIZZLE_STR_ATI:
853 sprintf(str, " SampleMap r%d, %s.str;\n", dst - GL_REG_0_ATI, makeArgStr(interp));
855 case GL_SWIZZLE_STQ_ATI:
856 sprintf(str, " SampleMap r%d, %s.stq;\n", dst - GL_REG_0_ATI, makeArgStr(interp));
858 case GL_SWIZZLE_STR_DR_ATI:
859 sprintf(str, " SampleMap r%d, %s.str_dr;\n", dst - GL_REG_0_ATI, makeArgStr(interp));
861 case GL_SWIZZLE_STQ_DQ_ATI:
862 sprintf(str, " SampleMap r%d, %s.stq_dq;\n", dst - GL_REG_0_ATI, makeArgStr(interp));
865 common->Warning("glSampleMapATI invalid swizzle;");
868 strcat(sPassString[sCurrentPass], str);
871 char *makeMaskStr(GLuint mask) {
872 // Since we return "str", it needs to be static to ensure that it retains
873 // its value outside this routine.
874 static char str[128];
883 strcpy(str, ".rgba");
902 if( mask & GL_RED_BIT_ATI )
904 if( mask & GL_GREEN_BIT_ATI )
906 if( mask & GL_BLUE_BIT_ATI )
914 char *makeDstModStr(GLuint mod) {
915 // Since we return "str", it needs to be static to ensure that it retains
916 // its value outside this routine.
917 static char str[128];
921 if( mod == GL_NONE) {
925 if( mod & GL_2X_BIT_ATI) {
929 if( mod & GL_4X_BIT_ATI) {
933 if( mod & GL_8X_BIT_ATI) {
937 if( mod & GL_SATURATE_BIT_ATI) {
941 if( mod & GL_HALF_BIT_ATI) {
942 strcat(str, ".half");
945 if( mod & GL_QUARTER_BIT_ATI) {
946 strcat(str, ".quarter");
949 if( mod & GL_EIGHTH_BIT_ATI) {
950 strcat(str, ".eighth");
956 char *makeArgModStr(GLuint mod) {
957 // Since we return "str", it needs to be static to ensure that it retains
958 // its value outside this routine.
959 static char str[128];
963 if( mod == GL_NONE) {
967 if( mod & GL_NEGATE_BIT_ATI) {
971 if( mod & GL_2X_BIT_ATI) {
975 if( mod & GL_BIAS_BIT_ATI) {
976 strcat(str, ".bias");
979 if( mod & GL_COMP_BIT_ATI) {
980 strcat(str, ".comp");
986 void glColorFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod) {
987 char str[128] = "\0";
994 sprintf(str, " MOV r%d", dst - GL_REG_0_ATI);
997 common->Warning("glColorFragmentOp1ATI invalid op;\n");
1000 if(dstMask != GL_NONE) {
1001 strcat(str, makeMaskStr(dstMask));
1004 strcat(str, ".rgb" );
1007 if(dstMod != GL_NONE) {
1008 strcat(str, makeDstModStr(dstMod));
1012 strcat(str, makeArgStr(arg1));
1013 if(arg1Rep != GL_NONE) {
1014 strcat(str, makeMaskStr(arg1Rep));
1016 if(arg1Mod != GL_NONE) {
1017 strcat(str, makeArgModStr(arg1Mod));
1021 strcat(sPassString[sCurrentPass], str);
1024 void glColorFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod) {
1025 char str[128] = "\0";
1032 // Unary operators - fall back to Op1 routine.
1034 glColorFragmentOp1ATI(op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod);
1039 sprintf(str, " ADD r%d", dst - GL_REG_0_ATI);
1042 sprintf(str, " MUL r%d", dst - GL_REG_0_ATI);
1045 sprintf(str, " SUB r%d", dst - GL_REG_0_ATI);
1048 sprintf(str, " DOT3 r%d", dst - GL_REG_0_ATI);
1051 sprintf(str, " DOT4 r%d", dst - GL_REG_0_ATI);
1054 common->Warning("glColorFragmentOp2ATI invalid op;");
1057 if(dstMask != GL_NONE) {
1058 strcat(str, makeMaskStr(dstMask));
1061 strcat(str, ".rgb" );
1063 if(dstMod != GL_NONE) {
1064 strcat(str, makeDstModStr(dstMod));
1068 strcat(str, makeArgStr(arg1));
1069 // if(arg1Rep != GL_NONE)
1070 strcat(str, makeMaskStr(arg1Rep));
1071 if(arg1Mod != GL_NONE) {
1072 strcat(str, makeArgModStr(arg1Mod));
1076 strcat(str, makeArgStr(arg2));
1077 // if(arg2Rep != GL_NONE)
1078 strcat(str, makeMaskStr(arg2Rep));
1079 if(arg2Mod != GL_NONE) {
1080 strcat(str, makeArgModStr(arg2Mod));
1084 strcat(sPassString[sCurrentPass], str);
1087 void glColorFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod) {
1088 char str[128] = "\0";
1093 // Unary operators - fall back to Op1 routine.
1095 glColorFragmentOp1ATI(op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod);
1098 // Binary operators - fall back to Op2 routine.
1104 glColorFragmentOp2ATI(op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod);
1107 // Ternary operators
1109 sprintf(str, " MAD r%d", dst - GL_REG_0_ATI);
1112 sprintf(str, " LERP r%d", dst - GL_REG_0_ATI);
1115 sprintf(str, " CND r%d", dst - GL_REG_0_ATI);
1118 sprintf(str, " CND0 r%d", dst - GL_REG_0_ATI);
1120 case GL_DOT2_ADD_ATI:
1121 sprintf(str, " DOT2ADD r%d", dst - GL_REG_0_ATI);
1124 common->Warning("glColorFragmentOp3ATI invalid op;");
1128 if(dstMask != GL_NONE) {
1129 strcat(str, makeMaskStr(dstMask));
1132 strcat(str, ".rgb" );
1134 if(dstMod != GL_NONE) {
1135 strcat(str, makeDstModStr(dstMod));
1139 strcat(str, makeArgStr(arg1));
1140 if(arg1Rep != GL_NONE) {
1141 strcat(str, makeMaskStr(arg1Rep));
1143 if(arg1Mod != GL_NONE) {
1144 strcat(str, makeArgModStr(arg1Mod));
1148 strcat(str, makeArgStr(arg2));
1149 if(arg2Rep != GL_NONE) {
1150 strcat(str, makeMaskStr(arg2Rep));
1152 if(arg2Mod != GL_NONE) {
1153 strcat(str, makeArgModStr(arg2Mod));
1157 strcat(str, makeArgStr(arg3));
1158 if(arg3Rep != GL_NONE) {
1159 strcat(str, makeMaskStr(arg3Rep));
1161 if(arg3Mod != GL_NONE) {
1162 strcat(str, makeArgModStr(arg3Mod));
1166 strcat(sPassString[sCurrentPass], str);
1169 void glAlphaFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod) {
1170 glColorFragmentOp1ATI ( op, dst, GL_ALPHA, dstMod, arg1, arg1Rep, arg1Mod);
1173 void glAlphaFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod) {
1174 glColorFragmentOp2ATI ( op, dst, GL_ALPHA, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod);
1177 void glAlphaFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod) {
1178 glColorFragmentOp3ATI ( op, dst, GL_ALPHA, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, arg3, arg3Rep, arg3Mod);
1182 GLExtension_t GLimp_ExtensionPointer(const char *name) {
1186 // special case for ATI_fragment_shader calls to map to ATI_text_fragment_shader routines
1187 if (!strcmp(name, "glGenFragmentShadersATI")) {
1188 return (GLExtension_t)glGenFragmentShadersATI;
1190 if (!strcmp(name, "glBindFragmentShaderATI")) {
1191 return (GLExtension_t)glBindFragmentShaderATI;
1193 if (!strcmp(name, "glDeleteFragmentShaderATI")) {
1194 return (GLExtension_t)glDeleteFragmentShaderATI;
1196 if (!strcmp(name, "glBeginFragmentShaderATI")) {
1197 return (GLExtension_t)glBeginFragmentShaderATI;
1199 if (!strcmp(name, "glEndFragmentShaderATI")) {
1200 return (GLExtension_t)glEndFragmentShaderATI;
1202 if (!strcmp(name, "glPassTexCoordATI")) {
1203 return (GLExtension_t)glPassTexCoordATI;
1205 if (!strcmp(name, "glSampleMapATI")) {
1206 return (GLExtension_t)glSampleMapATI;
1208 if (!strcmp(name, "glColorFragmentOp1ATI")) {
1209 return (GLExtension_t)glColorFragmentOp1ATI;
1211 if (!strcmp(name, "glColorFragmentOp2ATI")) {
1212 return (GLExtension_t)glColorFragmentOp2ATI;
1214 if (!strcmp(name, "glColorFragmentOp3ATI")) {
1215 return (GLExtension_t)glColorFragmentOp3ATI;
1217 if (!strcmp(name, "glAlphaFragmentOp1ATI")) {
1218 return (GLExtension_t)glAlphaFragmentOp1ATI;
1220 if (!strcmp(name, "glAlphaFragmentOp2ATI")) {
1221 return (GLExtension_t)glAlphaFragmentOp2ATI;
1223 if (!strcmp(name, "glAlphaFragmentOp3ATI")) {
1224 return (GLExtension_t)glAlphaFragmentOp3ATI;
1226 if (!strcmp(name, "glSetFragmentShaderConstantATI")) {
1227 return (GLExtension_t)glSetFragmentShaderConstantATI;
1230 // Prepend a '_' for the Unix C symbol mangling convention
1231 symbolName = (char *)alloca(strlen(name) + 2);
1232 strcpy(symbolName + 1, name);
1233 symbolName[0] = '_';
1235 if ( !NSIsSymbolNameDefined( symbolName ) ) {
1239 symbol = NSLookupAndBindSymbol(symbolName);
1241 // shouldn't happen ...
1245 return (GLExtension_t)(NSAddressOfSymbol(symbol));
1248 void * wglGetProcAddress(const char *name) {
1249 return (void *)GLimp_ExtensionPointer( name );
1254 ** GLW_InitExtensions
1256 void GLW_InitExtensions( void ) { }
1258 #define MAX_RENDERER_INFO_COUNT 128
1260 // Returns zero if there are no hardware renderers. Otherwise, returns the max memory across all renderers (on the presumption that the screen that we'll use has the most memory).
1261 unsigned long Sys_QueryVideoMemory() {
1263 CGLRendererInfoObj rendererInfo, rendererInfos[MAX_RENDERER_INFO_COUNT];
1264 long rendererInfoIndex, rendererInfoCount = MAX_RENDERER_INFO_COUNT;
1265 long rendererIndex, rendererCount;
1266 long maxVRAM = 0, vram = 0;
1269 long totalRenderers = 0;
1271 err = CGLQueryRendererInfo(CGDisplayIDToOpenGLDisplayMask(Sys_DisplayToUse()), rendererInfos, &rendererInfoCount);
1273 common->Printf("CGLQueryRendererInfo -> %d\n", err);
1277 //common->Printf("rendererInfoCount = %d\n", rendererInfoCount);
1278 for (rendererInfoIndex = 0; rendererInfoIndex < rendererInfoCount && totalRenderers < rendererInfoCount; rendererInfoIndex++) {
1279 rendererInfo = rendererInfos[rendererInfoIndex];
1280 //common->Printf("rendererInfo: 0x%08x\n", rendererInfo);
1283 err = CGLDescribeRenderer(rendererInfo, 0, kCGLRPRendererCount, &rendererCount);
1285 common->Printf("CGLDescribeRenderer(kCGLRPRendererID) -> %d\n", err);
1288 //common->Printf(" rendererCount: %d\n", rendererCount);
1290 for (rendererIndex = 0; rendererIndex < rendererCount; rendererIndex++) {
1292 //common->Printf(" rendererIndex: %d\n", rendererIndex);
1294 rendererID = 0xffffffff;
1295 err = CGLDescribeRenderer(rendererInfo, rendererIndex, kCGLRPRendererID, &rendererID);
1297 common->Printf("CGLDescribeRenderer(kCGLRPRendererID) -> %d\n", err);
1300 //common->Printf(" rendererID: 0x%08x\n", rendererID);
1303 err = CGLDescribeRenderer(rendererInfo, rendererIndex, kCGLRPAccelerated, &accelerated);
1305 common->Printf("CGLDescribeRenderer(kCGLRPAccelerated) -> %d\n", err);
1308 //common->Printf(" accelerated: %d\n", accelerated);
1313 err = CGLDescribeRenderer(rendererInfo, rendererIndex, kCGLRPVideoMemory, &vram);
1315 common->Printf("CGLDescribeRenderer -> %d\n", err);
1318 //common->Printf(" vram: 0x%08x\n", vram);
1320 // presumably we'll be running on the best card, so we'll take the max of the vrams
1326 err = CGLDestroyRendererInfo(rendererInfo);
1328 common->Printf("CGLDestroyRendererInfo -> %d\n", err);
1337 // We will set the Sys_IsHidden global to cause input to be handle differently (we'll just let NSApp handle events in this case). We also will unbind the GL context and restore the video mode.
1344 if ( !r_fullscreen.GetBool() ) {
1345 // We only support hiding in fullscreen mode right now
1351 // Don't need to store the current gamma since we always keep it around in glw_state.inGameTable.
1353 Sys_FadeScreen(Sys_DisplayToUse());
1355 // Disassociate the GL context from the screen
1356 // Have to call both to actually deallocate kernel resources and free the NSSurface
1357 CGLClearDrawable(OSX_GetCGLContext());
1358 [OSX_GetNSGLContext() clearDrawable];
1360 // Restore the original video mode
1361 _GLimp_RestoreOriginalVideoSettings();
1363 // Restore the original gamma if needed.
1364 // if (glConfig.deviceSupportsGamma) {
1365 // CGDisplayRestoreColorSyncSettings();
1368 // Release the screen(s)
1369 ReleaseAllDisplays();
1371 Sys_UnfadeScreens();
1373 // Shut down the input system so the mouse and keyboard settings are restore to normal
1374 Sys_ShutdownInput();
1376 // Hide the application so that when the user clicks on our app icon, we'll get an unhide notification
1382 CGDisplayErr Sys_CaptureActiveDisplays(void) {
1384 CGDisplayCount displayIndex;
1385 for (displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++) {
1386 const glwgamma_t *table;
1387 table = &glw_state.originalDisplayGammaTables[displayIndex];
1388 err = CGDisplayCapture(table->display);
1389 if (err != CGDisplayNoErr)
1392 return CGDisplayNoErr;
1406 // Capture the screen(s)
1407 err = Sys_CaptureActiveDisplays();
1408 if (err != CGDisplayNoErr) {
1409 Sys_UnfadeScreens();
1410 common->Printf( "Unhide failed -- cannot capture the display again.\n" );
1414 // Restore the game mode
1415 err = CGDisplaySwitchToMode(glw_state.display, (CFDictionaryRef)glw_state.gameMode);
1416 if ( err != CGDisplayNoErr ) {
1417 ReleaseAllDisplays();
1418 Sys_UnfadeScreens();
1419 common->Printf( "Unhide failed -- Unable to set display mode\n" );
1423 // Reassociate the GL context and the screen
1424 glErr = CGLSetFullScreen(OSX_GetCGLContext());
1426 ReleaseAllDisplays();
1427 Sys_UnfadeScreens();
1428 common->Printf( "Unhide failed: CGLSetFullScreen -> %d (%s)\n", err, CGLErrorString(glErr));
1432 // Restore the current context
1433 [OSX_GetNSGLContext() makeCurrentContext];
1435 // Restore the gamma that the game had set
1436 Sys_UnfadeScreen(Sys_DisplayToUse(), &glw_state.inGameTable);
1438 // Restore the input system (last so if something goes wrong we don't eat the mouse)
1445 bool GLimp_SpawnRenderThread( void (*function)( void ) ) {
1449 void *GLimp_RendererSleep(void) {
1453 void GLimp_FrontEndSleep(void) { }
1455 void GLimp_WakeRenderer( void *data ) { }
1457 void *GLimp_BackEndSleep( void ) {
1461 void GLimp_WakeBackEnd( void *data ) {
1464 // enable / disable context is just for the r_skipRenderContext debug option
1465 void GLimp_DeactivateContext( void ) {
1466 [NSOpenGLContext clearCurrentContext];
1469 void GLimp_ActivateContext( void ) {
1470 [OSX_GetNSGLContext() makeCurrentContext];
1473 void GLimp_EnableLogging(bool stat) { }
1475 NSDictionary *Sys_GetMatchingDisplayMode( glimpParms_t parms ) {
1476 NSArray *displayModes;
1478 unsigned int modeIndex, modeCount, bestModeIndex;
1480 // cvar_t *cMinFreq, *cMaxFreq;
1481 int minFreq, maxFreq;
1482 unsigned int colorDepth;
1488 minFreq = r_minDisplayRefresh.GetInteger();
1489 maxFreq = r_maxDisplayRefresh.GetInteger();
1490 if ( minFreq > maxFreq ) {
1491 common->Error( "r_minDisplayRefresh must be less than or equal to r_maxDisplayRefresh" );
1494 displayModes = (NSArray *)CGDisplayAvailableModes(glw_state.display);
1495 if (!displayModes) {
1496 common->Error( "CGDisplayAvailableModes returned NULL -- 0x%0x is an invalid display", glw_state.display);
1499 modeCount = [displayModes count];
1501 common->Printf( "%d modes avaliable\n", modeCount);
1502 common->Printf( "Current mode is %s\n", [[(id)CGDisplayCurrentMode(glw_state.display) description] cString]);
1505 // Default to the current desktop mode
1506 bestModeIndex = 0xFFFFFFFF;
1508 for ( modeIndex = 0; modeIndex < modeCount; ++modeIndex ) {
1512 mode = [displayModes objectAtIndex: modeIndex];
1514 common->Printf( " mode %d -- %s\n", modeIndex, [[mode description] cString]);
1517 // Make sure we get the right size
1518 if ([[mode objectForKey: (id)kCGDisplayWidth] intValue] != parms.width ||
1519 [[mode objectForKey: (id)kCGDisplayHeight] intValue] != parms.height) {
1521 common->Printf( " -- bad size\n");
1525 // Make sure that our frequency restrictions are observed
1526 refresh = [[mode objectForKey: (id)kCGDisplayRefreshRate] intValue];
1527 if (minFreq && refresh < minFreq) {
1529 common->Printf( " -- refresh too low\n");
1533 if (maxFreq && refresh > maxFreq) {
1535 common->Printf( " -- refresh too high\n");
1539 if ([[mode objectForKey: (id)kCGDisplayBitsPerPixel] intValue] != colorDepth) {
1541 common->Printf( " -- bad depth\n");
1545 object = [mode objectForKey: (id)kCGDisplayModeIsStretched];
1547 if ( [object boolValue] != cvarSystem->GetCVarBool( "r_stretched" ) ) {
1549 common->Printf( " -- bad stretch setting\n");
1554 if ( cvarSystem->GetCVarBool( "r_stretched" ) ) {
1556 common->Printf( " -- stretch requested, stretch property not available\n");
1561 bestModeIndex = modeIndex;
1563 common->Printf( " -- OK\n", bestModeIndex);
1567 common->Printf( " bestModeIndex = %d\n", bestModeIndex);
1569 if (bestModeIndex == 0xFFFFFFFF) {
1570 common->Printf( "No suitable display mode available.\n");
1574 return [displayModes objectAtIndex: bestModeIndex];
1578 #define MAX_DISPLAYS 128
1580 void Sys_GetGammaTable(glwgamma_t *table) {
1581 CGTableCount tableSize = 512;
1584 table->tableSize = tableSize;
1587 table->red = (float *)malloc(tableSize * sizeof(*table->red));
1590 table->green = (float *)malloc(tableSize * sizeof(*table->green));
1593 table->blue = (float *)malloc(tableSize * sizeof(*table->blue));
1595 // TJW: We _could_ loop here if we get back the same size as our table, increasing the table size.
1596 err = CGGetDisplayTransferByTable(table->display, tableSize, table->red, table->green, table->blue,
1598 if (err != CGDisplayNoErr) {
1599 common->Printf("GLimp_Init: CGGetDisplayTransferByTable returned %d.\n", err);
1600 table->tableSize = 0;
1604 void Sys_SetGammaTable(glwgamma_t *table) { }
1606 void Sys_StoreGammaTables() {
1607 // Store the original gamma for all monitors so that we can fade and unfade them all
1608 CGDirectDisplayID displays[MAX_DISPLAYS];
1609 CGDisplayCount displayIndex;
1612 err = CGGetActiveDisplayList(MAX_DISPLAYS, displays, &glw_state.displayCount);
1613 if (err != CGDisplayNoErr)
1614 Sys_Error("Cannot get display list -- CGGetActiveDisplayList returned %d.\n", err);
1616 glw_state.originalDisplayGammaTables = (glwgamma_t *)calloc(glw_state.displayCount, sizeof(*glw_state.originalDisplayGammaTables));
1617 for (displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++) {
1620 table = &glw_state.originalDisplayGammaTables[displayIndex];
1621 table->display = displays[displayIndex];
1622 Sys_GetGammaTable(table);
1627 // This isn't a mathematically correct fade, but we don't care that much.
1628 void Sys_SetScreenFade(glwgamma_t *table, float fraction) {
1629 CGTableCount tableSize;
1630 CGGammaValue *red, *blue, *green;
1631 CGTableCount gammaIndex;
1633 // if (!glConfig.deviceSupportsGamma)
1636 if (!(tableSize = table->tableSize))
1637 // we couldn't get the table for this display for some reason
1640 // common->Printf("0x%08x %f\n", table->display, fraction);
1642 red = glw_state.tempTable.red;
1643 green = glw_state.tempTable.green;
1644 blue = glw_state.tempTable.blue;
1645 if (glw_state.tempTable.tableSize < tableSize) {
1646 glw_state.tempTable.tableSize = tableSize;
1647 red = (float *)realloc(red, sizeof(*red) * tableSize);
1648 green = (float *)realloc(green, sizeof(*green) * tableSize);
1649 blue = (float *)realloc(blue, sizeof(*blue) * tableSize);
1650 glw_state.tempTable.red = red;
1651 glw_state.tempTable.green = green;
1652 glw_state.tempTable.blue = blue;
1655 for (gammaIndex = 0; gammaIndex < table->tableSize; gammaIndex++) {
1656 red[gammaIndex] = table->red[gammaIndex] * fraction;
1657 blue[gammaIndex] = table->blue[gammaIndex] * fraction;
1658 green[gammaIndex] = table->green[gammaIndex] * fraction;
1661 CGSetDisplayTransferByTable(table->display, table->tableSize, red, green, blue);
1664 // Fades all the active displays at the same time.
1666 #define FADE_DURATION 0.5
1667 void Sys_FadeScreens() {
1668 CGDisplayCount displayIndex;
1671 NSTimeInterval start, current;
1674 // if (!glConfig.deviceSupportsGamma)
1677 common->Printf("Fading all displays\n");
1679 start = [NSDate timeIntervalSinceReferenceDate];
1681 while (time != FADE_DURATION) {
1682 current = [NSDate timeIntervalSinceReferenceDate];
1683 time = current - start;
1684 if (time > FADE_DURATION)
1685 time = FADE_DURATION;
1687 for (displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++) {
1688 table = &glw_state.originalDisplayGammaTables[displayIndex];
1689 Sys_SetScreenFade(table, 1.0 - time / FADE_DURATION);
1694 void Sys_FadeScreen(CGDirectDisplayID display) {
1695 CGDisplayCount displayIndex;
1699 common->Printf( "FIXME: Sys_FadeScreen\n" );
1703 // if (!glConfig.deviceSupportsGamma)
1706 common->Printf("Fading display 0x%08x\n", display);
1708 for (displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++) {
1709 if (display == glw_state.originalDisplayGammaTables[displayIndex].display) {
1710 NSTimeInterval start, current;
1713 start = [NSDate timeIntervalSinceReferenceDate];
1716 table = &glw_state.originalDisplayGammaTables[displayIndex];
1717 while (time != FADE_DURATION) {
1718 current = [NSDate timeIntervalSinceReferenceDate];
1719 time = current - start;
1720 if (time > FADE_DURATION)
1721 time = FADE_DURATION;
1723 Sys_SetScreenFade(table, 1.0 - time / FADE_DURATION);
1729 common->Printf("Unable to find display to fade it\n");
1732 void Sys_UnfadeScreens() {
1733 CGDisplayCount displayIndex;
1736 NSTimeInterval start, current;
1739 common->Printf( "FIXME: Sys_UnfadeScreens\n" );
1743 // if (!glConfig.deviceSupportsGamma)
1746 common->Printf("Unfading all displays\n");
1748 start = [NSDate timeIntervalSinceReferenceDate];
1750 while (time != FADE_DURATION) {
1751 current = [NSDate timeIntervalSinceReferenceDate];
1752 time = current - start;
1753 if (time > FADE_DURATION)
1754 time = FADE_DURATION;
1756 for (displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++) {
1757 table = &glw_state.originalDisplayGammaTables[displayIndex];
1758 Sys_SetScreenFade(table, time / FADE_DURATION);
1763 void Sys_UnfadeScreen(CGDirectDisplayID display, glwgamma_t *table) {
1764 CGDisplayCount displayIndex;
1767 common->Printf( "FIXME: Sys_UnfadeScreen\n" );
1770 // if (!glConfig.deviceSupportsGamma)
1773 common->Printf("Unfading display 0x%08x\n", display);
1778 common->Printf("Given table:\n");
1779 for (i = 0; i < table->tableSize; i++) {
1780 common->Printf(" %f %f %f\n", table->red[i], table->blue[i], table->green[i]);
1784 // Search for the original gamma table for the display
1786 for (displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++) {
1787 if (display == glw_state.originalDisplayGammaTables[displayIndex].display) {
1788 table = &glw_state.originalDisplayGammaTables[displayIndex];
1795 NSTimeInterval start, current;
1798 start = [NSDate timeIntervalSinceReferenceDate];
1801 while (time != FADE_DURATION) {
1802 current = [NSDate timeIntervalSinceReferenceDate];
1803 time = current - start;
1804 if (time > FADE_DURATION)
1805 time = FADE_DURATION;
1806 Sys_SetScreenFade(table, time / FADE_DURATION);
1811 common->Printf("Unable to find display to unfade it\n");
1814 #define MAX_DISPLAYS 128
1816 CGDirectDisplayID Sys_DisplayToUse(void) {
1817 static bool gotDisplay = NO;
1818 static CGDirectDisplayID displayToUse;
1821 CGDirectDisplayID displays[MAX_DISPLAYS];
1822 CGDisplayCount displayCount;
1826 return displayToUse;
1830 err = CGGetActiveDisplayList( MAX_DISPLAYS, displays, &displayCount );
1831 if ( err != CGDisplayNoErr ) {
1832 common->Error("Cannot get display list -- CGGetActiveDisplayList returned %d.\n", err );
1835 // -1, the default, means to use the main screen
1836 displayIndex = r_screen.GetInteger();
1838 if ( displayIndex < 0 || displayIndex >= displayCount ) {
1839 // This is documented (in CGDirectDisplay.h) to be the main display. We want to
1840 // return this instead of kCGDirectMainDisplay since this will allow us to compare
1842 displayToUse = displays[ 0 ];
1844 displayToUse = displays[ displayIndex ];
1847 return displayToUse;
1852 GLimp_SetScreenParms
1855 bool GLimp_SetScreenParms( glimpParms_t parms ) {
1864 void Sys_GrabMouseCursor( bool grabIt ) { }