From 447f4202ae5af2291ebd3a481b6931bf52d90e21 Mon Sep 17 00:00:00 2001 From: Eric Heien Date: Mon, 14 Oct 2002 20:42:01 +0000 Subject: [PATCH] mac opengl svn path=/trunk/boinc/; revision=493 --- api/mac_app_opengl.c | 409 +++++++ api/mac_app_opengl.h | 33 + api/mac_carbon_dsp.c | 888 +++++++++++++++ api/mac_carbon_dsp.h | 128 +++ api/mac_carbon_gl.c | 1379 ++++++++++++++++++++++++ api/mac_carbon_gl.h | 243 +++++ checkin_notes | 12 + mac_build/boinc.pbproj/project.pbxproj | 172 ++- 8 files changed, 3220 insertions(+), 44 deletions(-) create mode 100644 api/mac_app_opengl.c create mode 100644 api/mac_app_opengl.h create mode 100755 api/mac_carbon_dsp.c create mode 100755 api/mac_carbon_dsp.h create mode 100755 api/mac_carbon_gl.c create mode 100755 api/mac_carbon_gl.h diff --git a/api/mac_app_opengl.c b/api/mac_app_opengl.c new file mode 100644 index 0000000000..ea9a47774c --- /dev/null +++ b/api/mac_app_opengl.c @@ -0,0 +1,409 @@ +// The contents of this file are subject to the Mozilla Public License +// Version 1.0 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://www.mozilla.org/MPL/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations +// under the License. +// +// The Original Code is the Berkeley Open Infrastructure for Network Computing. +// +// The Initial Developer of the Original Code is the SETI@home project. +// Portions created by the SETI@home project are Copyright (C) 2002 +// University of California at Berkeley. All Rights Reserved. +// +// Contributor(s): +// + +#include "graphics_api.h" + +#include "mac_app_opengl.h" +#include "mac_carbon_gl.h" + +#ifdef __APPLE_CC__ + #include + #include +#else + #include + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include +#endif + +#include +#include +#include + +// project includes --------------------------------------------------------- + +#include "mac_main.h" + +void drawGL(WindowPtr pWindow); + +static void DisposeGLWindow (WindowPtr pWindow); // Dispose a single window and it's GL context + +// statics/globals (internal only) ------------------------------------------ + +static const EventTypeSpec appEventList[] = +{ +{kEventClassCommand, kEventCommandProcess}, +{kEventClassMouse, kEventMouseDown}, +{kEventClassMouse, kEventMouseUp}, +{kEventClassMouse, kEventMouseMoved}, +{kEventClassMouse, kEventMouseDragged}, +{kEventClassMouse, kEventMouseWheelMoved} +}; + +WindowRef appGLWindow; +EventLoopTimerRef boincTimer; +EventLoopTimerUPP boincTimerUPP; +EventHandlerUPP appCommandProcessor; +WindowPtr boincAboutWindow; +AGLContext boincAGLContext; +GLuint monacoFontList; +char boincStrContext [256]; +structGLWindowInfo glInfo; + +long gFrameWindow=0; +float gRotation=0; +AbsoluteTime gTimeWindow; + +bool user_requested_exit = false; + +// -------------------------------------------------------------------------- + +int InitGLWindow(int xsize, int ysize, int depth) +{ + OSStatus err; + Rect winRect; + TimerUPP boincYieldUPP; + EventLoopTimerRef boincYieldTimer; + short i,fNum; + long response; + MenuHandle menu; + + InitCursor(); + + // add quit if not under Mac OS X + err = Gestalt (gestaltMenuMgrAttr, &response); + if ((err == noErr) && !(response & gestaltMenuMgrAquaLayoutMask)) { + menu = NewMenu (128, "\pFile"); // new menu + InsertMenu (menu, 0); // add menu to end + + AppendMenu (menu, "\pQuit/Q"); // add quit + } + + SetRect( &winRect, 100, 100, 100+xsize, 100+ysize ); + + err = CreateNewWindow ( kDocumentWindowClass, kWindowStandardDocumentAttributes, &winRect, &appGLWindow ); + if (err != noErr) return -1; + + // Application-level event handler installer + appCommandProcessor = NewEventHandlerUPP(MainAppEventHandler); + err = InstallApplicationEventHandler(appCommandProcessor, GetEventTypeCount(appEventList), + appEventList, 0, NULL); + // Install application graphics timer + boincTimerUPP = NewEventLoopTimerUPP(GraphicsLoopProcessor); + err = InstallEventLoopTimer(GetMainEventLoop(), 0, + kEventDurationMillisecond*10, // Every 1/60th of a second + boincTimerUPP, NULL, &boincTimer); + + // Install preemption + boincYieldUPP = NewEventLoopTimerUPP(YieldProcessor); + err = InstallEventLoopTimer(GetMainEventLoop(), 0, + kEventDurationMillisecond*10, // Every 10 ms + boincYieldUPP, NULL, &boincYieldTimer); + + // TODO: add an event handler for the window + ChangeWindowAttributes( appGLWindow, kWindowStandardHandlerAttribute, 0 ); + SetWTitle (appGLWindow, "\pWindow"); + ShowWindow(appGLWindow); + SetPortWindowPort (appGLWindow); + + glInfo.fAcceleratedMust = false; // must renderer be accelerated? + glInfo.VRAM = 0 * 1048576; // minimum VRAM (if not zero this is always a required minimum) + glInfo.textureRAM = 0 * 1048576; // minimum texture RAM (if not zero this is always a required minimum) + if (!CheckMacOSX ()) // this is false on Mac OS 9 since Mac OS 9 does not support dragging conttexts with shared txtures between to different vendor's renderers. + glInfo.fDraggable = false; // should a pixel format that supports all monitors be chosen? + else + glInfo.fDraggable = true; // should a pixel format that supports all monitors be chosen? + glInfo.fmt = 0; // output pixel format + + i = 0; + glInfo.aglAttributes [i++] = AGL_RGBA; + glInfo.aglAttributes [i++] = AGL_DOUBLEBUFFER; + glInfo.aglAttributes [i++] = AGL_ACCELERATED; + glInfo.aglAttributes [i++] = AGL_NO_RECOVERY; + glInfo.aglAttributes [i++] = AGL_DEPTH_SIZE; + glInfo.aglAttributes [i++] = 16; + glInfo.aglAttributes [i++] = AGL_NONE; + + BuildGLFromWindow (appGLWindow, &boincAGLContext, &glInfo, NULL ); + if (!boincAGLContext) + { + DestroyGLFromWindow (&boincAGLContext, &glInfo); + sprintf (boincStrContext, "No context"); + } + else + { + Rect rectPort; + + GetWindowPortBounds (appGLWindow, &rectPort); + aglSetCurrentContext (boincAGLContext); + aglReportError (); + aglUpdateContext (boincAGLContext); + aglReportError (); + + // Set Texture mapping parameters + glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + glClearColor(0.15f, 0.15f, 0.15f, 1.0f); // Clear color buffer to dark grey + glClear (GL_COLOR_BUFFER_BIT); + glReportError (); + aglSwapBuffers (boincAGLContext); + aglReportError (); + + aglDisable (boincAGLContext, AGL_BUFFER_RECT); + aglReportError (); + glViewport (0, 0, rectPort.right - rectPort.left, rectPort.bottom - rectPort.top); + glReportError (); + sprintf (boincStrContext, "%d x %d", rectPort.right - rectPort.left, rectPort.bottom - rectPort.top); + + GetFNum("\pMonaco", &fNum); // build font + monacoFontList = BuildFontGL (boincAGLContext, fNum, normal, 9); + + aglUpdateContext (boincAGLContext); + aglReportError (); + } + + return 0; +} + +////////////////////////////////////////////////////////////////////////////////// +// GraphicsLoopProcessor // +////////////////////////////////////////////////////////////////////////////////// +pascal void GraphicsLoopProcessor(EventLoopTimerRef inTimer, void* timeData) { + DoUpdate (boincAGLContext); +} + +////////////////////////////////////////////////////////////////////////////////// +// YieldProcessor // +////////////////////////////////////////////////////////////////////////////////// +pascal void YieldProcessor(EventLoopTimerRef inTimer, void* timeData) { + YieldToAnyThread(); +} + +/* + if ((pWindowInfo) && (boincAGLContext)) + { + GetWindowPortBounds (whichWindow, &rectTemp); + aglSetCurrentContext (boincAGLContext); // ensure the context we are working with is current + aglUpdateContext (boincAGLContext); + glViewport (0, 0, rectTemp.right - rectTemp.left, rectTemp.bottom - rectTemp.top); + sprintf (pWindowInfo->strContext, "%d x %d", rectTemp.right - rectTemp.left, rectTemp.bottom - rectTemp.top); + } +*/ + +////////////////////////////////////////////////////////////////////////////////// +// MainAppEventHandler // +////////////////////////////////////////////////////////////////////////////////// +pascal OSStatus MainAppEventHandler(EventHandlerCallRef appHandler, EventRef theEvent, void* appData) +{ +#pragma unused (appHandler, appData) + + HICommand aCommand; + OSStatus result; + Point mDelta; + + switch(GetEventClass(theEvent)) + { + case kEventClassMouse: // 'mous' + GetEventParameter(theEvent, // the event itself + kEventParamMouseDelta, // symbolic parameter name + typeQDPoint, // expected type + NULL, // actual type (NULL is valid) + sizeof(mDelta), // buffer size + NULL, // actual buffer size (Can be NULL) + &mDelta); // variable to hold data + switch(GetEventKind(theEvent)) + { + case kEventMouseDown: + break; + case kEventMouseUp: + break; + case kEventMouseMoved: + break; + case kEventMouseDragged: + break; + case kEventMouseWheelMoved: + break; + default: + result = eventNotHandledErr; + break; + } + break; + case kEventClassCommand: + result = GetEventParameter(theEvent, kEventParamDirectObject, + typeHICommand, NULL, sizeof(HICommand), + NULL, &aCommand); + switch (aCommand.commandID) + { + case kHICommandQuit: + QuitApplicationEventLoop(); + result = noErr; + break; + case kHICommandOK: // 'ok ' + case kHICommandCancel: // 'not!' + case kHICommandUndo: // 'undo' + case kHICommandRedo: // 'redo' + case kHICommandCut: // 'cut ' + case kHICommandCopy: // 'copy' + case kHICommandPaste: // 'past' + case kHICommandClear: // 'clea' + case kHICommandSelectAll: // 'sall' + case kHICommandHide: // 'hide' + case kHICommandZoomWindow: // 'zoom' + case kHICommandMinimizeWindow: // 'mini' + case kHICommandArrangeInFront: // 'frnt' + break; + case kHICommandAbout: // 'abou' + // Open About window + //CreateAboutWindow(); + result = noErr; + break; + default: + result = eventNotHandledErr; + break; + } + break; + default: + result = eventNotHandledErr; + break; + } + + return result; +} + +// -------------------------------------------------------------------------- + +pascal void mac_graphics_event_loop ( GRAPHICS_INFO *gi ) { + InitGLWindow(gi->xsize, gi->ysize, 16); + RunApplicationEventLoop(); +} + +// -------------------------------------------------------------------------- + +void mac_cleanup (void) +{ + // TODO: Dispose all the timers here + RemoveEventLoopTimer(boincTimer); + DisposeEventLoopTimerUPP(boincTimerUPP); + DisposeEventHandlerUPP(appCommandProcessor); + //DisposeGLWindow (appGLWindow); +} + +// -------------------------------------------------------------------------- + +static void DisposeGLWindow (WindowPtr pWindow) // Dispose a single window and it's GL context +{ + if (pWindow) + { + DeleteFontGL (monacoFontList); + // must clean up failure to do so will result in an Unmapped Memory Exception + DestroyGLFromWindow (&boincAGLContext, &glInfo); + + DisposeWindow (pWindow); + } +} + + +#pragma mark - +//----------------------------------------------------------------------------------------------------------------------- + +// OpenGL Drawing + +void drawGL(WindowPtr pWindow) +{ + static int first = 1; + static char myStr[256]; + + if( first ) { + gFrameWindow = 0; + gTimeWindow.hi = 0; + gTimeWindow.lo = 0; + gRotation = 0.0; + first = 0; + } + float f = 0.0; + + glClearColor(0.25f, 0.25f, 0.25f, 1.0f); // Clear color buffer to dark grey + glClear(GL_COLOR_BUFFER_BIT); + + gRotation += 0.5; + f = gRotation; + + glMatrixMode (GL_MODELVIEW); + glLoadIdentity (); + glRotated (f, 0.0, 0.0, 1.0); + glEnable (GL_TEXTURE_2D); + glBegin(GL_QUADS); // Draw textured polygon + + glColor3d(1.0, 0.0, 0.0); + glVertex3d(0.7, 0.7, 0.0); + + glColor3d(0.0, 1.0, 0.0); + glVertex3d(-0.7, 0.7, 0.0); + + glColor3d(0.0, 0.0, 1.0); + glVertex3d(-0.7, -0.7, 0.0); + + glColor3d(0.7, 0.7, 0.7); + glVertex3d(0.7, -0.7, 0.0); + + glEnd(); + + glDisable (GL_TEXTURE_2D); + // draw info + + Rect rectPort; + GLint matrixMode; + GetWindowPortBounds (pWindow, &rectPort); + glGetIntegerv (GL_MATRIX_MODE, &matrixMode); + glMatrixMode (GL_PROJECTION); + glPushMatrix(); + glLoadIdentity (); + glMatrixMode (GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity (); + glScalef (2.0 / (rectPort.right - rectPort.left), -2.0 / (rectPort.bottom - rectPort.top), 1.0); + glTranslatef (-(rectPort.right - rectPort.left) / 2.0, -(rectPort.bottom - rectPort.top) / 2.0, 0.0); + glColor3f (1.0, 1.0, 1.0); + glRasterPos3d (10, 12, 0); + + MultiWinDrawFrameRate (monacoFontList, myStr, &gFrameWindow, &gTimeWindow); + + glRasterPos3d (10, 24, 0); + DrawCStringGL (boincStrContext, monacoFontList); + glRasterPos3d (10, (rectPort.bottom - rectPort.top) - 15, 0); + DrawCStringGL ((char*) glGetString (GL_VENDOR), monacoFontList); + glRasterPos3d (10, (rectPort.bottom - rectPort.top) - 3, 0); + DrawCStringGL ((char*) glGetString (GL_RENDERER), monacoFontList); + glPopMatrix(); // GL_MODELVIEW + glMatrixMode (GL_PROJECTION); + glPopMatrix(); + glMatrixMode (matrixMode); +} diff --git a/api/mac_app_opengl.h b/api/mac_app_opengl.h new file mode 100644 index 0000000000..78c0884509 --- /dev/null +++ b/api/mac_app_opengl.h @@ -0,0 +1,33 @@ +// The contents of this file are subject to the Mozilla Public License +// Version 1.0 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://www.mozilla.org/MPL/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations +// under the License. +// +// The Original Code is the Berkeley Open Infrastructure for Network Computing. +// +// The Initial Developer of the Original Code is the SETI@home project. +// Portions created by the SETI@home project are Copyright (C) 2002 +// University of California at Berkeley. All Rights Reserved. +// +// Contributor(s): +// + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +pascal void mac_graphics_event_loop ( GRAPHICS_INFO *gi ); +pascal void GraphicsLoopProcessor(EventLoopTimerRef inTimer, void* timeData); +pascal void YieldProcessor(EventLoopTimerRef inTimer, void* timeData); +extern int InitGLWindow(int xsize, int ysize, int depth); + +#ifdef __cplusplus +} +#endif diff --git a/api/mac_carbon_dsp.c b/api/mac_carbon_dsp.c new file mode 100755 index 0000000000..413884aae5 --- /dev/null +++ b/api/mac_carbon_dsp.c @@ -0,0 +1,888 @@ +// The contents of this file are subject to the Mozilla Public License +// Version 1.0 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://www.mozilla.org/MPL/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations +// under the License. +// +// The Original Code is the Berkeley Open Infrastructure for Network Computing. +// +// The Initial Developer of the Original Code is the SETI@home project. +// Portions created by the SETI@home project are Copyright (C) 2002 +// University of California at Berkeley. All Rights Reserved. +// +// Contributor(s): +// + +/* + Contains: Functions to enable building and destroying a DSp fullscreen context + + Written by: Geoff Stahl (ggs) + + Copyright: Copyright © 1999 Apple Computer, Inc., All Rights Reserved + + Change History (most recent first): + + <3> 3/26/01 ggs Add DSp version check and other items for full screen on X + <2> 3/26/01 ggs Add new DSp functinality for Mac OS X + <1> 1/19/01 ggs Initial re-add + <7> 3/21/00 ggs Added windowed mode and clean up various implementation details + <6> 2/22/00 ggs fix fades + <5> 1/26/00 ggs Add fade code back in, ensure NULL pointer/context checks are in + <4> 1/24/00 ggs add new disclaimer, protection from NULL dispose, better + software renderer handling + <3> 12/18/99 ggs Fixed err use before init + <2> 12/18/99 ggs Fix headers + <1> 11/28/99 ggs Initial add. Split of just DSp handling functions. Added total + device RAM checks, better step downs using actual supported + resolutions. Need to add user verify for contexts that require + it, integration of this in context step down, and a freq bit + field. + <1> 11/11/99 ggs Initial Add + + Disclaimer: You may incorporate this sample code into your applications without + restriction, though the sample code has been provided "AS IS" and the + responsibility for its operation is 100% yours. However, what you are + not permitted to do is to redistribute the source as "DSC Sample Code" + after having made changes. If you're going to re-distribute the source, + we require that you make it clear in the source that the code was + descended from Apple Sample Code, but that you've made changes. + + Adapted to BOINC by Eric Heien +*/ + + +// Usage notes: +// kUseFades enables gamma fades for activates and deactivates +#define kUseFades + +//kUseRAMCheck enables estimated video card RAM checks +#define kUseRAMCheck + + +// system includes ---------------------------------------------------------- + +#ifdef __APPLE_CC__ + #include +#else + #include + #include + + #include +#endif + +#include + +// project includes --------------------------------------------------------- + +#include "mac_carbon_dsp.h" + +// globals (internal/private) ----------------------------------------------- + +enum +{ + kMaxNumRes = 64, // max number of resolution slots + kMaxRefreshFreq = 75 +}; + +Boolean gDSpStarted = false; // will never be true unless DSp is installed and start succeeds +Boolean gNeedFade = false; + +// prototypes (internal/private) -------------------------------------------- + +DSpContextReference * ReserveUnusedDevices (GDHandle hGD); +OSStatus FreeUnusedDevices (GDHandle hGD, DSpContextReference ** ppContextRefUnused); +void BuildResolutionList (GDHandle hGD, Point * pResList, SInt32 * pFreqList); +OSStatus DoDeviceRAMCheck (pstructGLInfo pcontextInfo, Point * pResList, SInt32 * pFreqList, GLint depthSizeSupport); +Boolean DoContextStepDown (pstructGLInfo pcontextInfo, DSpContextAttributes * pContextAttributes, Point * pResList, SInt32 * pFreqList); + + +// functions (internal/private) --------------------------------------------- + +// ReserveUnusedDevices + +// reserves contexts on unused devices to vprevent their selection by DSp, returns list of these devices + +DSpContextReference * ReserveUnusedDevices (GDHandle hGD) +{ + DSpContextAttributes theContextAttributes; + DSpContextReference * pContextRefUnused = NULL; + GDHandle hDevice = DMGetFirstScreenDevice (true); // check number of screens + DisplayIDType displayID = 0; + short numDevices = 0, indexDevice = 0; + + do + { + numDevices++; + hDevice = DMGetNextScreenDevice (hDevice, true); + } + while (hDevice); + numDevices--; // only count unused screens + if (numDevices) + { + pContextRefUnused = (DSpContextReference *) NewPtr ((long) sizeof (DSpContextReference) * numDevices); + hDevice = DMGetFirstScreenDevice (true); // check number of screens + do + { + if (hDevice != hGD) // if this device is not the one the user chose + { + if (noErr == DSpReportError (DMGetDisplayIDByGDevice (hDevice, &displayID, false))) + if (noErr == DSpReportError (DSpGetFirstContext (displayID, &pContextRefUnused [indexDevice]))) // get a context and + if (noErr == DSpReportError (DSpContext_GetAttributes (pContextRefUnused [indexDevice], &theContextAttributes))) // find attributes + DSpReportError (DSpContext_Reserve (pContextRefUnused [indexDevice], &theContextAttributes)); // reserve it + indexDevice++; + } + hDevice = DMGetNextScreenDevice (hDevice, true); + } + while (hDevice); + } + return pContextRefUnused; +} + +// -------------------------------------------------------------------------- + +// FreeUnusedDevices + +// frees screen that were previously reserved to prevent selection + +OSStatus FreeUnusedDevices (GDHandle hGD, DSpContextReference ** ppContextRefUnused) +{ + OSStatus err = noErr; + GDHandle hDevice = DMGetFirstScreenDevice (true); // check number of screens + short indexDevice = 0; + + do + { + if (hDevice != hGD) // if this device is not the one the user chose + { + err = DSpContext_Release (*ppContextRefUnused [indexDevice]); // release it + DSpReportError (err); + indexDevice++; + } + hDevice = DMGetNextScreenDevice (hDevice, true); + } + while (hDevice); + + if (*ppContextRefUnused) + DisposePtr ((Ptr) *ppContextRefUnused); + *ppContextRefUnused = NULL; + return err; +} + +// -------------------------------------------------------------------------- + +// BuildResolutionList + +// builds a list of supported resolutions and frequencies for GDevice + +void BuildResolutionList (GDHandle hGD, Point * pResList, SInt32 * pFreqList) +{ + DSpContextAttributes theContextAttributes; + DSpContextReference currContext; + OSStatus err; + DisplayIDType displayID = 0; + short i; + + for (i = 0; i < kMaxNumRes; i++) // clear resolution list + { + pResList [i].h = 0x7FFF; + pResList [i].v = 0x7FFF; + pFreqList [i] = 0; // some context require certain frequencies find highest for each (not higher than 85 + } + + err = DMGetDisplayIDByGDevice (hGD, &displayID, true); + if (noErr != err) + ReportErrorNum ("DMGetDisplayIDByGDevice error", err); + else + { + if (noErr == DSpReportError (DSpGetFirstContext (displayID, &currContext))) + do + { + // insertion sort into resolution list + if (noErr == DSpReportError (DSpContext_GetAttributes (currContext, &theContextAttributes))) + { + Point pntTemp; + Boolean fDone = false; + short i = 0; + while ((i < kMaxNumRes) && (!fDone)) + { + if ((theContextAttributes.displayWidth == pResList [i].h) && (theContextAttributes.displayHeight == pResList [i].v)) //skip + { + if ((pFreqList [i] == 0) || ((theContextAttributes.frequency <= (kMaxRefreshFreq << 16)) && (theContextAttributes.frequency > pFreqList [i]))) + pFreqList [i] = theContextAttributes.frequency; + break; + } + if (theContextAttributes.displayWidth * theContextAttributes.displayHeight < pResList [i].h * pResList [i].v) //insert + { + pntTemp = pResList [i]; + pResList [i].h = (short) theContextAttributes.displayWidth; + pResList [i].v = (short) theContextAttributes.displayHeight; + pFreqList [i] = theContextAttributes.frequency; + fDone = true; + } + i++; + } + // i points to next element to switch; finish array swaps (if + while ((i < kMaxNumRes) && (fDone)) + { + Point pntSwitch = pResList [i]; + pResList [i++] = pntTemp; + pntTemp = pntSwitch; + } + } + err = DSpGetNextContext (currContext, &currContext); + if (noErr != err) + { + if (kDSpContextNotFoundErr != err) + DSpReportError (err); + currContext = 0; // ensure we drop out + } + } + while (currContext); + else + ReportErrorNum ("DSpGetFirstContext error", err); + } + // zeroize unused elements + for (i = 0; i < kMaxNumRes; i++) + { + if ((pResList [i].h == 0x7FFF) || (pResList [i].v == 0x7FFF)) + { + pResList [i].h = 0; + pResList [i].v = 0; + } + } +} + +// -------------------------------------------------------------------------- + +// DoDeviceRAMCheck + +// checks requested allocation against device RAM +// Note: may modify pcontextInfo +// this should be equal or less strigent than OpenGL actual allocation to avoid failing on valid drawables + +OSStatus DoDeviceRAMCheck (pstructGLInfo pcontextInfo, Point * pResList, SInt32 * pFreqList, GLint depthSizeSupport) +{ + float frontBufferFactor = 1.0f, backBufferFactor = 0.0f; // amount of screen(front) or request(back) sized buffers required, in bytes + Point pntFrontBuffer; // size of front buffer that wil be allocated + short i, indexFrontBuffer; + OSStatus err = noErr; + + // must take into account the entire front buffer, so figure out what screen resolution we are really going to use + // find front buffer for request + i = 0; + while (((pResList [i].h < pcontextInfo->width) || (pResList [i].v < pcontextInfo->height)) && + ((pResList [i].h != 0) || (pResList [i].v != 0)) && + (i < kMaxNumRes)) + i++; + // save front buffer sizes + pntFrontBuffer.h = pResList [i].h; + pntFrontBuffer.v = pResList [i].v; + // if we have a valid frequnecy for the context set it (to ensure a good selection + pcontextInfo->freq = pFreqList [i] >> 16; + indexFrontBuffer = i; + + // front buffers required + if (16 == pcontextInfo->pixelDepth) + frontBufferFactor *= 2.0; + else if (32 == pcontextInfo->pixelDepth) + frontBufferFactor *= 4.0; + + // back buffers required + backBufferFactor = 0.0f; + i = 0; + while (64 > i) + if (AGL_DOUBLEBUFFER == pcontextInfo->aglAttributes[i++]) + { + if (16 == pcontextInfo->pixelDepth) + backBufferFactor = 2.0f; + else if (32 == pcontextInfo->pixelDepth) + backBufferFactor = 4.0f; + break; + } + i = 0; + while (64 > i) + if (AGL_DEPTH_SIZE == pcontextInfo->aglAttributes[i++]) + { + long requestDepth = pcontextInfo->aglAttributes[i]; + GLint bit = 0x00000001; + short currDepth = 0, prevDepth = 0; +// if (depthSizeSupport) +// { + do + { + if (bit & depthSizeSupport) // if the card supports the depth + { + prevDepth = currDepth; + switch (bit) + { + case AGL_1_BIT: + currDepth = 1; + break; + case AGL_2_BIT: + currDepth = 2; + break; + case AGL_3_BIT: + currDepth = 3; + break; + case AGL_4_BIT: + currDepth = 4; + break; + case AGL_5_BIT: + currDepth = 5; + break; + case AGL_6_BIT: + currDepth = 6; + break; + case AGL_8_BIT: + currDepth = 8; + break; + case AGL_10_BIT: + currDepth = 10; + break; + case AGL_12_BIT: + currDepth = 12; + break; + case AGL_16_BIT: + currDepth = 16; + break; + case AGL_24_BIT: + currDepth = 24; + break; + case AGL_32_BIT: + currDepth = 32; + break; + case AGL_48_BIT: + currDepth = 48; + break; + case AGL_64_BIT: + currDepth = 64; + break; + case AGL_96_BIT: + currDepth = 96; + break; + case AGL_128_BIT: + currDepth = 128; + break; + } + } + bit *= 2; + } while (!((requestDepth > prevDepth) && (requestDepth <= currDepth)) && (bit < AGL_128_BIT + 1)); +// } +// else // no card depth support info +// currDepth = requestDepth; // we don't have card info thus assume we can support exact depth requested (may fail later but will always be equal or less stringent) + if ((AGL_128_BIT >= bit) && (0 != currDepth)) + backBufferFactor += (float) currDepth / 8.0; + break; + } + + // What we now have: + // pcontextInfo->width, height: request width and height + // pResList: sorted list of resolutions supported on this display + // pntFrontBuffer : size of front buffer that will currently be allocated + // indexFrontBuffer: position in array of current front buffer request + // frontBufferFactor: number of screen resolution size buffers that will be needed + // backBufferFactor: number of request size buffers that will be needed + + // if we see zero VRAM here we must be looking at the software renderer thus this check is moot. + if (pcontextInfo->VRAM == 0) + { + // no changes required + return noErr; + } + + + // find a context size that can support our texture requirements in the current total VRAM + if ((pcontextInfo->VRAM - pcontextInfo->textureRAM) < (pntFrontBuffer.h * pntFrontBuffer.v * frontBufferFactor + + pcontextInfo->width * pcontextInfo->height * backBufferFactor)) + { + if (pcontextInfo->fDepthMust && pcontextInfo->fSizeMust) + { + // cannot accomdate request + ReportError ("Not enough total VRAM for drawable and textures (depth buffer and pixel size must be as requested)"); + return err; + } + else if (pcontextInfo->fSizeMust) // if we can adjust the size, try adjusting the + { + // try 16 bit if must size is true + if ((pcontextInfo->pixelDepth > 16) && + (pcontextInfo->VRAM - pcontextInfo->textureRAM) > (pntFrontBuffer.h * pntFrontBuffer.v * frontBufferFactor / 2.0 + + pcontextInfo->width * pcontextInfo->height * (backBufferFactor - 2.0))) + pcontextInfo->pixelDepth = 16; + else + { + // cannot accomdate request + ReportError ("Not enough total VRAM for drawable and textures"); + return err; + } + } + else // can adjust size and might be able to adjust depth + { // make drawable fit + Boolean fFound = false; + // see if we can just adjust the pixel depth + if ((pcontextInfo->pixelDepth > 16) && // if we are requesting 32 bit + (!pcontextInfo->fDepthMust) && // if we can adjust the pixel depth + (pcontextInfo->VRAM - pcontextInfo->textureRAM) > (pntFrontBuffer.h * pntFrontBuffer.v * frontBufferFactor / 2.0 + + pcontextInfo->width * pcontextInfo->height * (backBufferFactor - 2.0))) + { + fFound = true; + pcontextInfo->pixelDepth = 16; + } + else // pixel depth alone wont do it + { + i = (short) (indexFrontBuffer - 1); + while (i >= 0) + { + // + if ((pcontextInfo->VRAM - pcontextInfo->textureRAM) > (pResList [i].h * pResList [i].v * frontBufferFactor + + pResList [i].h * pResList [i].v * backBufferFactor)) + { + fFound = true; + pcontextInfo->width = pResList [i].h; + pcontextInfo->height = pResList [i].v; + pcontextInfo->freq = pFreqList [i] >> 16; + break; + } + else if ((pcontextInfo->pixelDepth > 16) && // if we are requesting 32 bit + (!pcontextInfo->fDepthMust) && // if we can adjust the pixel depth + (pcontextInfo->VRAM - pcontextInfo->textureRAM) > (pResList [i].h * pResList [i].v * frontBufferFactor / 2.0 + + pResList [i].h * pResList [i].v * (backBufferFactor - 2.0))) + { + fFound = true; + pcontextInfo->width = pResList [i].h; + pcontextInfo->height = pResList [i].v; + pcontextInfo->freq = pFreqList [i] >> 16; + pcontextInfo->pixelDepth = 16; + break; + } + i--; + } + // we tried the smallest screen size and still need to use less VRAM, adjust backbuffer to what is available + if ((!fFound) && (((pcontextInfo->VRAM - pcontextInfo->textureRAM) - pResList [0].h * pResList [0].v * frontBufferFactor) > 0)) + { + float factor; + fFound = true; + factor = (float) sqrt((float) (pcontextInfo->width * pcontextInfo->height * backBufferFactor) / + (float) ((pcontextInfo->VRAM - pcontextInfo->textureRAM) - pResList [0].h * pResList [0].v * frontBufferFactor)); + pcontextInfo->width /= factor; + pcontextInfo->height /= factor; + pcontextInfo->freq = pFreqList [0] >> 16; + } + } + if (!fFound) + { + // cannot accomdate request + ReportError ("Not enough total VRAM for drawable and textures"); + return err; + } + + } + } + return noErr; +} + +// -------------------------------------------------------------------------- + +// DoContextStepDown + +// steps down through frequencies, depths and sizes to try to find a valid context +// bounded by flags for SizeMust and DepthMust +// Note: may modify pcontextInfo + +Boolean DoContextStepDown (pstructGLInfo pcontextInfo, DSpContextAttributes * pContextAttributes, Point * pResList, SInt32 * pFreqList) +{ + // find current resolution + short i = 0; + while (((pResList [i].h <= pContextAttributes->displayWidth) || (pResList [i].v <= pContextAttributes->displayHeight)) && + ((pResList [i].h != 0) || (pResList [i].v != 0)) && + (i < kMaxNumRes)) + i++; + i--; // i points to index of current resolution + + if (pcontextInfo->fSizeMust) // adjust depth only + { + if (pcontextInfo->pixelDepth > 16) // also try pixel depth step down + { + pContextAttributes->displayBestDepth = 16; + pContextAttributes->backBufferBestDepth = 16; + } + else + return false; // no more options to try + } + else if (pcontextInfo->fDepthMust) // adjust size only + { + if (i > 0) + { + i--; // i was pointing at current resolution, now it is pointing at new resolution to try + // set new resolution + pContextAttributes->displayWidth = pResList [i].h; + pContextAttributes->displayHeight = pResList [i].v; + pcontextInfo->freq = pFreqList [i] >> 16; + } + else + return false; + } + else // adjust size and depth + { + if (pContextAttributes->displayBestDepth > 16) + { + pContextAttributes->displayBestDepth = 16; + pContextAttributes->backBufferBestDepth = 16; + } + else if (i > 0) + { + i--; // i was pointing at current resolution, now it is pointing at new resolution to try + // reset pixel depth + pContextAttributes->displayBestDepth = pcontextInfo->pixelDepth; + pContextAttributes->backBufferBestDepth = pcontextInfo->pixelDepth; + // set new resolution + pContextAttributes->displayWidth = pResList [i].h; + pContextAttributes->displayHeight = pResList [i].v; + pcontextInfo->freq = pFreqList [i] >> 16; + } + else + return false; + + } + return true; +} + +#pragma mark - +// functions (public) ------------------------------------------------------- + +// GetDSpVersion + +// Gets the current version of DSp + +NumVersion GetDSpVersion (void) +{ + NumVersion versionDSp = { 0, 0, 0, 0 }; + OSStatus err = noErr; + if (!gDSpStarted) + err = StartDSp (); + if (noErr == err) + versionDSp = DSpGetVersion (); + return versionDSp; +} + +// -------------------------------------------------------------------------- + +// StartDSp + +// handles starting up DrawSprocket + +OSStatus StartDSp (void) +{ + OSStatus err = noErr; + if (!gDSpStarted) + { + // check for DSp + if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) DSpStartup) + { + ReportError ("DSp not installed"); + return kDSpNotInitializedErr; + } + else + { + err = DSpReportError (DSpStartup()); // start DSp + if (noErr != err) + return err; + else + gDSpStarted = true; + } + } + return err; +} + +// -------------------------------------------------------------------------- + +// ShutdownDSpContext + +// shuts down DrawSprocket + +void ShutdownDSp (void) +{ + if (gDSpStarted) + { + DSpShutdown (); + gDSpStarted = false; + } +} + +#pragma mark - +// -------------------------------------------------------------------------- + +// GetDSpDrawable + +// Just returns the front buffer + +// Inputs: *pdspContext +// pcontextInfo: request and requirements for cotext and drawable + +// Outputs: returns CGrafPtr thaat is front buffer of context + +// if error: will return NULL + +CGrafPtr GetDSpDrawable (DSpContextReference dspContext) +{ + CGrafPtr pCGraf = NULL; + if (noErr == DSpReportError (DSpContext_GetFrontBuffer (dspContext, &pCGraf))) + return pCGraf; + else + return NULL; +} + +// -------------------------------------------------------------------------- + +// BuildDSpContext + +// contextInfo and tries to allocate the corresponding DSp context + +// Inputs: hGD: GDHandle to device to look at +// pcontextInfo: request and requirements for cotext and drawable + +// Outputs: *pdspContext as allocated +// pcontextInfo: allocated parameters + +// if fail to allocate: pdspContext will be NULL +// if error: will return error pdspContext will be NULL + +OSStatus BuildDSpContext (DSpContextReference* pdspContext, GDHandle hGD, GLint depthSizeSupport, pstructGLInfo pcontextInfo) +{ + DSpContextAttributes theContextAttributes, foundAttributes; + DSpContextReference * pContextRefUnused; + SInt32 aFreqList [kMaxNumRes]; + Point aResList [kMaxNumRes]; // list for resolution information + OSStatus err = noErr; + + *pdspContext = 0; + + // check for DSp + if (noErr != StartDSp ()) + { + ReportError ("DSp startup failed"); + return noErr; // already reported + } + + // reserve contexts on other screens to prevent their selection + pContextRefUnused = ReserveUnusedDevices (hGD); + + // build resolution list + BuildResolutionList (hGD, aResList, aFreqList); + + // handle default pixel depths + if (pcontextInfo->pixelDepth == 0) // default + { + pcontextInfo->pixelDepth = (**(**hGD).gdPMap).pixelSize; + if (pcontextInfo->pixelDepth < 16) + pcontextInfo->pixelDepth = 16; + } + +#ifdef kUseRAMCheck + if (noErr != DoDeviceRAMCheck (pcontextInfo, aResList, aFreqList, depthSizeSupport)) + return err; +#endif // kUseRAMCheck + + // Note: DSp < 1.7.3 REQUIRES the back buffer attributes even if only one buffer is required + BlockZero (&theContextAttributes, sizeof (DSpContextAttributes)); +// memset(&theContextAttributes, 0, sizeof (DSpContextAttributes)); + theContextAttributes.displayWidth = pcontextInfo->width; + theContextAttributes.displayHeight = pcontextInfo->height; + theContextAttributes.displayBestDepth = pcontextInfo->pixelDepth; + theContextAttributes.backBufferBestDepth = pcontextInfo->pixelDepth; + do + { + theContextAttributes.frequency = pcontextInfo->freq * 0x10000; + theContextAttributes.colorNeeds = kDSpColorNeeds_Require; + theContextAttributes.displayDepthMask = kDSpDepthMask_All; + theContextAttributes.backBufferDepthMask = kDSpDepthMask_All; + theContextAttributes.pageCount = 1; // only the front buffer is needed + err = DSpFindBestContext(&theContextAttributes, pdspContext); + if (noErr != err) // if we had any errors, reset for next try + if (!DoContextStepDown (pcontextInfo, &theContextAttributes, aResList, aFreqList)) + break; // have run out of options + } while (err == kDSpContextNotFoundErr); + + // check find best context errors + if (kDSpContextNotFoundErr == err) + { + *pdspContext = 0; + return noErr; + } + else if (noErr != err) + { + DSpReportError (err); + *pdspContext = 0; + return err; + } + + err = DSpReportError (DSpContext_GetAttributes (*pdspContext, &foundAttributes)); + if (noErr != err) + { + *pdspContext = 0; + return err; + } + // reset width and height to full screen and handle our own centering + // HWA will not correctly center less than full screen size contexts + theContextAttributes.displayWidth = foundAttributes.displayWidth; + theContextAttributes.displayHeight = foundAttributes.displayHeight; + theContextAttributes.pageCount = 1; // only the front buffer is needed + theContextAttributes.contextOptions = 0 | kDSpContextOption_DontSyncVBL; // no page flipping and no VBL sync needed + + err = DSpReportError (DSpContext_Reserve(*pdspContext, &theContextAttributes )); // reserve our context + if (noErr != err) + { + *pdspContext = 0; + return err; + } + if (gNeedFade == true) + { + DSpReportError (DSpContext_CustomFadeGammaOut (NULL, NULL, fadeTicks)); + gNeedFade = false; + } + err = DSpReportError (DSpContext_SetState (*pdspContext, kDSpContextState_Active)); // activate our context + if (noErr != err) + { + DSpContext_Release (*pdspContext); + DSpReportError (DSpContext_CustomFadeGammaIn (NULL, NULL, fadeTicks)); + *pdspContext = 0; + return err; + } + + FreeUnusedDevices (hGD, &pContextRefUnused); + + if (!pcontextInfo->fSizeMust) // if we got whatever was available + { + // reset inputs to what was allocated (constrain aspect ratio) + // unless we ask for smaller, then leave the same + if ((pcontextInfo->width > foundAttributes.displayWidth) || (pcontextInfo->height > foundAttributes.displayHeight)) + { + float hFactor = (float) pcontextInfo->width / (float) foundAttributes.displayWidth; + float vFactor = (float) pcontextInfo->height / (float) foundAttributes.displayHeight; + if (hFactor > vFactor) + { + pcontextInfo->width = (short) foundAttributes.displayWidth; + pcontextInfo->height /= hFactor; + } + else + { + pcontextInfo->height = (short) foundAttributes.displayHeight; + pcontextInfo->width /= vFactor; + } + } + } + // else still use inputs to allocate drawable + + pcontextInfo->freq = foundAttributes.frequency / 0x10000; + pcontextInfo->pixelDepth = foundAttributes.displayBestDepth; + + return noErr; +} + +//----------------------------------------------------------------------------------------------------------------------- + +// Deactivates and dumps context + +void DestroyDSpContext (DSpContextReference* pdspContext) +{ + if (gDSpStarted) + { + if (*pdspContext) + { + DSpReportError (DSpContext_SetState(*pdspContext, kDSpContextState_Inactive)); + DSpReportError (DSpContext_CustomFadeGammaIn (NULL, NULL, fadeTicks)); + DSpReportError (DSpContext_Release (*pdspContext)); + *pdspContext = NULL; + } + } +} + + +#pragma mark - +//----------------------------------------------------------------------------------------------------------------------- + +OSStatus DSpContext_CustomFadeGammaIn (DSpContextReference inContext, const RGBColor *fadeColor, long fadeTicks) +{ + OSStatus err = noErr; +#ifndef kUseFades + #pragma unused (inContext, fadeColor, fadeTicks) +#else + RGBColor inZeroIntensityColor; + UInt32 currTick; + UInt16 step = (UInt16) (800 / fadeTicks); + long x, percent = 0; + + if (gDSpStarted) + { + if (fadeTicks == 0) + fadeTicks = 1; + if (fadeColor == NULL) + { + inZeroIntensityColor.red = 0x0000; + inZeroIntensityColor.green = 0x0000; + inZeroIntensityColor.blue = 0x0000; + } + else + inZeroIntensityColor = *fadeColor; + currTick = TickCount (); + for (x = 1; x <= fadeTicks; x++) + { + percent = step * x / 8; + err = DSpContext_FadeGamma(inContext, percent, &inZeroIntensityColor); + if (err != noErr) + break; + while (currTick >= TickCount ()) {} +// SystemTask (); + currTick = TickCount (); + } + if (err == noErr) + err = DSpContext_FadeGamma(inContext, 100, &inZeroIntensityColor); + } +#endif // kUseFades + return err; +} + +//----------------------------------------------------------------------------------------------------------------------- + +OSStatus DSpContext_CustomFadeGammaOut (DSpContextReference inContext, const RGBColor *fadeColor, long fadeTicks ) +{ + + OSStatus err = noErr; +#ifndef kUseFades + #pragma unused (inContext, fadeColor, fadeTicks) +#else + RGBColor inZeroIntensityColor; + UInt32 currTick; + UInt16 step = (UInt16) (800 / fadeTicks); + long x, percent = 0; + + if (gDSpStarted) + { + if (fadeTicks == 0) + fadeTicks = 1; // ensure we do not have zero fade time + if (fadeColor == NULL) + { + inZeroIntensityColor.red = 0x0000; + inZeroIntensityColor.green = 0x0000; + inZeroIntensityColor.blue = 0x0000; + } + else + inZeroIntensityColor = *fadeColor; + currTick = TickCount (); + for (x = fadeTicks - 1; x >= 0; x--) + { + percent = step * x / 8; + err = DSpContext_FadeGamma(inContext, percent, &inZeroIntensityColor); + if (err != noErr) + break; + while (currTick >= TickCount ()) {} +// SystemTask (); + currTick = TickCount (); + } + } +#endif // kUseFades + return err; +} diff --git a/api/mac_carbon_dsp.h b/api/mac_carbon_dsp.h new file mode 100755 index 0000000000..7433f4cc1a --- /dev/null +++ b/api/mac_carbon_dsp.h @@ -0,0 +1,128 @@ +// The contents of this file are subject to the Mozilla Public License +// Version 1.0 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://www.mozilla.org/MPL/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations +// under the License. +// +// The Original Code is the Berkeley Open Infrastructure for Network Computing. +// +// The Initial Developer of the Original Code is the SETI@home project. +// Portions created by the SETI@home project are Copyright (C) 2002 +// University of California at Berkeley. All Rights Reserved. +// +// Contributor(s): +// + +/* + Contains: Functions to enable building and destorying a DSp fullscreen context + + Written by: Geoff Stahl (ggs) + + Copyright: Copyright © 1999 Apple Computer, Inc., All Rights Reserved + + Change History (most recent first): + + <2> 3/26/01 ggs Add DSp version check and other items for full screen on X + <1> 1/19/01 ggs Initial re-add + <4> 1/26/00 ggs Add fade code back in, ensure NULL pointer/context checks are in + <3> 1/24/00 ggs Add C++ support + <2> 12/18/99 ggs Fix headers + <1> 11/28/99 ggs Initial add. Split of just DSp handling functions. Added total + device RAM checks, better step downs using actual supported + resolutions. Need to add user verify for contexts that require + it, integration of this in context step down, and a freq bit + field. + <1> 11/11/99 ggs Initial Add + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Adapted to BOINC by Eric Heien +*/ + + +// Usage notes: + + + +// include control -------------------------------------------------- + +#ifndef SetupDSp_h +#define SetupDSp_h + + +// includes --------------------------------------------------------- + +#ifdef __APPLE_CC__ + #include +#else + #include +#endif + +#include "mac_carbon_gl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// structures (public) ----------------------------------------------- + +enum { fadeTicks = 10 }; + +// public function declarations ------------------------------------- + +NumVersion GetDSpVersion (void); +OSStatus StartDSp (void); +void ShutdownDSp (void); + +CGrafPtr GetDSpDrawable (DSpContextReference dspContext); +OSStatus BuildDSpContext (DSpContextReference* pdspContext, GDHandle hGD, GLint depthSizeSupport, pstructGLInfo pcontextInfo); +void DestroyDSpContext (DSpContextReference* pdspContext); + +OSStatus DSpContext_CustomFadeGammaOut (DSpContextReference inContext, const RGBColor *fadeColor, long fadeTicks); +OSStatus DSpContext_CustomFadeGammaIn (DSpContextReference inContext, const RGBColor *fadeColor, long fadeTicks); + +extern Boolean gDSpStarted; +extern Boolean gNeedFade; + +#ifdef __cplusplus +} +#endif + +#endif // SetupDSp_h diff --git a/api/mac_carbon_gl.c b/api/mac_carbon_gl.c new file mode 100755 index 0000000000..9f299c25cb --- /dev/null +++ b/api/mac_carbon_gl.c @@ -0,0 +1,1379 @@ +// The contents of this file are subject to the Mozilla Public License +// Version 1.0 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://www.mozilla.org/MPL/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations +// under the License. +// +// The Original Code is the Berkeley Open Infrastructure for Network Computing. +// +// The Initial Developer of the Original Code is the SETI@home project. +// Portions created by the SETI@home project are Copyright (C) 2002 +// University of California at Berkeley. All Rights Reserved. +// +// Contributor(s): +// + + +/* + Contains: Functions to enable building and destorying a GL full screen or windowed context + + Written by: Geoff Stahl (ggs) + + Copyright: Copyright © 1999 Apple Computer, Inc., All Rights Reserved + + Change History (most recent first): + + <4> 8/23/01 ggs Fixed texture sharing and added number of bug fixes + <3> 4/20/01 ggs Added support for texture sharing by sharing all contexts by default + <2> 3/26/01 ggs Add DSp version check and other items for full screen on X + <1> 1/19/01 ggs Initial re-add + <7> 3/22/00 ggs remove extranious prototype + <6> 3/21/00 ggs Added windowed mode and clean up various implementation details + <5> 1/26/00 ggs Add fade code back in, ensure NULL pointer/context/drawable + checks are in, add Preflight + <4> 1/24/00 ggs Added glFinish to shutdown code + <3> 1/24/00 ggs update to latest, better rendrere info handling for 3dfx, better + checks on pause and resume, added frin devce numer and gdhandle + from point + <2.7> 11/28/99 ggs Split out DSp and error handling. Added texture memory + considerations, assume VRAM is required if other than zero + <2.6> 11/14/99 ggs Fix source server copy + <2.5> 11/13/99 ggs fixed default pixel depth (0) condition that was causing failures + <2.4> 11/13/99 ggs added custom fade code + <2.3> 11/13/99 ggs Reset for Quake 3 use + <2.2> 11/12/99 ggs re-add + <2.1> 11/12/99 ggs added support for frequency retrieval, fixed display number + output to be correct if display number input was -1 + <2> 11/12/99 ggs 1.0 functionality + <1> 11/11/99 ggs Initial Add + + Disclaimer: You may incorporate this sample code into your applications without + restriction, though the sample code has been provided "AS IS" and the + responsibility for its operation is 100% yours. However, what you are + not permitted to do is to redistribute the source as "DSC Sample Code" + after having made changes. If you're going to re-distribute the source, + we require that you make it clear in the source that the code was + descended from Apple Sample Code, but that you've made changes. + + Adapted to BOINC by Eric Heien +*/ + +// system includes ---------------------------------------------------------- + +#ifdef __APPLE_CC__ + #include + #include +#else + #include + #include + #include + #include + #include + #include + #include + #include +#endif + +#include + +// project includes --------------------------------------------------------- + +#include "mac_carbon_dsp.h" +#include "mac_carbon_gl.h" + +extern WindowRef appGLWindow; + +// globals (internal/private) ----------------------------------------------- + +const RGBColor rgbBlack = { 0x0000, 0x0000, 0x0000 }; + +const short kWindowType = kWindowDocumentProc; + +// prototypes (internal/private) -------------------------------------------- + +static Boolean CheckRenderer (GDHandle hGD, long *VRAM, long *textureRAM, GLint* , Boolean fAccelMust); +static Boolean CheckAllDeviceRenderers (long* pVRAM, long* pTextureRAM, GLint* pDepthSizeSupport, Boolean fAccelMust); +static Boolean CheckWindowExtents (GDHandle hGD, short width, short height); +static void DumpCurrent (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext, pstructGLInfo pcontextInfo); + +static OSStatus BuildGLContext (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext, GDHandle hGD, + pstructGLInfo pcontextInfo, AGLContext aglShareContext); +static OSStatus BuildDrawable (AGLDrawable* paglDraw, GDHandle hGD, pstructGLInfo pcontextInfo); +static OSStatus BuildGLonDevice (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext, + GDHandle hGD, pstructGLInfo pcontextInfo, AGLContext aglShareContext); +static OSStatus BuildGLonWindow (WindowPtr pWindow, AGLContext* paglContext, pstructGLWindowInfo pcontextInfo, AGLContext aglShareContext); + + +extern void drawGL(WindowPtr pWindow); + + +// functions (internal/private) --------------------------------------------- + +// CheckRenderer + +// looks at renderer attributes it has at least the VRAM is accelerated + +// Inputs: hGD: GDHandle to device to look at +// pVRAM: pointer to VRAM in bytes required; out is actual VRAM if a renderer was found, otherwise it is the input parameter +// pTextureRAM: pointer to texture RAM in bytes required; out is same (implementation assume VRAM returned by card is total so we add texture and VRAM) +// fAccelMust: do we check for acceleration + +// Returns: true if renderer for the requested device complies, false otherwise + +static Boolean CheckRenderer (GDHandle hGD, long* pVRAM, long* pTextureRAM, GLint* pDepthSizeSupport, Boolean fAccelMust) +{ + AGLRendererInfo info, head_info; + GLint inum; + GLint dAccel = 0; + GLint dVRAM = 0, dMaxVRAM = 0; + Boolean canAccel = false, found = false; + head_info = aglQueryRendererInfo(&hGD, 1); + aglReportError (); + if(!head_info) + { + ReportError ("aglQueryRendererInfo error"); + return false; + } + else + { + info = head_info; + inum = 0; + // see if we have an accelerated renderer, if so ignore non-accelerated ones + // this prevents returning info on software renderer when actually we'll get the hardware one + while (info) + { + aglDescribeRenderer(info, AGL_ACCELERATED, &dAccel); + aglReportError (); + if (dAccel) + canAccel = true; + info = aglNextRendererInfo(info); + aglReportError (); + inum++; + } + + info = head_info; + inum = 0; + while (info) + { + aglDescribeRenderer (info, AGL_ACCELERATED, &dAccel); + aglReportError (); + // if we can accel then we will choose the accelerated renderer + // how about compliant renderers??? + if ((canAccel && dAccel) || (!canAccel && (!fAccelMust || dAccel))) + { + aglDescribeRenderer (info, AGL_VIDEO_MEMORY, &dVRAM); // we assume that VRAM returned is total thus add texture and VRAM required + aglReportError (); + if (dVRAM >= (*pVRAM + *pTextureRAM)) + { + if (dVRAM >= dMaxVRAM) // find card with max VRAM + { + aglDescribeRenderer (info, AGL_DEPTH_MODES, pDepthSizeSupport); // which depth buffer modes are supported + aglReportError (); + dMaxVRAM = dVRAM; // store max + found = true; + } + } + } + info = aglNextRendererInfo(info); + aglReportError (); + inum++; + } + } + aglDestroyRendererInfo(head_info); + if (found) // if we found a card that has enough VRAM and meets the accel criteria + { + *pVRAM = dMaxVRAM; // return VRAM + return true; + } + // VRAM will remain to same as it did when sent in + return false; +} + +//----------------------------------------------------------------------------------------------------------------------- + +// CheckAllDeviceRenderers + +// looks at renderer attributes and each device must have at least one renderer that fits the profile + +// Inputs: pVRAM: pointer to VRAM in bytes required; out is actual min VRAM of all renderers found, otherwise it is the input parameter +// pTextureRAM: pointer to texture RAM in bytes required; out is same (implementation assume VRAM returned by card is total so we add texture and VRAM) +// fAccelMust: do we check fro acceleration + +// Returns: true if any renderer for on each device complies (not necessarily the same renderer), false otherwise + +static Boolean CheckAllDeviceRenderers (long* pVRAM, long* pTextureRAM, GLint* pDepthSizeSupport, Boolean fAccelMust) +{ + AGLRendererInfo info, head_info; + GLint inum; + GLint dAccel = 0; + GLint dVRAM = 0, dMaxVRAM = 0; + Boolean canAccel = false, found = false, goodCheck = true; // can the renderer accelerate, did we find a valid renderer for the device, are we still successfully on all the devices looked at + long MinVRAM = 0x8FFFFFFF; // max long + GDHandle hGD = GetDeviceList (); // get the first screen + while (hGD && goodCheck) + { + head_info = aglQueryRendererInfo(&hGD, 1); + aglReportError (); + if(!head_info) + { + ReportError ("aglQueryRendererInfo error"); + return false; + } + else + { + info = head_info; + inum = 0; + // see if we have an accelerated renderer, if so ignore non-accelerated ones + // this prevents returning info on software renderer when actually we'll get the hardware one + while (info) + { + aglDescribeRenderer(info, AGL_ACCELERATED, &dAccel); + aglReportError (); + if (dAccel) + canAccel = true; + info = aglNextRendererInfo(info); + aglReportError (); + inum++; + } + + info = head_info; + inum = 0; + while (info) + { + aglDescribeRenderer(info, AGL_ACCELERATED, &dAccel); + aglReportError (); + // if we can accel then we will choose the accelerated renderer + // how about compliant renderers??? + if ((canAccel && dAccel) || (!canAccel && (!fAccelMust || dAccel))) + { + aglDescribeRenderer(info, AGL_VIDEO_MEMORY, &dVRAM); // we assume that VRAM returned is total thus add texture and VRAM required + aglReportError (); + if (dVRAM >= (*pVRAM + *pTextureRAM)) + { + if (dVRAM >= dMaxVRAM) // find card with max VRAM + { + aglDescribeRenderer(info, AGL_DEPTH_MODES, pDepthSizeSupport); // which depth buffer modes are supported + aglReportError (); + dMaxVRAM = dVRAM; // store max + found = true; + } + } + } + info = aglNextRendererInfo(info); + aglReportError (); + inum++; + } + } + aglDestroyRendererInfo(head_info); + if (found) // if we found a card that has enough VRAM and meets the accel criteria + { + if (MinVRAM > dMaxVRAM) + MinVRAM = dMaxVRAM; // return VRAM + } + else + goodCheck = false; // one device failed thus entire requirement fails + hGD = GetNextDevice (hGD); // get next device + } // while + if (goodCheck) // we check all devices and each was good + { + *pVRAM = MinVRAM; // return VRAM + return true; + } + return false; //at least one device failed to have mins +} + +//----------------------------------------------------------------------------------------------------------------------- + +// CheckWindowExtents + +// checks to see window fits on screen completely + +// Inputs: hGD: GDHandle to device to look at +// width/height: requested width and height of window + +// Returns: true if window and borders fit, false otherwise + +static Boolean CheckWindowExtents (GDHandle hGD, short width, short height) +{ + Rect strucRect, rectWin = {0, 0, 1, 1}; + short deviceHeight = (short) ((**hGD).gdRect.bottom - (**hGD).gdRect.top - GetMBarHeight ()); + short deviceWidth = (short) ((**hGD).gdRect.right - (**hGD).gdRect.left); + short windowWidthExtra, windowHeightExtra; + // build window (not visible) + WindowPtr pWindow = NewCWindow (NULL, &rectWin, "\p", true, kWindowType, (WindowPtr)-1, 0, 0); + + GetWindowBounds (pWindow, kWindowStructureRgn, &strucRect); + windowWidthExtra = (short) ((strucRect.right - strucRect.left) - 1); + windowHeightExtra = (short) ((strucRect.bottom - strucRect.top) - 1); + DisposeWindow (pWindow); + if ((width + windowWidthExtra <= deviceWidth) && + (height + windowHeightExtra <= deviceHeight)) + return true; + return false; +} + +// -------------------------------------------------------------------------- + +// DumpCurrent + +// Kills currently allocated context +// does not care about being pretty (assumes display is likely faded) + +// Inputs: paglDraw, paglContext, pdspContext: things to be destroyed + +void DumpCurrent (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext, pstructGLInfo pcontextInfo) +{ + if (*pdspContext) + DSpReportError (DSpContext_CustomFadeGammaOut (NULL, NULL, fadeTicks)); + + if (*paglContext) + { + aglSetCurrentContext (NULL); + aglReportError (); + aglSetDrawable (*paglContext, NULL); + aglReportError (); + aglDestroyContext (*paglContext); + aglReportError (); + *paglContext = NULL; + } + + if (pcontextInfo->fmt) + { + aglDestroyPixelFormat (pcontextInfo->fmt); // pixel format is no longer needed + aglReportError (); + } + pcontextInfo->fmt = 0; + + if (*paglDraw && !(pcontextInfo->fFullscreen && CheckMacOSX ())) // do not destory a window on DSp if in Mac OS X + // since there is no window built in X + DisposeWindow (GetWindowFromPort (*paglDraw)); + *paglDraw = NULL; + DestroyDSpContext (pdspContext); // fades in, safe to call at all times +} + +#pragma mark - +// -------------------------------------------------------------------------- + +// BuildGLContext + +// Builds OpenGL context + +// Inputs: hGD: GDHandle to device to look at +// pcontextInfo: request and requirements for cotext and drawable + +// Outputs: paglContext as allocated +// pcontextInfo: allocated parameters + +// if fail to allocate: paglContext will be NULL +// if error: will return error paglContext will be NULL + +static OSStatus BuildGLContext (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext, + GDHandle hGD, pstructGLInfo pcontextInfo, AGLContext aglShareContext) +{ + OSStatus err = noErr; + NumVersion versionDSp = GetDSpVersion (); + + if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) aglChoosePixelFormat) // check for existance of OpenGL + { + ReportError ("OpenGL not installed"); + return noErr; + } + + // DSp has problems on Mac OS X with DSp version less than 1.99 so use agl full screen + if ((pcontextInfo->fFullscreen) && (CheckMacOSX ()) && ((versionDSp.majorRev == 0x01) && (versionDSp.minorAndBugRev < 0x99))) // need to set pixel format for full screen + { + short i = 0; + while (pcontextInfo->aglAttributes[i++] != AGL_NONE) {} + i--; // point to AGL_NONE + pcontextInfo->aglAttributes [i++] = AGL_FULLSCREEN; + pcontextInfo->aglAttributes [i++] = AGL_PIXEL_SIZE; + pcontextInfo->aglAttributes [i++] = (SInt32) pcontextInfo->pixelDepth; + pcontextInfo->aglAttributes [i++] = AGL_NONE; + } + + pcontextInfo->fmt = aglChoosePixelFormat (&hGD, 1, pcontextInfo->aglAttributes); // get an appropriate pixel format + aglReportError (); + if (NULL == pcontextInfo->fmt) + { + ReportError("Could not find valid pixel format"); + return noErr; + } + + // using a default method of sharing all the contexts enables texture sharing across these contexts by default + *paglContext = aglCreateContext (pcontextInfo->fmt, aglShareContext); // Create an AGL context + if (AGL_BAD_MATCH == aglGetError()) + *paglContext = aglCreateContext (pcontextInfo->fmt, 0); // unable to sahre context, create without sharing + aglReportError (); + if (NULL == *paglContext) + { + ReportError ("Could not create context"); + return paramErr; + } + if (aglShareContext == NULL) + aglShareContext = *paglContext; + + // set our drawable + + // DSp has problems on Mac OS X use DSp only when version is not less than 1.99 + if ((pcontextInfo->fFullscreen) && (CheckMacOSX ()) && !((versionDSp.majorRev == 0x01) && (versionDSp.minorAndBugRev < 0x99))) // fullscreen X late DSp + { + // use DSp's front buffer on Mac OS X + *paglDraw = GetDSpDrawable (*pdspContext); + // there is a problem in Mac OS X GM CoreGraphics that may not size the port pixmap correctly + // this will check the vertical sizes and offset if required to fix the problem + // this will not center ports that are smaller then a particular resolution + { + short deltaV, deltaH; + Rect portBounds; + PixMapHandle hPix = GetPortPixMap (*paglDraw); + Rect pixBounds = (**hPix).bounds; + GetPortBounds (*paglDraw, &portBounds); + deltaV = (short) ((portBounds.bottom - portBounds.top) - (pixBounds.bottom - pixBounds.top) + + (portBounds.bottom - portBounds.top - pcontextInfo->height) / 2); + deltaH = (short) (-(portBounds.right - portBounds.left - pcontextInfo->width) / 2); + if (deltaV || deltaH) + { + GrafPtr pPortSave; + GetPort (&pPortSave); + SetPort ((GrafPtr)*paglDraw); + // set origin to account for CG offset and if requested drawable smaller than screen rez + SetOrigin (deltaH, deltaV); + SetPort (pPortSave); + } + } + if (!aglSetDrawable (*paglContext, *paglDraw)) // attach the CGrafPtr to the context + return aglReportError (); + } + // DSp has problems on Mac OS X with DSp version less than 1.99 so use agl full screen + else if ((pcontextInfo->fFullscreen) && (CheckMacOSX ()) && ((versionDSp.majorRev == 0x01) && (versionDSp.minorAndBugRev < 0x99))) // fulscreen X early DSp + { + // use aglFullScreen + short display = 0; + if (!aglSetFullScreen (*paglContext, pcontextInfo->width, pcontextInfo->height, 60, display)) // attach fulls screen device to the context + { + ReportError ("SetFullScreen failed"); + aglReportError (); + return paramErr; + } + } + else // not Mac OS X fullscreen: this is for three cases 1) Mac OS 9 windowed 2) Mac OS X windowed 3) Mac OS 9 fullscreen (as you need to build a window on top of DSp for GL to work correctly + { + // build window as late as possible + err = BuildDrawable (paglDraw, hGD, pcontextInfo); + if (err != noErr) + { + ReportError ("Could not build drawable"); + return err; + } + if (!aglSetDrawable (*paglContext, *paglDraw)) // attach the CGrafPtr to the context + return aglReportError (); + } + if(!aglSetCurrentContext (*paglContext)) // make the context the current context + return aglReportError (); + + return err; +} + +// -------------------------------------------------------------------------- + +// BuildDrawable + +// Builds window to be used as drawable + +// Inputs: hGD: GDHandle to device to look at +// pcontextInfo: request and requirements for cotext and drawable + +// Outputs: paglDraw as allocated +// pcontextInfo: allocated parameters + +// if fail to allocate: paglDraw will be NULL +// if error: will return error paglDraw will be NULL + +static OSStatus BuildDrawable (AGLDrawable* paglDraw, GDHandle hGD, pstructGLInfo pcontextInfo) +{ + Rect rectWin; + RGBColor rgbSave; + GrafPtr pGrafSave; + OSStatus err = noErr; + + // center window in our context's gdevice + rectWin.top = (short) ((**hGD).gdRect.top + ((**hGD).gdRect.bottom - (**hGD).gdRect.top) / 2); // v center + rectWin.top -= pcontextInfo->height / 2; + rectWin.left = (short) ((**hGD).gdRect.left + ((**hGD).gdRect.right - (**hGD).gdRect.left) / 2); // h center + rectWin.left -= pcontextInfo->width / 2; + rectWin.right = (short) (rectWin.left + pcontextInfo->width); + rectWin.bottom = (short) (rectWin.top + pcontextInfo->height); + + + if (pcontextInfo->fFullscreen) + *paglDraw = GetWindowPort (NewCWindow (NULL, &rectWin, "\p", 0, plainDBox, (WindowPtr)-1, 0, 0)); + else + *paglDraw = GetWindowPort (NewCWindow (NULL, &rectWin, "\p", 0, kWindowType, (WindowPtr)-1, 0, 0)); + ShowWindow (GetWindowFromPort (*paglDraw)); + GetPort (&pGrafSave); + SetPort ((GrafPtr)*paglDraw); + GetForeColor (&rgbSave); + RGBForeColor (&rgbBlack); + GetWindowBounds (GetWindowFromPort (*paglDraw), kWindowContentRgn, &rectWin); + PaintRect (&rectWin); + RGBForeColor (&rgbSave); // ensure color is reset for proper blitting + SetPort (pGrafSave); + return err; +} + +// -------------------------------------------------------------------------- + +// BuildGLonDevice + +// Takes device single device and tries to build on it + +// Inputs: hGD: GDHandle to device to look at +// *pcontextInfo: request and requirements for cotext and drawable + +// Outputs: *paglDraw, *paglContext and *pdspContext as allocated +// *pcontextInfo: allocated parameters + +// if fail to allocate: paglDraw, paglContext and pdspContext will be NULL +// if error: will return error and paglDraw, paglContext and pdspContext will be NULL +// Note: *paglDraw and *pdspContext can be null is aglFullScreen is used + +static OSStatus BuildGLonDevice (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext, + GDHandle hGD, pstructGLInfo pcontextInfo, AGLContext aglShareContext) +{ + GLint depthSizeSupport; + OSStatus err = noErr; + Boolean fCheckRenderer = false; + NumVersion versionDSp = GetDSpVersion (); + + if (pcontextInfo->fFullscreen) + { + // if we are in 16 or 32 bit mode already, we can check the renderer now (we will double check later) + if (16 <= (**(**hGD).gdPMap).pixelSize) + { + // check for VRAM and accelerated + if (!CheckRenderer (hGD, &(pcontextInfo->VRAM), &(pcontextInfo->textureRAM), &depthSizeSupport, pcontextInfo->fAcceleratedMust)) + { + ReportError ("Renderer check failed"); + return err; + } + else + fCheckRenderer = true; + } + + // only for Mac OS 9 or less and greater than Mac OS X 10.0.2 + // DSp has problems on Mac OS X with DSp version less than 1.99 (10.0.2 or less) + if ((!CheckMacOSX ()) || ((versionDSp.majorRev > 0x01) || ((versionDSp.majorRev == 0x01) && (versionDSp.minorAndBugRev >= 0x99)))) // DSp should be supported in version after 1.98 + { + err = BuildDSpContext (pdspContext, hGD, depthSizeSupport, pcontextInfo); + // we are now faded + if ((err != noErr) || (*pdspContext == NULL)) + { + if (err != noErr) + ReportErrorNum ("BuildDSpContext failed with error:", err); + else + ReportError ("Could not build DrawSprocket context"); + if (*pdspContext) + DSpReportError (DSpContext_CustomFadeGammaIn (NULL, NULL, fadeTicks)); + return err; + } + } + // else we are using aglFullScreen and no DSp work is required + } + else + { + if (pcontextInfo->pixelDepth == 0) // default + { + pcontextInfo->pixelDepth = (**(**hGD).gdPMap).pixelSize; + if (16 > pcontextInfo->pixelDepth) + pcontextInfo->pixelDepth = 16; + } + if (pcontextInfo->fDepthMust && (pcontextInfo->pixelDepth != (**(**hGD).gdPMap).pixelSize)) // device depth must match and does not + { + ReportError ("Pixel Depth does not match device in windowed mode."); + if (*pdspContext) + DSpReportError (DSpContext_CustomFadeGammaIn (NULL, NULL, fadeTicks)); + return err; + } + // copy back the curretn depth + pcontextInfo->pixelDepth = (**(**hGD).gdPMap).pixelSize; + if (!CheckWindowExtents (hGD, pcontextInfo->width, pcontextInfo->height)) + { + ReportError ("Window will not fit on device in windowed mode."); + if (*pdspContext) + DSpReportError (DSpContext_CustomFadeGammaIn (NULL, NULL, fadeTicks)); + return err; + } + } + + // if we have not already checked the renderer, check for VRAM and accelerated + if (!fCheckRenderer) + { + if (!CheckRenderer (hGD, &(pcontextInfo->VRAM), &(pcontextInfo->textureRAM), &depthSizeSupport, pcontextInfo->fAcceleratedMust)) + { + ReportError ("Renderer check failed"); + if (*pdspContext) + DSpReportError (DSpContext_CustomFadeGammaIn (NULL, NULL, fadeTicks)); + return err; + } + } + + // do agl + // need to send device #'s through this + err = BuildGLContext (paglDraw, paglContext, pdspContext, hGD, pcontextInfo, aglShareContext); + + // DSp has problems on Mac OS X with DSp version less than 1.99 + if ((!CheckMacOSX ()) || ((versionDSp.majorRev > 0x01) || ((versionDSp.majorRev == 0x01) && (versionDSp.minorAndBugRev >= 0x99))))// DSp should be supported in version after 1.98 + { + if (*pdspContext) + DSpReportError (DSpContext_CustomFadeGammaIn (NULL, NULL, fadeTicks)); + } + return err; +} + + +// -------------------------------------------------------------------------- + +// BuildGLonDrawable + +// Takes a drawable and tries to build on it + +// Inputs: aglDraw: a valid AGLDrawable +// *pcontextInfo: request and requirements for cotext and drawable + +// Outputs: *paglContext as allocated +// *pcontextInfo: allocated parameters + +// if fail to allocate: paglContext will be NULL +// if error: will return error and paglContext will be NULL + +static OSStatus BuildGLonWindow (WindowPtr pWindow, AGLContext* paglContext, pstructGLWindowInfo pcontextInfo, AGLContext aglShareContext) +{ + GDHandle hGD = NULL; + GrafPtr cgrafSave = NULL; + short numDevices; + GLint depthSizeSupport; + OSStatus err = noErr; + + if (!pWindow || !pcontextInfo) + { + ReportError ("NULL parameter passed to BuildGLonDrawable."); + return paramErr; + } + + GetPort (&cgrafSave); + SetPortWindowPort(pWindow); + + // check renderer VRAM and acceleration + numDevices = FindGDHandleFromWindow (pWindow, &hGD); + if (!pcontextInfo->fDraggable) // if numDevices > 1 then we will only be using the software renderer otherwise check only window device + { + if ((numDevices > 1) || (numDevices == 0)) // this window spans mulitple devices thus will be software only + { + // software renderer + // infinite VRAM, infinite textureRAM, not accelerated + if (pcontextInfo->fAcceleratedMust) + { + ReportError ("Unable to accelerate window that spans multiple devices"); + return err; + } + } + else // not draggable on single device + { + if (!CheckRenderer (hGD, &(pcontextInfo->VRAM), &(pcontextInfo->textureRAM), &depthSizeSupport, pcontextInfo->fAcceleratedMust)) + { + ReportError ("Renderer check failed"); + return err; + } + } + } + // else draggable so must check all for support (each device should have at least one renderer that meets the requirements) + else if (!CheckAllDeviceRenderers (&(pcontextInfo->VRAM), &(pcontextInfo->textureRAM), &depthSizeSupport, pcontextInfo->fAcceleratedMust)) + { + ReportError ("Renderer check failed"); + return err; + } + + // do agl + if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) aglChoosePixelFormat) // check for existance of OpenGL + { + ReportError ("OpenGL not installed"); + return NULL; + } + // we successfully passed the renderer check + + if ((!pcontextInfo->fDraggable && (numDevices == 1))) // not draggable on a single device + pcontextInfo->fmt = aglChoosePixelFormat (&hGD, 1, pcontextInfo->aglAttributes); // get an appropriate pixel format + else + pcontextInfo->fmt = aglChoosePixelFormat (NULL, 0, pcontextInfo->aglAttributes); // get an appropriate pixel format + aglReportError (); + if (NULL == pcontextInfo->fmt) + { + ReportError("Could not find valid pixel format"); + return NULL; + } + + *paglContext = aglCreateContext (pcontextInfo->fmt, aglShareContext); // Create an AGL context + if (AGL_BAD_MATCH == aglGetError()) + *paglContext = aglCreateContext (pcontextInfo->fmt, 0); // unable to sahre context, create without sharing + aglReportError (); + if (NULL == *paglContext) + { + ReportError ("Could not create context"); + return NULL; + } + + if (!aglSetDrawable (*paglContext, GetWindowPort (pWindow))) // attach the CGrafPtr to the context + return aglReportError (); + + if(!aglSetCurrentContext (*paglContext)) // make the context the current context + return aglReportError (); + + SetPort (cgrafSave); + + return err; +} + +#pragma mark - + +// functions (public) ------------------------------------------------------- + +// CheckMacOSX + +// Runtime check to see if we are running on Mac OS X + +// Inputs: None + +// Returns: 0 if < Mac OS X or version number of Mac OS X (10.0 for GM) + +UInt32 CheckMacOSX (void) +{ + UInt32 response; + + if ((Gestalt(gestaltSystemVersion, (SInt32 *) &response) == noErr) && (response >= 0x01000)) + return response; + else + return 0; +} + +// -------------------------------------------------------------------------- + +// PreflightGL + +// Checks for presense of OpenGL and DSp (if required) +// Inputs: checkFullscreen: true if one wants to run fullscreen (which requires DrwSprocket currently) +// Ouputs: true if OpenGL is installed (and DrawSprocket if checkFullscreen is true + +Boolean PreflightGL (Boolean checkFullscreen) +{ + if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) aglChoosePixelFormat) // check for existance of OpenGL + return false; + if (checkFullscreen && ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) DSpStartup)) // check for existance of DSp + return false; + return true; +} + +// -------------------------------------------------------------------------- + +// BuildGL + +// Takes device and geometry request and tries to build best context and drawable +// if device does not work will walk down devices looking for first one that satisfies requirments + +// Inputs: *pnumDevice: 0 any device, # attempt that device first, then any device +// *pcontextInfo: request and requirements for cotext and drawable + +// Outputs: *paglDraw, *paglContext and *pdspContext as allocated +// *pnumDevice to device number in list that was used +// *pcontextInfo: allocated parameters + +// if fail to allocate: paglDraw, paglContext and pdspContext will be NULL +// if error: will return error and paglDraw, paglContext and pdspContext will be NULL + +OSStatus BuildGL (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext, + short* pnumDevice, pstructGLInfo pcontextInfo, AGLContext aglShareContext) +{ + OSStatus err = noErr; + GDHandle hGD = NULL; + structGLInfo contextInfoSave; + + // clear + *paglDraw = NULL; + *paglContext = 0; + *pdspContext = 0; + contextInfoSave = *pcontextInfo; // save info to reset on failures + + // if we are full screen and not on Mac OS X (which will use aglFullScreen) + if (pcontextInfo->fFullscreen) + { + NumVersion versionDSp = GetDSpVersion (); + // DSp has problems on Mac OS X with DSp version less than 1.99 + if ((!CheckMacOSX ()) || ((versionDSp.majorRev > 0x01) || ((versionDSp.majorRev == 0x01) && (versionDSp.minorAndBugRev >= 0x99))))// DSp should be supported in version after 1.98 + { + err = StartDSp (); + if (gDSpStarted) + gNeedFade = true; + else + return err; + } + } + + + //find main device + if (*pnumDevice == -1) + { + GDHandle hDevice; // check number of screens + hGD = GetMainDevice (); + if (NULL != hGD) + { + err = BuildGLonDevice (paglDraw, paglContext, pdspContext, hGD, pcontextInfo, aglShareContext); + // find device number + *pnumDevice = 0; + hDevice = DMGetFirstScreenDevice (true); + do + { + if (hDevice == hGD) + break; + hDevice = DMGetNextScreenDevice (hDevice, true); + (*pnumDevice)++; + } + while (hDevice); + if (!hDevice) + ReportError ("main device match not found"); + } + else + ReportError ("Cannot get main device"); + } + + if ((err != noErr) || (*paglContext == 0)) + { + err = noErr; + DumpCurrent (paglDraw, paglContext, pdspContext, pcontextInfo); // dump what ever partial solution we might have + *pcontextInfo = contextInfoSave; // restore info + //find target device and check this first is one exists + if (*pnumDevice) + { + short i; + hGD = DMGetFirstScreenDevice (true); + for (i = 0; i < *pnumDevice; i++) + { + GDHandle hGDNext = DMGetNextScreenDevice (hGD, true); + if (NULL == hGDNext) // ensure we did not run out of devices + break; // if no more devices drop out + else + hGD = hGDNext; // otherwise continue + } + *pnumDevice = i; // record device we actually got + err = BuildGLonDevice (paglDraw, paglContext, pdspContext, hGD, pcontextInfo, aglShareContext); + } + } + + // while we have not allocated a context or there were errors + if ((err != noErr) || (*paglContext == 0)) + { + err = noErr; + DumpCurrent (paglDraw, paglContext, pdspContext, pcontextInfo); // dump what ever partial solution we might have + *pcontextInfo = contextInfoSave; // restore info + // now look through the devices in order + hGD = DMGetFirstScreenDevice (true); + *pnumDevice = -1; + do + { + (*pnumDevice)++; + err = BuildGLonDevice (paglDraw, paglContext, pdspContext, hGD, pcontextInfo, aglShareContext); + if ((err != noErr) || (*paglDraw == NULL) || (*paglContext == 0)) // reset hGD only if we are not done + { + hGD = DMGetNextScreenDevice (hGD, true); + DumpCurrent (paglDraw, paglContext, pdspContext, pcontextInfo); // dump what ever partial solution we might have + *pcontextInfo = contextInfoSave; // restore info + } + } + while (((err != noErr) || (*paglContext == 0)) && hGD); + } + return err; +} + +// -------------------------------------------------------------------------- + +// DestroyGL + +// Destroys drawable and context +// Ouputs: *paglDraw, *paglContext and *pdspContext should be 0 on exit + +OSStatus DestroyGL (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext, pstructGLInfo pcontextInfo) +{ + if ((!paglContext) || (!*paglContext)) + return paramErr; // not a valid context + glFinish (); + DumpCurrent (paglDraw, paglContext, pdspContext, pcontextInfo); + ShutdownDSp (); // safe to call anytime + return noErr; +} + +//----------------------------------------------------------------------------------------------------------------------- + +// BuildGLFromWindow + +// Takes window in the form of an AGLDrawable and geometry request and tries to build best context + +// Inputs: aglDraw: a valid AGLDrawable (i.e., a WindowPtr) +// *pcontextInfo: request and requirements for cotext and drawable + +// Outputs: *paglContext as allocated +// *pcontextInfo: allocated parameters + +// if fail to allocate: paglContext will be NULL +// if error: will return error and paglContext will be NULL + +OSStatus BuildGLFromWindow (WindowPtr pWindow, AGLContext* paglContext, pstructGLWindowInfo pcontextInfo, AGLContext aglShareContext) +{ + if (!pWindow) + return paramErr; + return BuildGLonWindow (pWindow, paglContext, pcontextInfo, aglShareContext); +} + +// -------------------------------------------------------------------------- + +// DestroyGLFromWindow + +// Destroys context that waas allocated with BuildGLFromWindow +// Ouputs: *paglContext should be NULL on exit + +OSStatus DestroyGLFromWindow (AGLContext* paglContext, pstructGLWindowInfo pcontextInfo) +{ + OSStatus err; + + if ((!paglContext) || (!*paglContext)) + return paramErr; // not a valid context + glFinish (); + aglSetCurrentContext (NULL); + err = aglReportError (); + aglSetDrawable (*paglContext, NULL); + err = aglReportError (); + aglDestroyContext (*paglContext); + err = aglReportError (); + *paglContext = NULL; + + if (pcontextInfo->fmt) + { + aglDestroyPixelFormat (pcontextInfo->fmt); // pixel format is no longer valid + err = aglReportError (); + } + pcontextInfo->fmt = 0; + + return err; +} + +//----------------------------------------------------------------------------------------------------------------------- + +// SuspendFullScreenGL + +// Special suspend function to ensure the the GL window is hidden + +// needs to be reviewed + +OSStatus SuspendFullScreenGL (AGLDrawable aglDraw, AGLContext aglContext) +{ + if (aglDraw && aglContext) // will only have a drawable + { + glFinish (); // must do this to ensure the queue is complete + aglSetCurrentContext (NULL); + HideWindow (GetWindowFromPort (aglDraw)); + return aglReportError (); + } + return noErr; +} + +//----------------------------------------------------------------------------------------------------------------------- + +// ResumeFullScreenGL + +// Needs a special resume function to ensure the the GL window is shown + +// needs to be reviewed + +OSStatus ResumeFullScreenGL (AGLDrawable aglDraw, AGLContext aglContext) +{ + if (aglDraw && aglContext) + { + ShowWindow (GetWindowFromPort (aglDraw)); + aglSetCurrentContext (aglContext); + aglUpdateContext (aglContext); + return aglReportError (); + } + return paramErr; +} + +//----------------------------------------------------------------------------------------------------------------------- + +// PauseGL + +// Pauses gl to allow toolbox drawing + +OSStatus PauseGL (AGLContext aglContext) +{ + if (aglContext) + { + glFinish (); // must do this to ensure the queue is complete + aglSetCurrentContext (NULL); + return aglReportError (); + } + return paramErr; +} + +//----------------------------------------------------------------------------------------------------------------------- + +// ResumeGL + +// resumes gl to allow gl drawing + +OSStatus ResumeGL (AGLContext aglContext) +{ + if (aglContext) + { + aglSetCurrentContext (aglContext); + aglUpdateContext (aglContext); + return aglReportError (); + } + return paramErr; +} + +// -------------------------------------------------------------------------- + +// FindGDHandleFromRect + +// Inputs: a global Rect + +// Outputs: the GDHandle that that Rect is mostly on + +// returns the number of devices that the Rect touches +short FindGDHandleFromRect (Rect * pRect, GDHandle * phgdOnThisDevice) +{ + Rect rectSect; + long greatestArea, sectArea; + short numDevices = 0; + GDHandle hgdNthDevice; + + if (!phgdOnThisDevice) + return NULL; + + *phgdOnThisDevice = NULL; + + hgdNthDevice = GetDeviceList (); + greatestArea = 0; + // check window against all gdRects in gDevice list and remember + // which gdRect contains largest area of window} + while (hgdNthDevice) + { + if (TestDeviceAttribute (hgdNthDevice, screenDevice)) { + if (TestDeviceAttribute (hgdNthDevice, screenActive)) + { + // The SectRect routine calculates the intersection + // of the window rectangle and this gDevice + // rectangle and returns TRUE if the rectangles intersect, + // FALSE if they don't. + SectRect (pRect, &(**hgdNthDevice).gdRect, &rectSect); + // determine which screen holds greatest window area + // first, calculate area of rectangle on current device + sectArea = (long) (rectSect.right - rectSect.left) * (rectSect.bottom - rectSect.top); + if (sectArea > 0) + numDevices++; + if (sectArea > greatestArea) + { + greatestArea = sectArea; // set greatest area so far + *phgdOnThisDevice = hgdNthDevice; // set zoom device + } + hgdNthDevice = GetNextDevice(hgdNthDevice); + } + } + } + return numDevices; +} + +// -------------------------------------------------------------------------- + +// GetWindowDevice + +// Inputs: a valid WindowPtr + +// Outputs: the GDHandle that that window is mostly on + +// returns the number of devices that the windows content touches + +short FindGDHandleFromWindow (WindowPtr pWindow, GDHandle * phgdOnThisDevice) +{ + GrafPtr pgpSave; + Rect rectWind, rectSect; + long greatestArea, sectArea; + short numDevices = 0; + GDHandle hgdNthDevice; + + if (!pWindow || !phgdOnThisDevice) + return NULL; + + *phgdOnThisDevice = NULL; + + GetPort (&pgpSave); + SetPortWindowPort (pWindow); + + GetWindowPortBounds (pWindow, &rectWind); + LocalToGlobal ((Point*)& rectWind.top); // convert to global coordinates + LocalToGlobal ((Point*)& rectWind.bottom); + hgdNthDevice = GetDeviceList (); + greatestArea = 0; + // check window against all gdRects in gDevice list and remember + // which gdRect contains largest area of window} + while (hgdNthDevice) + { + if (TestDeviceAttribute (hgdNthDevice, screenDevice)) { + if (TestDeviceAttribute (hgdNthDevice, screenActive)) + { + // The SectRect routine calculates the intersection + // of the window rectangle and this gDevice + // rectangle and returns TRUE if the rectangles intersect, + // FALSE if they don't. + SectRect (&rectWind, &(**hgdNthDevice).gdRect, &rectSect); + // determine which screen holds greatest window area + // first, calculate area of rectangle on current device + sectArea = (long) (rectSect.right - rectSect.left) * (rectSect.bottom - rectSect.top); + if (sectArea > 0) + numDevices++; + if (sectArea > greatestArea) + { + greatestArea = sectArea; // set greatest area so far + *phgdOnThisDevice = hgdNthDevice; // set zoom device + } + hgdNthDevice = GetNextDevice(hgdNthDevice); + } + } + } + + SetPort (pgpSave); + return numDevices; +} + +//----------------------------------------------------------------------------------------------------------------------- + +// FindDeviceNumFromRect + +// returns the number of the device that the point is on (i.e., where it is in the search order) +// just a ultility to find the number of the device from a point + +short FindDeviceNumFromRect (Rect * pRect) +{ + short displayNum = 0; + GDHandle hgdNthDevice, hgdFoundDevice; + + FindGDHandleFromRect (pRect, &hgdFoundDevice); + + hgdNthDevice = DMGetFirstScreenDevice (true); + while (hgdNthDevice) + { + if (hgdFoundDevice == hgdNthDevice) + break; + hgdNthDevice = DMGetNextScreenDevice(hgdNthDevice, true); + displayNum++; + } // of WHILE + + return displayNum; +} + +//----------------------------------------------------------------------------------------------------------------------- + +// Draw frame rate in current color at current raster positon with provided font display list +// This version handles multiple windows, thus the calling code must track the values of frames and time from call to call +// The application needs to maintain a cstring (32 characters should be fine), frame counter and time for each window, +// but this routine will take care of all updates. + +void MultiWinDrawFrameRate (GLuint fontList, char * cString, long * frames, AbsoluteTime * time) +{ + AbsoluteTime currTime = UpTime (); + float deltaTime = (float) AbsoluteDeltaToDuration (currTime, *time); + if (0 > deltaTime) // if negative microseconds + deltaTime /= -1000000.0; + else // else milliseconds + deltaTime /= 1000.0; + + (*frames)++; + + if (0.5 <= deltaTime) // has update interval passed + { + sprintf (cString, "FPS: %0.1f", (float) *frames / deltaTime); + *time = currTime; // reset for next time interval + *frames = 0; + } + + DrawCStringGL (cString, fontList); +} + +#pragma mark - + +//----------------------------------------------------------------------------------------------------------------------- + +void DrawCStringGL (char * cstrOut, GLuint fontList) +{ + GLint i = 0; + while (cstrOut [i]) + glCallList (fontList + cstrOut[i++]); +} + +//----------------------------------------------------------------------------------------------------------------------- + +GLuint BuildFontGL (AGLContext ctx, GLint fontID, Style face, GLint size) +{ + GLuint listBase = glGenLists (256); + if (aglUseFont (ctx, fontID , face, size, 0, 256, (long) listBase)) + { + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + return listBase; + } + else + { + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glDeleteLists (listBase, 256); + return 0; + } +} + +//----------------------------------------------------------------------------------------------------------------------- + +void DeleteFontGL (GLuint fontList) +{ + if (fontList) + glDeleteLists (fontList, 256); +} + +#pragma mark - +// -------------------------------------------------------------------------- + +// central error reporting + +void ReportErrorNum (char * strError, long numError) +{ + fprintf (stderr, "%s %ld (0x%lx)\n", strError, numError, numError); +} + +// -------------------------------------------------------------------------- + +void ReportError (char * strError) +{ + fprintf (stderr, "%s\n", strError); +} + +//----------------------------------------------------------------------------------------------------------------------- + +OSStatus DSpReportError (OSStatus error) +{ + switch (error) + { + case noErr: + break; + case kDSpNotInitializedErr: + ReportError ("DSp Error: Not initialized"); + break; + case kDSpSystemSWTooOldErr: + ReportError ("DSp Error: system Software too old"); + break; + case kDSpInvalidContextErr: + ReportError ("DSp Error: Invalid context"); + break; + case kDSpInvalidAttributesErr: + ReportError ("DSp Error: Invalid attributes"); + break; + case kDSpContextAlreadyReservedErr: + ReportError ("DSp Error: Context already reserved"); + break; + case kDSpContextNotReservedErr: + ReportError ("DSp Error: Context not reserved"); + break; + case kDSpContextNotFoundErr: + ReportError ("DSp Error: Context not found"); + break; + case kDSpFrameRateNotReadyErr: + ReportError ("DSp Error: Frame rate not ready"); + break; + case kDSpConfirmSwitchWarning: +// ReportError ("DSp Warning: Must confirm switch"); // removed since it is just a warning, add back for debugging + return 0; // don't want to fail on this warning + break; + case kDSpInternalErr: + ReportError ("DSp Error: Internal error"); + break; + case kDSpStereoContextErr: + ReportError ("DSp Error: Stereo context"); + break; + } + return error; +} + +//----------------------------------------------------------------------------------------------------------------------- + +// if error dump agl errors to debugger string, return error + +OSStatus aglReportError (void) +{ + GLenum err = aglGetError(); + if (AGL_NO_ERROR != err) + ReportError ((char *)aglErrorString(err)); + // ensure we are returning an OSStatus noErr if no error condition + if (err == AGL_NO_ERROR) + return noErr; + else + return (OSStatus) err; +} + +//----------------------------------------------------------------------------------------------------------------------- + +// if error dump gl errors to debugger string, return error + +OSStatus glReportError (void) +{ + GLenum err = glGetError(); + switch (err) + { + case GL_NO_ERROR: + break; + case GL_INVALID_ENUM: + ReportError ("GL Error: Invalid enumeration"); + break; + case GL_INVALID_VALUE: + ReportError ("GL Error: Invalid value"); + break; + case GL_INVALID_OPERATION: + ReportError ("GL Error: Invalid operation"); + break; + case GL_STACK_OVERFLOW: + ReportError ("GL Error: Stack overflow"); + break; + case GL_STACK_UNDERFLOW: + ReportError ("GL Error: Stack underflow"); + break; + case GL_OUT_OF_MEMORY: + ReportError ("GL Error: Out of memory"); + break; + } + // ensure we are returning an OSStatus noErr if no error condition + if (err == GL_NO_ERROR) + return noErr; + else + return (OSStatus) err; +} + +// -------------------------------------------------------------------------- + +void DoUpdate (AGLContext aglContext) +{ + if (aglContext) + { + aglSetCurrentContext (aglContext); + aglUpdateContext (aglContext); + + drawGL (appGLWindow); + + aglSwapBuffers(aglContext); // send swap command + } +} + diff --git a/api/mac_carbon_gl.h b/api/mac_carbon_gl.h new file mode 100755 index 0000000000..892596343e --- /dev/null +++ b/api/mac_carbon_gl.h @@ -0,0 +1,243 @@ +// The contents of this file are subject to the Mozilla Public License +// Version 1.0 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://www.mozilla.org/MPL/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations +// under the License. +// +// The Original Code is the Berkeley Open Infrastructure for Network Computing. +// +// The Initial Developer of the Original Code is the SETI@home project. +// Portions created by the SETI@home project are Copyright (C) 2002 +// University of California at Berkeley. All Rights Reserved. +// +// Contributor(s): +// + +/* + Contains: Functions to enable build and destory a GL fullscreen context + + Written by: Geoff Stahl (ggs) + + Copyright: Copyright © 1999 Apple Computer, Inc., All Rights Reserved + + Change History (most recent first): + + <2> 3/26/01 ggs Add DSp version check and other items for full screen on X + <1> 1/19/01 ggs Initial re-add + <7> 3/21/00 ggs Added windowed mode and clean up various implementation details + <6> 1/26/00 ggs Add fade code back in, ensure NULL pointer/context/drawable + checks are in, add Preflight + <5> 1/24/00 ggs Added get device num and get gdhandle from point routines, add + support for compiling from C++ + <4> 12/18/99 ggs Fix headers + <3> 11/28/99 ggs Split out DSp and error handling. Added texture memory + considerations, assume VRAM is required if other than zero + <3> 11/12/99 ggs add pixel format and freq return + <2> 11/12/99 ggs 1.0 Interface complete + <1> 11/11/99 ggs Initial Add + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Adapted to BOINC by Eric Heien +*/ + + +// Usage notes: + + +// include control -------------------------------------------------- + +#ifndef SetupGL_h +#define SetupGL_h + + +// includes --------------------------------------------------------- + +#ifdef __APPLE_CC__ + #include + #include +#else + #include + #include + #include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// structures (public) ----------------------------------------------- + +// structure for creating a fullscreen context +struct structGLInfo // storage for setup info +{ + SInt16 width; // input: width of drawable (screen width in full screen mode), return: actual width allocated + SInt16 height; // input: height of drawable (screen height in full screen mode), return: actual height allocated + Boolean fSizeMust; // input: dspContext must be requested display size (ignored in window mode) + // if fSizeMust display size will not be stepped down to try to find a match, + // if display is stepped down aspect ratio will be maintained for returned size + UInt32 pixelDepth; // input: requested pixel depth + Boolean fDepthMust; // input: pixel depth must be set (if false then current depth will be used if able) + Boolean fFullscreen; // input: use DSp to get fullscreen? (or find full screen renderer) + // if fFullscreen, will search for full screen renderers first then use DSp for others + // unless a device is specified, in which case we will try there first + Boolean fAcceleratedMust; // input: must renderer be accelerated? + GLint aglAttributes[64]; // input: pixel format attributes always required (reset to what was actually allocated) + SInt32 VRAM; // input: minimum VRAM; output: actual (if successful otherwise input) + SInt32 textureRAM; // input: amount of texture RAM required on card; output: same (used in allcoation to ensure enough texture + AGLPixelFormat fmt; // input: none; output pixel format... + SInt32 freq; // input: frequency request for display; output: actual +}; +typedef struct structGLInfo structGLInfo; +typedef struct structGLInfo * pstructGLInfo; + +// structure for creating a context from a window +struct structGLWindowInfo // storage for setup info +{ + Boolean fAcceleratedMust; // input: must renderer be accelerated? + GLint aglAttributes[64]; // input: pixel format attributes always required (reset to what was actually allocated) + SInt32 VRAM; // input: minimum VRAM; output: actual (if successful otherwise input) + SInt32 textureRAM; // input: amount of texture RAM required on card; output: same (used in allcoation to ensure enough texture + AGLPixelFormat fmt; // input: none; output pixel format... + Boolean fDraggable; // input: is window going to be dragable, + // if so renderer check (accel, VRAM, textureRAM) will look at all renderers vice just the current one + // if window is not dragable renderer check will either check the single device or short + // circuit to software if window spans multiple devices + // software renderer is consider to have unlimited VRAM, unlimited textureRAM and to not be accelerated +}; +typedef struct structGLWindowInfo structGLWindowInfo; +typedef struct structGLWindowInfo * pstructGLWindowInfo; + + +// public function declarations ------------------------------------- + +// Runtime check to see if we are running on Mac OS X +// Inputs: None +// Returns: 0 if < Mac OS X or version number of Mac OS X (10.0 for GM) +UInt32 CheckMacOSX (void); + +// Checks for presense of OpenGL and DSp (if required) +// Inputs: checkFullscreen: true if one wants to run fullscreen (which requires DrwSprocket currently) +// Ouputs: true if OpenGL is installed (and DrawSprocket if checkFullscreen is true +Boolean PreflightGL (Boolean checkFullscreen); + +// Takes device # and geometry request and tries to build best context and drawable +// If requested device does not work, will start at first device and walk down devices +// looking for first one that satisfies requirments +// Devices are numbered in order that DMGetFirstScreenDevice/DMGetNextScreenDevice returns, +// fullscreen devices are numbered after this, but they will be searched first if fFullscreen == true, +// they will not be searched in the non-fullscreen case + +// Inputs: *pnumDevice: -1: main device, 0: any device, other #: attempt that device first, then any device +// *pcontextInfo: request and requirements for cotext and drawable + +// Outputs: *paglDraw, *paglContext and *pdspContext as allocated +// *pnumDevice to device number in list that was used +// *pcontextInfo: allocated parameters + +// If fail to build context: paglDraw, paglContext and pdspContext will be NULL +// If fatal error: will return error and paglDraw, paglContext and pdspContext will be NULL +// Note: Errors can be generated internally when a specific device fails, this is normal and these +// will not be returned is a subsequent device succeeds + +OSStatus BuildGL (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext, + short* pnumDevice, pstructGLInfo pcontextInfo, AGLContext aglShareContext); + +// Destroys drawable and context +// Ouputs: *paglDraw, *paglContext and *pdspContext should be 0 on exit + +OSStatus DestroyGL (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext, pstructGLInfo pcontextInfo); + +// same as above except that it takes a window as input and attempts to build requested conext on that +OSStatus BuildGLFromWindow (WindowPtr pWindow, AGLContext* paglContext, pstructGLWindowInfo pcontextInfo, AGLContext aglShareContext); + +// same as above but destorys a context that was associated with an existing window, window is left intacted +OSStatus DestroyGLFromWindow (AGLContext* paglContext, pstructGLWindowInfo pcontextInfo); + +// Special suspend function to ensure the the GL window is hidden +OSStatus SuspendFullScreenGL (AGLDrawable aglDraw, AGLContext aglContext); + +// Special resume function to ensure the the GL window is shown +OSStatus ResumeFullScreenGL (AGLDrawable aglDraw, AGLContext aglContext); + +// Pauses gl to allow toolbox drawing +OSStatus PauseGL (AGLContext aglContext); + +// resumes gl to allow gl drawing +OSStatus ResumeGL (AGLContext aglContext); + +short FindGDHandleFromRect (Rect * pRect, GDHandle * phgdOnThisDevice); + + +short FindGDHandleFromWindow (WindowPtr pWindow, GDHandle * phgdOnThisDevice); + +// returns the number of the device that the rect is mostly is on (i.e., where it is numerically in the search order) +short FindDeviceNumFromRect (Rect * rect); + +void MultiWinDrawFrameRate (GLuint fontList, char * cString, long * frames, AbsoluteTime * time); + +void DrawCStringGL (char * cstrOut, GLuint fontList); + +GLuint BuildFontGL (AGLContext ctx, GLint fontID, Style face, GLint size); +void DeleteFontGL (GLuint fontList); + + +// Error reporter, can be set to report however the application desires +void ReportError (char * strError); + +// Error with numeric code reporter, can be set to report however the application desires +void ReportErrorNum (char * strError, long numError); + +// Handle reporting of DSp errors, error code is passed through +OSStatus DSpReportError (OSStatus error); + +// Handle reporting of agl errors, error code is passed through +OSStatus aglReportError (void); + +// Handle reporting of OpenGL errors, error code is passed through +OSStatus glReportError (void); + +void DoUpdate (AGLContext aglContext); + +#ifdef __cplusplus +} +#endif + +#endif // SetupGL_h diff --git a/checkin_notes b/checkin_notes index d8877491a8..b7f1794528 100755 --- a/checkin_notes +++ b/checkin_notes @@ -2128,3 +2128,15 @@ Eric October 13, 2002 file_names.C scheduler_op.C +Eric October 14, 2002 + - Added initial support for Mac OpenGL graphics, still needs to + be polished and tested (particularly multithreaded aspect) + + api/ + mac_app_opengl.c,h + mac_carbon_dsp.c,h + mac_carbon_gl.c,h + mac_build/ + boinc.pbproj/ + project.pbxproj + diff --git a/mac_build/boinc.pbproj/project.pbxproj b/mac_build/boinc.pbproj/project.pbxproj index bdb6b51837..5e7233db6e 100755 --- a/mac_build/boinc.pbproj/project.pbxproj +++ b/mac_build/boinc.pbproj/project.pbxproj @@ -201,7 +201,7 @@ INSTALL_PATH = "$(HOME)/Applications"; LIBRARY_SEARCH_PATHS = ""; OPTIMIZATION_CFLAGS = "-O0"; - OTHER_CFLAGS = "-DHOSTTYPE=\\\\\\\"MacOSX\\\\\\\" -DHOST=\\\\\\\"MacOSX\\\\\\\" -DVERSION=1 -Dmac -DHAVE_SYS_SOCKET_H -DHAVE_SYS_RESOURCE_H -DHAVE_NETDB_H -DHAVE_UNISTD_H -DHAVE_SYS_WAIT_H -DHAVE_NETINET_IN_H -DHAVE_SIGNAL_H -DHAVE_ARPA_INET_H -DHAVE_SYS_TIME_H -DHAVE_SYS_TYPES_H -DHAVE_DIRENT_H -DHAVE_FCNTL_H -DHAVE_SYS_STAT_H"; + OTHER_CFLAGS = "-DHOSTTYPE=\\\\\\\"MacOSX\\\\\\\" -DHOST=\\\\\\\"MacOSX\\\\\\\" -DVERSION=1 -Dmac -DHAVE_SYS_SOCKET_H -DHAVE_SYS_RESOURCE_H -DHAVE_NETDB_H -DHAVE_UNISTD_H -DHAVE_SYS_WAIT_H -DHAVE_NETINET_IN_H -DHAVE_SIGNAL_H -DHAVE_ARPA_INET_H -DHAVE_SYS_TIME_H -DHAVE_SYS_TYPES_H -DHAVE_DIRENT_H -DHAVE_FCNTL_H -DHAVE_SYS_STAT_H -DHAVE_SYS_SYSCTL_H -DHAVE_SYS_MOUNT_H -DHAVE_SYS_VMMETER_H"; OTHER_LDFLAGS = ""; OTHER_REZFLAGS = ""; PRODUCT_NAME = BOINC; @@ -322,7 +322,6 @@ F54B900A02AC0A0D01FB7237, F54B900B02AC0A0D01FB7237, F54B900C02AC0A0D01FB7237, - F54B900D02AC0A0D01FB7237, F54B900E02AC0A0D01FB7237, F54B900F02AC0A0D01FB7237, F54B901002AC0A0D01FB7237, @@ -1147,7 +1146,6 @@ F54B8FD502AC0A0C01FB7237, F54B8FD602AC0A0C01FB7237, F54B8FD702AC0A0C01FB7237, - F54B8FD802AC0A0C01FB7237, F54B8FD902AC0A0C01FB7237, F54B8FDA02AC0A0C01FB7237, F54B8FDB02AC0A0C01FB7237, @@ -1291,12 +1289,6 @@ path = ../client/log_flags.h; refType = 2; }; - F54B8FD802AC0A0C01FB7237 = { - isa = PBXFileReference; - name = main.C; - path = ../client/main.C; - refType = 2; - }; F54B8FD902AC0A0C01FB7237 = { isa = PBXFileReference; name = message.h; @@ -1543,12 +1535,6 @@ settings = { }; }; - F54B900D02AC0A0D01FB7237 = { - fileRef = F54B8FD802AC0A0C01FB7237; - isa = PBXBuildFile; - settings = { - }; - }; F54B900E02AC0A0D01FB7237 = { fileRef = F54B8FDA02AC0A0C01FB7237; isa = PBXBuildFile; @@ -1778,6 +1764,12 @@ }; F54FF8B6029F2FFC012012A7 = { children = ( + F579BDAB0357F389012012A7, + F579BDAC0357F389012012A7, + F5895D8F0359FDD6012012A7, + F5895D920359FDD6012012A7, + F5895D900359FDD6012012A7, + F5895D910359FDD6012012A7, F59DD6F7032FF0AF01A80164, F59DD6F6032FF0AF01A80164, F5E946F303269BE2012012A7, @@ -1804,7 +1796,7 @@ ); buildSettings = { LIBRARY_SEARCH_PATHS = /usr/lib/gcc/darwin/3.1; - OTHER_CFLAGS = "-Dunix -Dmac -DHAVE_DIRENT_H -DBOINC_APP_GRAPHICS"; + OTHER_CFLAGS = "-Dunix -Dmac -DHAVE_DIRENT_H -DHAVE_SYS_RESOURCE_H -DHAVE_UNISTD_H -DHAVE_SIGNAL_H -DHAVE_SYS_TIME_H -DBOINC_APP_GRAPHICS"; OTHER_LDFLAGS = ""; OTHER_REZFLAGS = ""; PRODUCT_NAME = upper_case; @@ -1854,10 +1846,13 @@ buildActionMask = 2147483647; files = ( F5BFEB8F02D1137F012012A7, - F5E946F803269BEF012012A7, F5E946FA03269BF0012012A7, - F5E946FD03269BF3012012A7, F59DD6FA032FF0AF01A80164, + F579BDAD0357F389012012A7, + F5895D930359FDD6012012A7, + F5895D940359FDD6012012A7, + F5895D9A035A2BEC012012A7, + F5895D9C035A2BEE012012A7, ); isa = PBXHeadersBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -1875,10 +1870,13 @@ F54FF8C2029F304E012012A7, F5BFEB9002D1137F012012A7, F5E946F503269BE2012012A7, - F5E946F703269BEE012012A7, F5E946F903269BF0012012A7, - F5E946FB03269BF2012012A7, F59DD6FB032FF0AF01A80164, + F579BDAE0357F389012012A7, + F5895D950359FDD6012012A7, + F5895D960359FDD6012012A7, + F5895D99035A2BEC012012A7, + F5895D9B035A2BEE012012A7, ); isa = PBXSourcesBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -1895,6 +1893,8 @@ F59DD6FE0330029E01A80164, F5C932E2033257FD01A80164, F5C932E30332580901A80164, + F5895D6503591C6A012012A7, + F5895D6603591C70012012A7, ); isa = PBXFrameworksBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -1930,6 +1930,114 @@ settings = { }; }; + F579BDAB0357F389012012A7 = { + isa = PBXFileReference; + name = mac_app_opengl.h; + path = ../api/mac_app_opengl.h; + refType = 2; + }; + F579BDAC0357F389012012A7 = { + isa = PBXFileReference; + name = mac_app_opengl.c; + path = ../api/mac_app_opengl.c; + refType = 2; + }; + F579BDAD0357F389012012A7 = { + fileRef = F579BDAB0357F389012012A7; + isa = PBXBuildFile; + settings = { + }; + }; + F579BDAE0357F389012012A7 = { + fileRef = F579BDAC0357F389012012A7; + isa = PBXBuildFile; + settings = { + }; + }; + F5895D6503591C6A012012A7 = { + fileRef = F5C5402002BFA6C601BEDAB8; + isa = PBXBuildFile; + settings = { + }; + }; + F5895D6603591C70012012A7 = { + fileRef = F5C5401F02BFA6C601BEDAB8; + isa = PBXBuildFile; + settings = { + }; + }; + F5895D8F0359FDD6012012A7 = { + isa = PBXFileReference; + name = mac_carbon_dsp.h; + path = ../api/mac_carbon_dsp.h; + refType = 2; + }; + F5895D900359FDD6012012A7 = { + isa = PBXFileReference; + name = mac_carbon_gl.h; + path = ../api/mac_carbon_gl.h; + refType = 2; + }; + F5895D910359FDD6012012A7 = { + isa = PBXFileReference; + name = mac_carbon_gl.c; + path = ../api/mac_carbon_gl.c; + refType = 2; + }; + F5895D920359FDD6012012A7 = { + isa = PBXFileReference; + name = mac_carbon_dsp.c; + path = ../api/mac_carbon_dsp.c; + refType = 2; + }; + F5895D930359FDD6012012A7 = { + fileRef = F5895D8F0359FDD6012012A7; + isa = PBXBuildFile; + settings = { + }; + }; + F5895D940359FDD6012012A7 = { + fileRef = F5895D900359FDD6012012A7; + isa = PBXBuildFile; + settings = { + }; + }; + F5895D950359FDD6012012A7 = { + fileRef = F5895D910359FDD6012012A7; + isa = PBXBuildFile; + settings = { + }; + }; + F5895D960359FDD6012012A7 = { + fileRef = F5895D920359FDD6012012A7; + isa = PBXBuildFile; + settings = { + }; + }; + F5895D99035A2BEC012012A7 = { + fileRef = F5EAD479031AF001018E201A; + isa = PBXBuildFile; + settings = { + }; + }; + F5895D9A035A2BEC012012A7 = { + fileRef = F5EAD478031AF001018E201A; + isa = PBXBuildFile; + settings = { + }; + }; + F5895D9B035A2BEE012012A7 = { + fileRef = F5EAD475031AEFF8018E201A; + isa = PBXBuildFile; + settings = { + }; + }; + F5895D9C035A2BEE012012A7 = { + fileRef = F5EAD474031AEFF8018E201A; + isa = PBXBuildFile; + settings = { + }; + }; F59DD6F6032FF0AF01A80164 = { isa = PBXFileReference; path = graphics_api.h; @@ -2124,18 +2232,6 @@ settings = { }; }; - F5E946F703269BEE012012A7 = { - fileRef = F5EAD479031AF001018E201A; - isa = PBXBuildFile; - settings = { - }; - }; - F5E946F803269BEF012012A7 = { - fileRef = F5EAD478031AF001018E201A; - isa = PBXBuildFile; - settings = { - }; - }; F5E946F903269BF0012012A7 = { fileRef = F5755AD302FE063A012012A7; isa = PBXBuildFile; @@ -2148,18 +2244,6 @@ settings = { }; }; - F5E946FB03269BF2012012A7 = { - fileRef = F5EAD475031AEFF8018E201A; - isa = PBXBuildFile; - settings = { - }; - }; - F5E946FD03269BF3012012A7 = { - fileRef = F5EAD474031AEFF8018E201A; - isa = PBXBuildFile; - settings = { - }; - }; F5EAD474031AEFF8018E201A = { isa = PBXFileReference; name = filesys.h;