2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2009 Sam Lantinga
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "SDL_config.h"
25 Written by Darrell Walisser <dwaliss1@purdue.edu>
27 Implementation notes ----------------------------------------------------------------------
29 A bit on GWorlds in VRAM from technote 1182:
31 There are two important things to note about GWorld's allocated in
32 VRAM. First, the base address retrieved through GetPixBaseAddr or
33 read directly from the PixMap structure can become invalid anytime
34 memory is allocated in VRAM. This can occur either by explicit
35 allocations, such as calls to NewGWorld, or by implicit ones, such as
36 those associated with the internal texture allocation of OpenGL. The
37 stored pixel images themselves will still be valid but may have been
38 moved in VRAM, thus rendering any stored base addresses invalid.
39 You should never store an image's base address for longer than is
40 necessary and especially never across calls to NewGWorld or
41 texture-creation routines.
43 Secondly, an offscreen pixel image allocated in VRAM can be
44 purged at system task time by the display driver. This means any
45 time your application yields time such by calling WaitNextEvent or
46 SystemTask you can lose your VRAM GWorld contents. While this
47 happens infrequently, usually associated with display resolution or
48 pixel depth changes you must code for this eventuality. This purge
49 can occur whether or not the GWorld is locked or not. A return value
50 of false from LockPixels, a NULL return value from GetPixBaseAddr
51 or NULL in the baseAddr field of the PixMap mean that the pixel
52 image has been purged. To reallocate it you can either call
53 UpdateGWorld or Dispose your current GWorld through
54 DisposeGWorld and reallocate it via NewGWorld. Either way you must
55 then rebuild the pixel image.
57 ------------------------------------------------------------------------------------
59 Currently, I don't account for (1). In my testing, NewGWorld never invalidated
60 other existing GWorlds in VRAM. However, I do have protection for (2).
61 Namely, I am using GetOSEvent() instead of WaitNextEvent() so that there are no
62 context switches (the app hogs the CPU). Eventually a book-keeping system should
63 be coded to take care of (1) and (2).
65 ------------------------------------------------------------------------------------
67 System requirements (* denotes optional):
70 2. *MacOS 9 or later (but *not* Mac OS X) for hardware accelerated blit / fill
71 3. *May also require certain graphics hardware for (2). I trust that all Apple OEM
72 hardware will work. Third party accelerators may work if they have QuickDraw
73 acceleration in the drivers and the drivers have been updated for OS 9. The current
74 Voodoo 3 drivers (1.0b12) do not work.
78 1. Use SDL_UpdateRects !
80 If no QuickDraw acceleration is present, double-buffered surfaces will use a back buffer
81 in System memory. I recommend you use SDL_UpdateRects with double-buffered surfaces
82 for best performance on these cards, since the overhead is nearly zero for VRAM back buffer.
84 2. Load most-resident surfaces first.
86 If you fill up VRAM or AGP memory, there is no contingency for purging to make room for the next one.
87 Therefore, you should load the surfaces you plan to use the most frequently first.
88 Sooner or later, I will code LRU replacement to help this.
91 Some kind of posterized mode for resolutions < 640x480.
92 Window support / fullscreen toggle.
93 Figure out how much VRAM is available. Put in video->info->video_mem.
97 I can't create a hardware surface the same size as the screen?! How to fix?
103 DSP_TRY_CC_AND_AA - Define if you want to try HWA color-key and alpha blitters
104 HW color-key blitting gives substantial improvements,
105 but hw alpha is neck-and-neck with SDL's soft bitter.
107 DSP_NO_SYNC_VBL - Define for HWA double-buffered surfaces: don't sync
108 pseudo-flip to monitor redraw.
110 DSP_NO_SYNC_OPENGL - Define for OpenGL surfaces: don't sync buffer swap. Synching buffer
111 swap may result in reduced performance, but can eliminate some
114 09/17/00 Lots of little tweaks. Build modelist in reverse order so largest contexts
115 list first. Compared various methods with ROM methods and fixed rez switch
116 crashing bug in GL Tron. (Woohoo!)
119 #define DSP_TRY_CC_AND_AA
121 /* #define DSP_NO_SYNC_VBL */
123 #define DSP_NO_SYNC_OPENGL
126 #if defined(__APPLE__) && defined(__MACH__)
127 #include <Carbon/Carbon.h>
128 #include <DrawSprocket/DrawSprocket.h>
129 #elif TARGET_API_MAC_CARBON && (UNIVERSAL_INTERFACES_VERSION > 0x0335)
131 #include <DrawSprocket.h>
136 #include <DiskInit.h>
137 #include <QDOffscreen.h>
138 #include <DrawSprocket.h>
141 #include "SDL_video.h"
142 #include "SDL_syswm.h"
143 #include "../SDL_sysvideo.h"
144 #include "../SDL_blit.h"
145 #include "../SDL_pixels_c.h"
146 #include "SDL_dspvideo.h"
147 #include "../maccommon/SDL_macgl_c.h"
148 #include "../maccommon/SDL_macwm_c.h"
149 #include "../maccommon/SDL_macmouse_c.h"
150 #include "../maccommon/SDL_macevents_c.h"
152 /* Initialization/Query functions */
153 static int DSp_VideoInit(_THIS, SDL_PixelFormat *vformat);
154 static SDL_Rect **DSp_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
155 static SDL_Surface *DSp_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
156 static int DSp_SetColors(_THIS, int firstcolor, int ncolors,
158 static int DSp_CreatePalette(_THIS);
159 static int DSp_DestroyPalette(_THIS);
160 static void DSp_VideoQuit(_THIS);
162 static int DSp_GetMainDevice (_THIS, GDHandle *device);
163 static void DSp_IsHWAvailable (_THIS, SDL_PixelFormat *vformat);
164 static void DSp_DSpUpdate(_THIS, int numrects, SDL_Rect *sdl_rects);
165 static void DSp_DirectUpdate(_THIS, int numrects, SDL_Rect *sdl_rects);
167 /* Hardware surface functions */
168 static int DSp_SetHWAlpha(_THIS, SDL_Surface *surface, UInt8 alpha);
169 static int DSp_SetHWColorKey(_THIS, SDL_Surface *surface, Uint32 key);
170 static int DSp_NewHWSurface(_THIS, CGrafPtr *port, int depth, int width, int height);
171 static int DSp_AllocHWSurface(_THIS, SDL_Surface *surface);
172 static int DSp_LockHWSurface(_THIS, SDL_Surface *surface);
173 static void DSp_UnlockHWSurface(_THIS, SDL_Surface *surface);
174 static void DSp_FreeHWSurface(_THIS, SDL_Surface *surface);
175 static int DSp_FlipHWSurface(_THIS, SDL_Surface *surface);
176 static int DSp_CheckHWBlit(_THIS, SDL_Surface *src, SDL_Surface *dest);
177 static int DSp_HWAccelBlit(SDL_Surface *src, SDL_Rect *srcrect,
178 SDL_Surface *dst, SDL_Rect *dstrect);
179 static int DSp_FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color);
182 static void DSp_GL_SwapBuffers (_THIS);
185 #if ! TARGET_API_MAC_CARBON
187 #define GetPortPixRowBytes(x) ( (*(x->portPixMap))->rowBytes )
188 #define GetGDevPixMap(x) ((**(x)).gdPMap)
189 #define GetPortPixMap(x) ((*(x)).portPixMap)
191 #define GetPixDepth(y) ((**(y)).pixelSize)
192 //#define GetPixRowBytes(y) ((**(y)).rowBytes)
193 //#define GetPixBaseAddr(y) ((**(y)).baseAddr)
194 #define GetPixCTab(y) ((**(y)).pmTable)
195 #define GetPortBitMapForCopyBits(x) (&(((GrafPtr)(x))->portBits))
198 #define GetPortPixRowBytes(x) (GetPixRowBytes(GetPortPixMap(x)) )
199 #define GetGDevPixMap(x) ((**(x)).gdPMap)
203 typedef struct private_hwdata {
205 GWorldPtr offscreen; // offscreen gworld in VRAM or AGP
207 #ifdef DSP_TRY_CC_AND_AA
208 GWorldPtr mask; // transparent mask
209 RGBColor alpha; // alpha color
210 RGBColor trans; // transparent color
215 typedef private_hwdata private_swdata ; /* have same fields */
217 /* Macintosh toolbox driver bootstrap functions */
219 static int DSp_Available(void)
221 /* Check for DrawSprocket */
222 #if ! TARGET_API_MAC_OSX
223 /* This check is only meaningful if you weak-link DrawSprocketLib */
224 return ((Ptr)DSpStartup != (Ptr)kUnresolvedCFragSymbolAddress);
226 return 1; // DrawSprocket.framework doesn't have it all, but it's there
230 static void DSp_DeleteDevice(SDL_VideoDevice *device)
232 /* -dw- taking no chances with null pointers */
235 if (device->hidden) {
237 if (device->hidden->dspinfo)
238 SDL_free(device->hidden->dspinfo);
240 SDL_free(device->hidden);
246 static SDL_VideoDevice *DSp_CreateDevice(int devindex)
248 SDL_VideoDevice *device;
250 /* Initialize all variables that we clean on shutdown */
251 device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice));
253 SDL_memset(device, 0, sizeof (*device));
254 device->hidden = (struct SDL_PrivateVideoData *)
255 SDL_malloc((sizeof *device->hidden));
257 SDL_memset(device->hidden, 0, sizeof ( *(device->hidden) ) );
259 if ( (device == NULL) || (device->hidden == NULL) ) {
265 SDL_free(device->hidden);
273 /* Allocate DrawSprocket information */
274 device->hidden->dspinfo = (struct DSpInfo *)SDL_malloc(
275 (sizeof *device->hidden->dspinfo));
276 if ( device->hidden->dspinfo == NULL ) {
278 SDL_free(device->hidden);
282 SDL_memset(device->hidden->dspinfo, 0, (sizeof *device->hidden->dspinfo));
284 /* Set the function pointers */
285 device->VideoInit = DSp_VideoInit;
286 device->ListModes = DSp_ListModes;
287 device->SetVideoMode = DSp_SetVideoMode;
288 device->SetColors = DSp_SetColors;
289 device->UpdateRects = NULL;
290 device->VideoQuit = DSp_VideoQuit;
291 device->AllocHWSurface = DSp_AllocHWSurface;
292 device->CheckHWBlit = NULL;
293 device->FillHWRect = NULL;
294 device->SetHWColorKey = NULL;
295 device->SetHWAlpha = NULL;
296 device->LockHWSurface = DSp_LockHWSurface;
297 device->UnlockHWSurface = DSp_UnlockHWSurface;
298 device->FlipHWSurface = DSp_FlipHWSurface;
299 device->FreeHWSurface = DSp_FreeHWSurface;
300 #if SDL_MACCLASSIC_GAMMA_SUPPORT
301 device->SetGammaRamp = Mac_SetGammaRamp;
302 device->GetGammaRamp = Mac_GetGammaRamp;
305 device->GL_MakeCurrent = Mac_GL_MakeCurrent;
306 device->GL_SwapBuffers = DSp_GL_SwapBuffers;
307 device->GL_LoadLibrary = Mac_GL_LoadLibrary;
308 device->GL_GetProcAddress = Mac_GL_GetProcAddress;
310 device->SetCaption = NULL;
311 device->SetIcon = NULL;
312 device->IconifyWindow = NULL;
313 device->GrabInput = NULL;
314 device->GetWMInfo = NULL;
315 device->FreeWMCursor = Mac_FreeWMCursor;
316 device->CreateWMCursor = Mac_CreateWMCursor;
317 device->ShowWMCursor = Mac_ShowWMCursor;
318 device->WarpWMCursor = Mac_WarpWMCursor;
319 device->InitOSKeymap = Mac_InitOSKeymap;
320 device->PumpEvents = Mac_PumpEvents;
322 device->GrabInput = NULL;
323 device->CheckMouseMode = NULL;
325 device->free = DSp_DeleteDevice;
330 VideoBootStrap DSp_bootstrap = {
331 "DSp", "MacOS DrawSprocket",
332 DSp_Available, DSp_CreateDevice
335 /* Use DSp/Display Manager to build mode list for given screen */
336 static SDL_Rect** DSp_BuildModeList (const GDHandle gDevice, int *displayWidth, int *displayHeight)
338 DSpContextAttributes attributes;
339 DSpContextReference context;
340 DisplayIDType displayID;
341 SDL_Rect temp_list [16];
342 SDL_Rect **mode_list;
343 int width, height, i, j;
345 #if TARGET_API_MAC_OSX
350 /* Ask Display Manager for integer id of screen device */
351 if ( DMGetDisplayIDByGDevice (gDevice, &displayID, SDL_TRUE) != noErr ) {
355 /* Get the first possible DSp context on this device */
356 if ( DSpGetFirstContext (displayID, &context) != noErr ) {
360 if ( DSpContext_GetAttributes (context, &attributes) != noErr )
363 *displayWidth = attributes.displayWidth;
364 *displayHeight = attributes.displayHeight;
366 for ( i = 0; i < SDL_arraysize(temp_list); i++ ) {
367 width = attributes.displayWidth;
368 height = attributes.displayHeight;
370 temp_list [i].x = 0 | attributes.displayBestDepth;
372 temp_list [i].w = width;
373 temp_list [i].h = height;
375 /* DSp will report many different contexts with the same width and height. */
376 /* They will differ in bit depth and refresh rate. */
377 /* We will ignore them until we reach one with a different width/height */
378 /* When there are no more contexts to look at, we will quit building the list*/
379 while ( width == attributes.displayWidth && height == attributes.displayHeight ) {
381 OSStatus err = DSpGetNextContext (context, &context);
383 if (err == kDSpContextNotFoundErr)
388 if ( DSpContext_GetAttributes (context, &attributes) != noErr )
391 temp_list [i].x |= attributes.displayBestDepth;
395 i++; /* i was not incremented before kicking out of the loop */
397 mode_list = (SDL_Rect**) SDL_malloc (sizeof (SDL_Rect*) * (i+1));
400 /* -dw- new stuff: build in reverse order so largest sizes list first */
401 for (j = i-1; j >= 0; j--) {
402 mode_list [j] = (SDL_Rect*) SDL_malloc (sizeof (SDL_Rect));
404 SDL_memcpy (mode_list [j], &(temp_list [j]), sizeof (SDL_Rect));
410 mode_list [i] = NULL; /* append null to the end */
420 static void DSp_IsHWAvailable (_THIS, SDL_PixelFormat *vformat)
423 VRAM GWorlds are only available on OS 9 or later.
424 Even with OS 9, some display drivers won't support it,
425 so we create a test GWorld and check for errors.
430 dsp_vram_available = SDL_FALSE;
431 dsp_agp_available = SDL_FALSE;
433 Gestalt ('sysv', &versionSystem);
434 if (0x00000860 < (versionSystem & 0x0000FFFF)) {
440 SetRect (&bounds, 0, 0, 320, 240);
442 #if useDistantHdwrMem && useLocalHdwrMem
443 err = NewGWorld (&offscreen, vformat->BitsPerPixel, &bounds, NULL, SDL_Display, useDistantHdwrMem | noNewDevice);
445 dsp_vram_available = SDL_TRUE;
446 DisposeGWorld (offscreen);
449 err = NewGWorld (&offscreen, vformat->BitsPerPixel, &bounds, NULL, SDL_Display, useLocalHdwrMem | noNewDevice);
451 DisposeGWorld (offscreen);
452 dsp_agp_available = SDL_TRUE;
458 static int DSp_GetMainDevice (_THIS, GDHandle *device)
461 #if TARGET_API_MAC_OSX
462 /* DSpUserSelectContext not available on OS X */
463 *device = GetMainDevice();
467 DSpContextAttributes attrib;
468 DSpContextReference context;
469 DisplayIDType display_id;
470 GDHandle main_device;
471 GDHandle device_list;
473 device_list = GetDeviceList ();
474 main_device = GetMainDevice ();
476 /* Quick check to avoid slower method when only one display exists */
477 if ( (**device_list).gdNextGD == NULL ) {
478 *device = main_device;
482 SDL_memset (&attrib, 0, sizeof (DSpContextAttributes));
484 /* These attributes are hopefully supported on all devices...*/
485 attrib.displayWidth = 640;
486 attrib.displayHeight = 480;
487 attrib.displayBestDepth = 8;
488 attrib.backBufferBestDepth = 8;
489 attrib.displayDepthMask = kDSpDepthMask_All;
490 attrib.backBufferDepthMask = kDSpDepthMask_All;
491 attrib.colorNeeds = kDSpColorNeeds_Require;
492 attrib.pageCount = 1;
494 if (noErr != DMGetDisplayIDByGDevice (main_device, &display_id, SDL_FALSE)) {
495 SDL_SetError ("Display Manager couldn't associate GDevice with a Display ID");
499 /* Put up dialog on main display to select which display to use */
500 if (noErr != DSpUserSelectContext (&attrib, display_id, NULL, &context)) {
501 SDL_SetError ("DrawSprocket couldn't create a context");
505 if (noErr != DSpContext_GetDisplayID (context, &display_id)) {
506 SDL_SetError ("DrawSprocket couldn't get display ID");
510 if (noErr != DMGetGDeviceByDisplayID (display_id, &main_device, SDL_FALSE)) {
511 SDL_SetError ("Display Manager couldn't associate Display ID with GDevice");
515 *device = main_device;
520 static int DSp_VideoInit(_THIS, SDL_PixelFormat *vformat)
522 NumVersion dsp_version = { 0x01, 0x00, 0x00, 0x00 };
524 #if UNIVERSAL_INTERFACES_VERSION > 0x0320
525 dsp_version = DSpGetVersion ();
528 if ( (dsp_version.majorRev == 1 && dsp_version.minorAndBugRev < 0x73) ||
529 (dsp_version.majorRev < 1) ) {
531 /* StandardAlert (kAlertStopAlert, "\pError!",
532 "\pI need DrawSprocket 1.7.3 or later!\n"
533 "You can find a newer version at http://www.apple.com/swupdates.",
536 SDL_SetError ("DrawSprocket version is too old. Need 1.7.3 or later.");
540 if ( DSpStartup () != noErr ) {
541 SDL_SetError ("DrawSprocket couldn't startup");
545 /* Start DSpintosh events */
546 Mac_InitEvents(this);
548 /* Get a handle to the main monitor, or choose one on multiple monitor setups */
549 if ( DSp_GetMainDevice(this, &SDL_Display) < 0)
552 /* Determine pixel format */
553 vformat->BitsPerPixel = GetPixDepth ( (**SDL_Display).gdPMap );
554 dsp_old_depth = vformat->BitsPerPixel;
556 switch (vformat->BitsPerPixel) {
558 vformat->Rmask = 0x00007c00;
559 vformat->Gmask = 0x000003e0;
560 vformat->Bmask = 0x0000001f;
566 if ( DSp_CreatePalette (this) < 0 ) {
567 SDL_SetError ("Could not create palette");
571 /* Get a list of available fullscreen modes */
572 SDL_modelist = DSp_BuildModeList (SDL_Display,
573 &this->info.current_w, &this->info.current_h);
574 if (SDL_modelist == NULL) {
575 SDL_SetError ("DrawSprocket could not build a mode list");
579 /* Check for VRAM and AGP GWorlds for HW Blitting */
580 DSp_IsHWAvailable (this, vformat);
582 this->info.wm_available = 0;
584 if (dsp_vram_available || dsp_agp_available) {
586 this->info.hw_available = SDL_TRUE;
588 this->CheckHWBlit = DSp_CheckHWBlit;
589 this->info.blit_hw = SDL_TRUE;
591 this->FillHWRect = DSp_FillHWRect;
592 this->info.blit_fill = SDL_TRUE;
594 #ifdef DSP_TRY_CC_AND_AA
595 this->SetHWColorKey = DSp_SetHWColorKey;
596 this->info.blit_hw_CC = SDL_TRUE;
598 this->SetHWAlpha = DSp_SetHWAlpha;
599 this->info.blit_hw_A = SDL_TRUE;
607 static SDL_Rect **DSp_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
609 static SDL_Rect *dsp_modes[16];
612 if ( format->BitsPerPixel == 0 )
613 return ( (SDL_Rect**) NULL );
615 while (SDL_modelist[i] != NULL) {
617 if (SDL_modelist[i]->x & format->BitsPerPixel) {
618 dsp_modes[j] = SDL_modelist[i];
629 /* Various screen update functions available */
630 static void DSp_DirectUpdate(_THIS, int numrects, SDL_Rect *rects);
632 #if ! TARGET_API_MAC_OSX
634 static volatile unsigned int retrace_count = 0; /* -dw- need volatile because it updates asychronously */
636 Boolean DSp_VBLProc ( DSpContextReference context, void *ref_con )
640 return 1; /* Darrell, is this right? */
643 static void DSp_SetHWError (OSStatus err, int is_agp)
646 const char *fmt, *mem;
655 fmt = "Hardware surface possible but not enough %s available";
658 fmt = "Hardware surface possible but invalid color depth";
661 fmt = "Hardware surface could not be allocated in %s - unknown error";
664 SDL_snprintf(message, SDL_arraysize(message), fmt, mem);
665 SDL_SetError(message);
667 #endif // TARGET_API_MAC_OSX
669 /* put up a dialog to verify display change */
670 static int DSp_ConfirmSwitch () {
672 /* resource id's for dialog */
673 const int rDialog = 1002;
674 const int bCancel = 1;
680 DialogItemIndex item = 0;
685 dialog = GetNewDialog (rDialog, NULL, (WindowPtr) -1);
689 #if TARGET_API_MAC_CARBON
690 SetPort (GetDialogPort(dialog));
692 SetPort ((WindowPtr) dialog);
695 SetDialogDefaultItem (dialog, bCancel);
696 SetDialogCancelItem (dialog, bCancel);
698 SetEventMask (everyEvent);
699 FlushEvents (everyEvent, 0);
701 /* On MacOS 8.5 or later, we can make the dialog go away after 15 seconds */
702 /* This is good since it's possible user can't even see the dialog! */
703 /* Requires linking to DialogsLib */
704 err = Gestalt(gestaltSystemVersion,&response);
705 if (err == noErr && response >= 0x00000850) {
706 SetDialogTimeout(dialog, bCancel, 15);
711 ModalDialog ( NULL, &item );
713 } while ( item != bCancel && item != bOK && err != noErr);
716 DisposeDialog (dialog);
719 SetEventMask(everyEvent - autoKeyMask);
720 FlushEvents(everyEvent, 0);
725 static void DSp_UnsetVideoMode(_THIS, SDL_Surface *current)
729 if ( current->flags & SDL_OPENGL ) {
733 if (dsp_context != NULL) {
736 DSpContext_GetFrontBuffer (dsp_context, &front);
738 if (front != dsp_back_buffer)
739 DisposeGWorld (dsp_back_buffer);
742 SDL_free(current->hwdata);
744 DSpContext_SetState (dsp_context, kDSpContextState_Inactive );
745 DSpContext_Release (dsp_context);
750 if (SDL_Window != NULL) {
751 DisposeWindow (SDL_Window);
755 current->pixels = NULL;
759 static SDL_Surface *DSp_SetVideoMode(_THIS,
760 SDL_Surface *current, int width, int height, int bpp, Uint32 flags)
763 #if !TARGET_API_MAC_OSX
764 DisplayIDType display_id;
767 DSpContextAttributes attrib;
769 UInt32 rmask = 0, gmask = 0, bmask = 0;
774 int use_dsp_back_buffer;
776 DSp_UnsetVideoMode (this, current);
778 if (bpp != dsp_old_depth)
779 DSp_DestroyPalette (this);
781 double_buf = (flags & SDL_DOUBLEBUF) != 0;
782 hw_surface = (flags & SDL_HWSURFACE) != 0;
783 use_dsp_back_buffer = !dsp_vram_available || !hw_surface ;
785 current->flags |= SDL_FULLSCREEN;
789 if ( double_buf && use_dsp_back_buffer ) {
795 SDL_memset (&attrib, 0, sizeof (DSpContextAttributes));
796 attrib.displayWidth = width;
797 attrib.displayHeight = height;
798 attrib.displayBestDepth = bpp;
799 attrib.backBufferBestDepth = bpp;
800 attrib.displayDepthMask = kDSpDepthMask_All;
801 attrib.backBufferDepthMask = kDSpDepthMask_All;
802 attrib.colorNeeds = kDSpColorNeeds_Require;
803 attrib.colorTable = 0;
804 attrib.pageCount = page_count;
805 #if TARGET_API_MAC_OSX || UNIVERSAL_INTERFACES_VERSION == 0x0320
807 if ( DSpFindBestContext (&attrib, &dsp_context) != noErr ) {
808 SDL_SetError ("DrawSprocket couldn't find a context");
813 if ( noErr != DMGetDisplayIDByGDevice (SDL_Display, &display_id, SDL_FALSE) ) {
814 SDL_SetError ("Display Manager couldn't associate GDevice with display_id");
817 if ( DSpFindBestContextOnDisplayID(&attrib, &dsp_context, display_id) != noErr ) {
818 SDL_SetError ("DrawSprocket couldn't find a suitable context on given display");
823 if ( DSpContext_Reserve (dsp_context, &attrib) != noErr ) {
824 SDL_SetError ("DrawSprocket couldn't get the needed resources to build the display");
828 if ( (err = DSpContext_SetState (dsp_context, kDSpContextState_Active)) != noErr ) {
830 if (err == kDSpConfirmSwitchWarning) {
832 if ( ! DSp_ConfirmSwitch () ) {
834 DSpContext_Release (dsp_context);
836 SDL_SetError ("User cancelled display switch");
840 /* Have to reactivate context. Why? */
841 DSpContext_SetState (dsp_context, kDSpContextState_Active);
845 SDL_SetError ("DrawSprocket couldn't activate the context");
851 if (bpp != dsp_old_depth) {
853 DSp_CreatePalette (this);
855 /* update format if display depth changed */
862 if ( ! SDL_ReallocFormat (current, bpp, rmask, gmask, bmask, 0 ) ) {
864 SDL_SetError ("Could not reallocate video format.");
871 /* single-buffer context */
872 DSpContext_GetFrontBuffer (dsp_context, &dsp_back_buffer);
874 current->hwdata = (private_hwdata*) SDL_malloc (sizeof (private_hwdata));
875 if (current ->hwdata == NULL) {
879 current->hwdata->offscreen = dsp_back_buffer;
880 current->flags |= SDL_HWSURFACE;
881 this->UpdateRects = DSp_DirectUpdate;
883 else if ( use_dsp_back_buffer ) {
885 DSpContext_GetBackBuffer (dsp_context, kDSpBufferKind_Normal, &dsp_back_buffer);
887 current->flags |= SDL_DOUBLEBUF | SDL_SWSURFACE; /* only front buffer is in VRAM */
888 this->UpdateRects = DSp_DSpUpdate;
890 else if ( DSp_NewHWSurface(this, &dsp_back_buffer, bpp, width-1, height-1) == 0 ) {
892 current->hwdata = (private_hwdata*) SDL_malloc (sizeof (private_hwdata));
893 if (current ->hwdata == NULL) {
898 SDL_memset (current->hwdata, 0, sizeof (private_hwdata));
899 current->hwdata->offscreen = dsp_back_buffer;
900 current->flags |= SDL_DOUBLEBUF | SDL_HWSURFACE;
901 this->UpdateRects = DSp_DirectUpdate; /* hardware doesn't do update rects, must be page-flipped */
905 DSpContext_Release (dsp_context);
906 use_dsp_back_buffer = SDL_TRUE;
910 current->pitch = GetPortPixRowBytes(dsp_back_buffer) & 0x3FFF;
911 current->pixels = GetPixBaseAddr(GetPortPixMap(dsp_back_buffer));
916 #if ! TARGET_API_MAC_OSX
918 if (use_dsp_back_buffer) {
920 DSpContext_GetMonitorFrequency (dsp_context, &freq);
921 DSpContext_SetMaxFrameRate (dsp_context, freq >> 16);
925 if ( (current->flags & SDL_HWSURFACE) || (current->flags & SDL_OPENGL) )
926 DSpContext_SetVBLProc (dsp_context, DSp_VBLProc, NULL);
930 current->flags |= SDL_HWPALETTE;
932 if (flags & SDL_OPENGL) {
935 RGBColor rgb = { 0.0, 0.0, 0.0 };
938 SetRect (&rect, 0, 0, width, height);
939 SDL_Window = NewCWindow(nil, &( (**SDL_Display).gdRect), "\p", SDL_TRUE, plainDBox, (WindowPtr)-1, SDL_FALSE, 0);
941 if (SDL_Window == NULL) {
943 SDL_SetError ("DSp_SetVideoMode : OpenGL window could not be created.");
947 /* Set window color to black to avoid white flash*/
948 GetPort (&save_port);
949 #if TARGET_API_MAC_CARBON
950 SetPort (GetWindowPort(SDL_Window));
952 SetPort (SDL_Window);
958 SetPortWindowPort (SDL_Window);
959 SelectWindow (SDL_Window);
961 if ( Mac_GL_Init (this) < 0 ) {
963 SDL_SetError ("DSp_SetVideoMode : could not create OpenGL context.");
967 current->flags |= SDL_OPENGL;
973 #ifdef DSP_TRY_CC_AND_AA
975 static int DSp_MakeHWMask (_THIS, SDL_Surface *surface)
977 GDHandle save_device;
980 RGBColor black = { 0, 0, 0 };
981 RGBColor white = { 0xFFFF, 0xFFFF, 0xFFFF };
984 Uint32 depth = GetPixDepth ( GetGDevPixMap (SDL_Display) );
986 SetRect (&rect, 0, 0, surface->w, surface->h);
988 if ( noErr != NewGWorld (&(surface->hwdata->mask), depth, &rect, 0, SDL_Display, 0 ) < 0 ) {
994 if ( noErr != NewGWorld (&temp, depth, &rect, 0 , SDL_Display, 0 ) ) {
1001 GetGWorld (&save_port, &save_device);
1002 SetGWorld (surface->hwdata->mask, SDL_Display);
1004 RGBForeColor (&white);
1007 RGBBackColor (&(surface->hwdata->trans));
1009 CopyBits ( GetPortBitMapForCopyBits(surface->hwdata->offscreen),
1010 GetPortBitMapForCopyBits(surface->hwdata->mask),
1011 &rect, &rect, transparent, NULL );
1013 SetGWorld (surface->hwdata->mask, SDL_Display);
1014 SetGWorld (save_port, save_device);
1018 static int DSp_SetHWAlpha(_THIS, SDL_Surface *surface, UInt8 alpha)
1020 surface->hwdata->alpha.red = (alpha / 255.0) * 65535;
1021 surface->hwdata->alpha.blue = (alpha / 255.0) * 65535;
1022 surface->hwdata->alpha.green = (alpha / 255.0) * 65535;
1024 surface->flags |= SDL_SRCALPHA;
1026 if (surface->flags & SDL_SRCCOLORKEY) {
1027 return(DSp_MakeHWMask (this, surface));
1032 static int DSp_SetHWColorKey(_THIS, SDL_Surface *surface, Uint32 key)
1035 GDHandle save_device;
1037 GetGWorld (&save_port, &save_device);
1038 SetGWorld (surface->hwdata->offscreen, NULL);
1040 Index2Color (key, &(surface->hwdata->trans));
1041 surface->flags |= SDL_SRCCOLORKEY;
1043 SetGWorld (save_port, save_device);
1045 if ( surface->flags & SDL_SRCALPHA ) {
1046 return(DSp_MakeHWMask (this, surface));
1051 #endif /* DSP_TRY_CC_AND_AA */
1053 static int DSp_NewHWSurface(_THIS, CGrafPtr *port, int depth, int width, int height) {
1058 SetRect (&bounds, 0, 0, width, height);
1060 #if useDistantHdwrMem && useLocalHdwrMem
1061 if (dsp_vram_available) {
1063 err = NewGWorld (port, depth, &bounds, 0 , SDL_Display, useDistantHdwrMem | noNewDevice );
1065 DSp_SetHWError (err, SDL_FALSE);
1070 if (dsp_agp_available) {
1072 err = NewGWorld (port, depth, &bounds, 0 , SDL_Display, useLocalHdwrMem | noNewDevice );
1075 DSp_SetHWError (err, SDL_TRUE);
1084 static int DSp_AllocHWSurface(_THIS, SDL_Surface *surface)
1088 if ( DSp_NewHWSurface (this, &temp, surface->format->BitsPerPixel, surface->w, surface->h) < 0 )
1091 surface->hwdata = (private_hwdata*) SDL_malloc (sizeof (private_hwdata));
1092 if (surface->hwdata == NULL) {
1097 SDL_memset (surface->hwdata, 0, sizeof(private_hwdata));
1098 surface->hwdata->offscreen = temp;
1099 surface->pitch = GetPixRowBytes (GetPortPixMap (temp)) & 0x3FFF;
1100 surface->pixels = GetPixBaseAddr (GetPortPixMap (temp));
1101 surface->flags |= SDL_HWSURFACE;
1102 #ifdef DSP_TRY_CC_AND_AA
1103 surface->flags |= SDL_HWACCEL;
1108 static void DSp_FreeHWSurface(_THIS, SDL_Surface *surface)
1110 if (surface->hwdata->offscreen != NULL)
1111 DisposeGWorld (surface->hwdata->offscreen);
1112 SDL_free(surface->hwdata);
1114 surface->pixels = NULL;
1117 static int DSp_CheckHWBlit(_THIS, SDL_Surface *src, SDL_Surface *dest)
1121 /* Set initial acceleration on */
1122 src->flags |= SDL_HWACCEL;
1124 /* Set the surface attributes */
1125 if ( (src->flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
1126 if ( ! this->info.blit_hw_A ) {
1127 src->flags &= ~SDL_HWACCEL;
1130 if ( (src->flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) {
1131 if ( ! this->info.blit_hw_CC ) {
1132 src->flags &= ~SDL_HWACCEL;
1136 /* Check to see if final surface blit is accelerated */
1137 accelerated = !!(src->flags & SDL_HWACCEL);
1138 if ( accelerated ) {
1139 src->map->hw_blit = DSp_HWAccelBlit;
1141 return(accelerated);
1144 static int DSp_HWAccelBlit(SDL_Surface *src, SDL_Rect *srcrect,
1145 SDL_Surface *dst, SDL_Rect *dstrect)
1148 GDHandle save_device;
1149 Rect src_rect, dst_rect;
1150 RGBColor black = { 0, 0, 0 };
1151 RGBColor white = { 0xFFFF, 0xFFFF, 0xFFFF };
1153 #ifdef DSP_TRY_CC_AND_AA
1157 SetRect (&src_rect, srcrect->x, srcrect->y, srcrect->x + srcrect->w, srcrect->y + srcrect->h);
1158 SetRect (&dst_rect, dstrect->x, dstrect->y, dstrect->x + dstrect->w, dstrect->y + dstrect->h);
1160 GetGWorld (&save_port, &save_device);
1161 SetGWorld (dst->hwdata->offscreen, NULL);
1163 RGBForeColor (&black);
1164 RGBBackColor (&white);
1166 #ifdef DSP_TRY_CC_AND_AA
1168 if ( (src->flags & SDL_SRCCOLORKEY) &&
1169 (src->flags & SDL_SRCALPHA) ) {
1171 OpColor (&(src->hwdata->alpha));
1173 CopyDeepMask ( GetPortBitMapForCopyBits(src->hwdata->offscreen),
1174 GetPortBitMapForCopyBits(src->hwdata->mask),
1175 GetPortBitMapForCopyBits(dst->hwdata->offscreen),
1176 &src_rect, &src_rect, &dst_rect,
1182 if ( src->flags & SDL_SRCCOLORKEY) {
1183 RGBBackColor (&(src->hwdata->trans) );
1186 else if (src->flags & SDL_SRCALPHA) {
1188 OpColor (&(src->hwdata->alpha));
1196 CopyBits ( GetPortBitMapForCopyBits(src->hwdata->offscreen),
1197 GetPortBitMapForCopyBits(dst->hwdata->offscreen),
1198 &src_rect, &dst_rect, mode, NULL );
1202 CopyBits ( &(((GrafPtr)(src->hwdata->offscreen))->portBits),
1203 &(((GrafPtr)(dst->hwdata->offscreen))->portBits),
1204 &src_rect, &dst_rect, srcCopy, NULL );
1206 #endif /* DSP_TRY_CC_AND_AA */
1208 SetGWorld (save_port, save_device);
1213 static int DSp_FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color)
1216 GDHandle save_device;
1220 SetRect (&fill_rect, rect->x, rect->y, rect->x + rect->w, rect->y + rect->h);
1222 GetGWorld (&save_port, &save_device);
1223 SetGWorld (dst->hwdata->offscreen, NULL);
1225 Index2Color (color, &rgb);
1227 RGBForeColor (&rgb);
1228 PaintRect (&fill_rect);
1230 SetGWorld (save_port, save_device);
1235 static int DSp_FlipHWSurface(_THIS, SDL_Surface *surface)
1237 if ( (surface->flags & SDL_HWSURFACE) ) {
1238 CGrafPtr dsp_front_buffer, save_port;
1241 #if ! TARGET_API_MAC_OSX
1242 unsigned int old_count;
1245 /* pseudo page flipping for VRAM back buffer*/
1246 DSpContext_GetFrontBuffer (dsp_context, &dsp_front_buffer);
1247 SetRect (&rect, 0, 0, surface->w-1, surface->h-1);
1249 GetPort ((GrafPtr *)&save_port);
1250 SetPort ((GrafPtr)dsp_front_buffer);
1252 /* wait for retrace */
1253 /* I have tried doing the swap in interrupt routine (VBL Proc) to do */
1254 /* it asynchronously, but apparently CopyBits isn't interrupt safe */
1256 #if ! TARGET_API_MAC_OSX
1257 #ifndef DSP_NO_SYNC_VBL
1258 old_count = retrace_count;
1259 while (old_count == retrace_count)
1264 CopyBits ( GetPortBitMapForCopyBits(dsp_back_buffer),
1265 GetPortBitMapForCopyBits(dsp_front_buffer),
1266 &rect, &rect, srcCopy, NULL );
1268 SetPort ((GrafPtr)save_port);
1271 /* not really page flipping at all: DSp just blits the dirty rectangles from DSp_UpdateRects */
1273 DSpContext_SwapBuffers (dsp_context, NULL, &busy_flag); /* this waits for VBL */
1274 DSpContext_GetBackBuffer (dsp_context, kDSpBufferKind_Normal, &dsp_back_buffer);
1275 surface->pixels = GetPixBaseAddr( GetPortPixMap(dsp_back_buffer) );
1280 static int DSp_LockHWSurface(_THIS, SDL_Surface *surface)
1282 if ( LockPixels (GetGWorldPixMap (surface->hwdata->offscreen)) )
1288 static void DSp_UnlockHWSurface(_THIS, SDL_Surface *surface)
1290 UnlockPixels (GetGWorldPixMap (surface->hwdata->offscreen));
1293 static void DSp_DirectUpdate(_THIS, int numrects, SDL_Rect *sdl_rects)
1298 static void DSp_DSpUpdate(_THIS, int numrects, SDL_Rect *sdl_rects)
1300 #if ! TARGET_API_MAC_OSX /* Unsupported DSp in here */
1304 for (i = 0; i < numrects; i++) {
1306 rect.top = sdl_rects[i].y;
1307 rect.left = sdl_rects[i].x;
1308 rect.bottom = sdl_rects[i].h + sdl_rects[i].y;
1309 rect.right = sdl_rects[i].w + sdl_rects[i].x;
1311 DSpContext_InvalBackBufferRect (dsp_context, &rect);
1316 static int DSp_CreatePalette(_THIS) {
1319 /* Create our palette */
1320 SDL_CTab = (CTabHandle)NewHandle(sizeof(ColorSpec)*256 + 8);
1321 if ( SDL_CTab == nil ) {
1325 (**SDL_CTab).ctSeed = GetCTSeed();
1326 (**SDL_CTab).ctFlags = 0;
1327 (**SDL_CTab).ctSize = 255;
1328 CTabChanged(SDL_CTab);
1329 SDL_CPal = NewPalette(256, SDL_CTab, pmExplicit+pmTolerant, 0);
1334 static int DSp_DestroyPalette(_THIS) {
1336 /* Free palette and restore original one */
1337 if ( SDL_CTab != nil ) {
1338 DisposeHandle((Handle)SDL_CTab);
1341 if ( SDL_CPal != nil ) {
1342 DisposePalette(SDL_CPal);
1345 RestoreDeviceClut(SDL_Display);
1350 static int DSp_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
1358 /* Verify the range of colors */
1359 if ( (firstcolor+ncolors) > ((**cTab).ctSize+1) ) {
1363 /* Set the screen palette and update the display */
1364 for(i = 0; i < ncolors; i++) {
1365 int j = firstcolor + i;
1366 (**cTab).ctTable[j].value = j;
1367 (**cTab).ctTable[j].rgb.red = colors[i].r << 8 | colors[i].r;
1368 (**cTab).ctTable[j].rgb.green = colors[i].g << 8 | colors[i].g;
1369 (**cTab).ctTable[j].rgb.blue = colors[i].b << 8 | colors[i].b;
1372 SetGDevice(SDL_Display);
1373 SetEntries(0, (**cTab).ctSize, (ColorSpec *)&(**cTab).ctTable);
1378 void DSp_VideoQuit(_THIS)
1382 /* Free current video mode */
1383 DSp_UnsetVideoMode(this, this->screen);
1385 /* Free Palette and restore original */
1386 DSp_DestroyPalette (this);
1388 #if SDL_MACCLASSIC_GAMMA_SUPPORT
1389 Mac_QuitGamma(this);
1392 /* Free list of video modes */
1393 if ( SDL_modelist != NULL ) {
1394 for ( i=0; SDL_modelist[i]; i++ ) {
1395 SDL_free(SDL_modelist[i]);
1397 SDL_free(SDL_modelist);
1398 SDL_modelist = NULL;
1401 /* Unload DrawSprocket */
1405 #if SDL_VIDEO_OPENGL
1407 /* swap buffers with v-sync */
1408 static void DSp_GL_SwapBuffers (_THIS) {
1410 #ifndef DSP_NO_SYNC_OPENGL
1412 unsigned int old_count;
1414 old_count = retrace_count;
1415 while (old_count == retrace_count)
1419 aglSwapBuffers (glContext);