This repository has been archived by the owner on Feb 11, 2021. It is now read-only.
/
SDL_dspvideo.c
1480 lines (1164 loc) · 41.2 KB
1
2
/*
SDL - Simple DirectMedia Layer
3
Copyright (C) 1997-2006 Sam Lantinga
4
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.
9
10
11
12
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
Lesser General Public License for more details.
14
15
16
17
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19
Sam Lantinga
20
slouken@libsdl.org
21
*/
22
#include "SDL_config.h"
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/*
Written by Darrell Walisser <dwaliss1@purdue.edu>
Implementation notes ----------------------------------------------------------------------
A bit on GWorlds in VRAM from technote 1182:
There are two important things to note about GWorld's allocated in
VRAM. First, the base address retrieved through GetPixBaseAddr or
read directly from the PixMap structure can become invalid anytime
memory is allocated in VRAM. This can occur either by explicit
allocations, such as calls to NewGWorld, or by implicit ones, such as
those associated with the internal texture allocation of OpenGL. The
stored pixel images themselves will still be valid but may have been
moved in VRAM, thus rendering any stored base addresses invalid.
You should never store an image's base address for longer than is
necessary and especially never across calls to NewGWorld or
texture-creation routines.
Secondly, an offscreen pixel image allocated in VRAM can be
purged at system task time by the display driver. This means any
time your application yields time such by calling WaitNextEvent or
SystemTask you can lose your VRAM GWorld contents. While this
happens infrequently, usually associated with display resolution or
pixel depth changes you must code for this eventuality. This purge
can occur whether or not the GWorld is locked or not. A return value
of false from LockPixels, a NULL return value from GetPixBaseAddr
or NULL in the baseAddr field of the PixMap mean that the pixel
image has been purged. To reallocate it you can either call
UpdateGWorld or Dispose your current GWorld through
DisposeGWorld and reallocate it via NewGWorld. Either way you must
then rebuild the pixel image.
------------------------------------------------------------------------------------
Currently, I don't account for (1). In my testing, NewGWorld never invalidated
other existing GWorlds in VRAM. However, I do have protection for (2).
Namely, I am using GetOSEvent() instead of WaitNextEvent() so that there are no
context switches (the app hogs the CPU). Eventually a book-keeping system should
be coded to take care of (1) and (2).
------------------------------------------------------------------------------------
System requirements (* denotes optional):
1. DrawSprocket 1.7.3
70
2. *MacOS 9 or later (but *not* Mac OS X) for hardware accelerated blit / fill
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
3. *May also require certain graphics hardware for (2). I trust that all Apple OEM
hardware will work. Third party accelerators may work if they have QuickDraw
acceleration in the drivers and the drivers have been updated for OS 9. The current
Voodoo 3 drivers (1.0b12) do not work.
Coding suggestions:
1. Use SDL_UpdateRects !
If no QuickDraw acceleration is present, double-buffered surfaces will use a back buffer
in System memory. I recommend you use SDL_UpdateRects with double-buffered surfaces
for best performance on these cards, since the overhead is nearly zero for VRAM back buffer.
2. Load most-resident surfaces first.
If you fill up VRAM or AGP memory, there is no contingency for purging to make room for the next one.
Therefore, you should load the surfaces you plan to use the most frequently first.
Sooner or later, I will code LRU replacement to help this.
TODO:
Some kind of posterized mode for resolutions < 640x480.
Window support / fullscreen toggle.
Figure out how much VRAM is available. Put in video->info->video_mem.
Track VRAM usage.
BUGS:
I can't create a hardware surface the same size as the screen?! How to fix?
COMPILE OPTIONS:
DSP_TRY_CC_AND_AA - Define if you want to try HWA color-key and alpha blitters
HW color-key blitting gives substantial improvements,
but hw alpha is neck-and-neck with SDL's soft bitter.
DSP_NO_SYNC_VBL - Define for HWA double-buffered surfaces: don't sync
pseudo-flip to monitor redraw.
DSP_NO_SYNC_OPENGL - Define for OpenGL surfaces: don't sync buffer swap. Synching buffer
swap may result in reduced performance, but can eliminate some
tearing artifacts.
CHANGELOG:
09/17/00 Lots of little tweaks. Build modelist in reverse order so largest contexts
list first. Compared various methods with ROM methods and fixed rez switch
crashing bug in GL Tron. (Woohoo!)
*/
#define DSP_TRY_CC_AND_AA
/* #define DSP_NO_SYNC_VBL */
#define DSP_NO_SYNC_OPENGL
126
127
128
129
#if defined(__APPLE__) && defined(__MACH__)
#include <Carbon/Carbon.h>
#include <DrawSprocket/DrawSprocket.h>
#elif TARGET_API_MAC_CARBON && (UNIVERSAL_INTERFACES_VERSION > 0x0335)
130
#include <Carbon.h>
131
#include <DrawSprocket.h>
132
133
134
135
136
137
#else
#include <LowMem.h>
#include <Gestalt.h>
#include <Devices.h>
#include <DiskInit.h>
#include <QDOffscreen.h>
138
#include <DrawSprocket.h>
139
140
141
142
#endif
#include "SDL_video.h"
#include "SDL_syswm.h"
143
144
145
#include "../SDL_sysvideo.h"
#include "../SDL_blit.h"
#include "../SDL_pixels_c.h"
146
#include "SDL_dspvideo.h"
147
148
149
150
#include "../maccommon/SDL_macgl_c.h"
#include "../maccommon/SDL_macwm_c.h"
#include "../maccommon/SDL_macmouse_c.h"
#include "../maccommon/SDL_macevents_c.h"
151
152
/* Initialization/Query functions */
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
static int DSp_VideoInit(_THIS, SDL_PixelFormat * vformat);
static SDL_Rect **DSp_ListModes(_THIS, SDL_PixelFormat * format,
Uint32 flags);
static SDL_Surface *DSp_SetVideoMode(_THIS, SDL_Surface * current, int width,
int height, int bpp, Uint32 flags);
static int DSp_SetColors(_THIS, int firstcolor, int ncolors,
SDL_Color * colors);
static int DSp_CreatePalette(_THIS);
static int DSp_DestroyPalette(_THIS);
static void DSp_VideoQuit(_THIS);
static int DSp_GetMainDevice(_THIS, GDHandle * device);
static void DSp_IsHWAvailable(_THIS, SDL_PixelFormat * vformat);
static void DSp_DSpUpdate(_THIS, int numrects, SDL_Rect * sdl_rects);
static void DSp_DirectUpdate(_THIS, int numrects, SDL_Rect * sdl_rects);
168
169
/* Hardware surface functions */
170
171
172
173
174
175
176
177
178
179
180
181
182
183
static int DSp_SetHWAlpha(_THIS, SDL_Surface * surface, UInt8 alpha);
static int DSp_SetHWColorKey(_THIS, SDL_Surface * surface, Uint32 key);
static int DSp_NewHWSurface(_THIS, CGrafPtr * port, int depth, int width,
int height);
static int DSp_AllocHWSurface(_THIS, SDL_Surface * surface);
static int DSp_LockHWSurface(_THIS, SDL_Surface * surface);
static void DSp_UnlockHWSurface(_THIS, SDL_Surface * surface);
static void DSp_FreeHWSurface(_THIS, SDL_Surface * surface);
static int DSp_FlipHWSurface(_THIS, SDL_Surface * surface);
static int DSp_CheckHWBlit(_THIS, SDL_Surface * src, SDL_Surface * dest);
static int DSp_HWAccelBlit(SDL_Surface * src, SDL_Rect * srcrect,
SDL_Surface * dst, SDL_Rect * dstrect);
static int DSp_FillHWRect(_THIS, SDL_Surface * dst, SDL_Rect * rect,
Uint32 color);
184
185
#if SDL_VIDEO_OPENGL
186
static void DSp_GL_SwapBuffers(_THIS);
187
188
189
190
#endif
#if ! TARGET_API_MAC_CARBON
191
192
193
194
195
#define GetPortPixRowBytes(x) ( (*(x->portPixMap))->rowBytes )
#define GetGDevPixMap(x) ((**(x)).gdPMap)
#define GetPortPixMap(x) ((*(x)).portPixMap)
#define GetPixDepth(y) ((**(y)).pixelSize)
196
197
//#define GetPixRowBytes(y) ((**(y)).rowBytes)
//#define GetPixBaseAddr(y) ((**(y)).baseAddr)
198
199
200
#define GetPixCTab(y) ((**(y)).pmTable)
#define GetPortBitMapForCopyBits(x) (&(((GrafPtr)(x))->portBits))
201
#else
202
203
#define GetPortPixRowBytes(x) (GetPixRowBytes(GetPortPixMap(x)) )
#define GetGDevPixMap(x) ((**(x)).gdPMap)
204
205
206
#endif
207
208
209
210
211
212
213
214
215
216
typedef struct private_hwdata
{
GWorldPtr offscreen; // offscreen gworld in VRAM or AGP
#ifdef DSP_TRY_CC_AND_AA
GWorldPtr mask; // transparent mask
RGBColor alpha; // alpha color
RGBColor trans; // transparent color
#endif
217
218
219
} private_hwdata;
220
typedef private_hwdata private_swdata; /* have same fields */
221
222
223
/* Macintosh toolbox driver bootstrap functions */
224
static int
225
DSp_Available(void)
226
{
227
/* Check for DrawSprocket */
228
#if ! TARGET_API_MAC_OSX
229
230
/* This check is only meaningful if you weak-link DrawSprocketLib */
return ((Ptr) DSpStartup != (Ptr) kUnresolvedCFragSymbolAddress);
231
#else
232
return 1; // DrawSprocket.framework doesn't have it all, but it's there
233
#endif
234
235
}
236
static void
237
DSp_DeleteDevice(SDL_VideoDevice * device)
238
{
239
240
241
242
243
244
/* -dw- taking no chances with null pointers */
if (device) {
if (device->hidden) {
if (device->hidden->dspinfo)
245
SDL_free(device->hidden->dspinfo);
246
247
SDL_free(device->hidden);
248
}
249
SDL_free(device);
250
}
251
252
}
253
static SDL_VideoDevice *
254
DSp_CreateDevice(int devindex)
255
{
256
257
258
SDL_VideoDevice *device;
/* Initialize all variables that we clean on shutdown */
259
device = (SDL_VideoDevice *) SDL_malloc(sizeof(SDL_VideoDevice));
260
if (device) {
261
SDL_memset(device, 0, sizeof(*device));
262
device->hidden = (struct SDL_PrivateVideoData *)
263
SDL_malloc((sizeof *device->hidden));
264
if (device->hidden)
265
SDL_memset(device->hidden, 0, sizeof(*(device->hidden)));
266
267
}
if ((device == NULL) || (device->hidden == NULL)) {
268
SDL_OutOfMemory();
269
270
271
272
if (device) {
if (device->hidden)
273
SDL_free(device->hidden);
274
275
SDL_free(device);
276
277
278
279
280
281
}
return (NULL);
}
/* Allocate DrawSprocket information */
282
283
284
device->hidden->dspinfo = (struct DSpInfo *) SDL_malloc((sizeof *device->
hidden->
dspinfo));
285
if (device->hidden->dspinfo == NULL) {
286
287
288
SDL_OutOfMemory();
SDL_free(device->hidden);
SDL_free(device);
289
290
return (0);
}
291
SDL_memset(device->hidden->dspinfo, 0, (sizeof *device->hidden->dspinfo));
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
/* Set the function pointers */
device->VideoInit = DSp_VideoInit;
device->ListModes = DSp_ListModes;
device->SetVideoMode = DSp_SetVideoMode;
device->SetColors = DSp_SetColors;
device->UpdateRects = NULL;
device->VideoQuit = DSp_VideoQuit;
device->AllocHWSurface = DSp_AllocHWSurface;
device->CheckHWBlit = NULL;
device->FillHWRect = NULL;
device->SetHWColorKey = NULL;
device->SetHWAlpha = NULL;
device->LockHWSurface = DSp_LockHWSurface;
device->UnlockHWSurface = DSp_UnlockHWSurface;
device->FlipHWSurface = DSp_FlipHWSurface;
device->FreeHWSurface = DSp_FreeHWSurface;
309
#if SDL_VIDEO_OPENGL
310
311
312
313
device->GL_MakeCurrent = Mac_GL_MakeCurrent;
device->GL_SwapBuffers = DSp_GL_SwapBuffers;
device->GL_LoadLibrary = Mac_GL_LoadLibrary;
device->GL_GetProcAddress = Mac_GL_GetProcAddress;
314
#endif
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
device->SetCaption = NULL;
device->SetIcon = NULL;
device->IconifyWindow = NULL;
device->GrabInput = NULL;
device->GetWMInfo = NULL;
device->FreeWMCursor = Mac_FreeWMCursor;
device->CreateWMCursor = Mac_CreateWMCursor;
device->ShowWMCursor = Mac_ShowWMCursor;
device->WarpWMCursor = Mac_WarpWMCursor;
device->InitOSKeymap = Mac_InitOSKeymap;
device->PumpEvents = Mac_PumpEvents;
device->GrabInput = NULL;
device->CheckMouseMode = NULL;
device->free = DSp_DeleteDevice;
return device;
333
334
335
}
VideoBootStrap DSp_bootstrap = {
336
337
"DSp", "MacOS DrawSprocket",
DSp_Available, DSp_CreateDevice
338
339
340
};
/* Use DSp/Display Manager to build mode list for given screen */
341
static SDL_Rect **
342
343
DSp_BuildModeList(const GDHandle gDevice, int *displayWidth,
int *displayHeight)
344
{
345
346
347
348
349
350
351
352
353
354
355
356
357
DSpContextAttributes attributes;
DSpContextReference context;
DisplayIDType displayID;
SDL_Rect temp_list[16];
SDL_Rect **mode_list;
int width, height, i, j;
#if TARGET_API_MAC_OSX
displayID = 0;
#else
/* Ask Display Manager for integer id of screen device */
358
if (DMGetDisplayIDByGDevice(gDevice, &displayID, SDL_TRUE) != noErr) {
359
360
361
362
return NULL;
}
#endif
/* Get the first possible DSp context on this device */
363
if (DSpGetFirstContext(displayID, &context) != noErr) {
364
365
366
return NULL;
}
367
if (DSpContext_GetAttributes(context, &attributes) != noErr)
368
369
370
371
372
return NULL;
*displayWidth = attributes.displayWidth;
*displayHeight = attributes.displayHeight;
373
for (i = 0; i < SDL_arraysize(temp_list); i++) {
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
width = attributes.displayWidth;
height = attributes.displayHeight;
temp_list[i].x = 0 | attributes.displayBestDepth;
temp_list[i].y = 0;
temp_list[i].w = width;
temp_list[i].h = height;
/* DSp will report many different contexts with the same width and height. */
/* They will differ in bit depth and refresh rate. */
/* We will ignore them until we reach one with a different width/height */
/* When there are no more contexts to look at, we will quit building the list */
while (width == attributes.displayWidth
&& height == attributes.displayHeight) {
389
OSStatus err = DSpGetNextContext(context, &context);
390
391
392
393
394
395
if (err != noErr)
if (err == kDSpContextNotFoundErr)
goto done;
else
return NULL;
396
if (DSpContext_GetAttributes(context, &attributes) != noErr)
397
398
399
400
401
402
403
404
return NULL;
temp_list[i].x |= attributes.displayBestDepth;
}
}
done:
i++; /* i was not incremented before kicking out of the loop */
405
mode_list = (SDL_Rect **) SDL_malloc(sizeof(SDL_Rect *) * (i + 1));
406
407
408
409
if (mode_list) {
/* -dw- new stuff: build in reverse order so largest sizes list first */
for (j = i - 1; j >= 0; j--) {
410
mode_list[j] = (SDL_Rect *) SDL_malloc(sizeof(SDL_Rect));
411
if (mode_list[j])
412
SDL_memcpy(mode_list[j], &(temp_list[j]), sizeof(SDL_Rect));
413
else {
414
SDL_OutOfMemory();
415
416
417
418
419
return NULL;
}
}
mode_list[i] = NULL; /* append null to the end */
} else {
420
SDL_OutOfMemory();
421
422
423
424
return NULL;
}
return mode_list;
425
426
}
427
static void
428
DSp_IsHWAvailable(_THIS, SDL_PixelFormat * vformat)
429
{
430
431
432
433
434
/*
VRAM GWorlds are only available on OS 9 or later.
Even with OS 9, some display drivers won't support it,
so we create a test GWorld and check for errors.
*/
435
436
437
438
439
440
long versionSystem;
dsp_vram_available = SDL_FALSE;
dsp_agp_available = SDL_FALSE;
441
Gestalt('sysv', &versionSystem);
442
443
444
445
446
447
if (0x00000860 < (versionSystem & 0x0000FFFF)) {
GWorldPtr offscreen;
OSStatus err;
Rect bounds;
448
SetRect(&bounds, 0, 0, 320, 240);
449
450
#if useDistantHdwrMem && useLocalHdwrMem
451
err =
452
453
NewGWorld(&offscreen, vformat->BitsPerPixel, &bounds, NULL,
SDL_Display, useDistantHdwrMem | noNewDevice);
454
455
if (err == noErr) {
dsp_vram_available = SDL_TRUE;
456
DisposeGWorld(offscreen);
457
458
459
}
err =
460
461
NewGWorld(&offscreen, vformat->BitsPerPixel, &bounds, NULL,
SDL_Display, useLocalHdwrMem | noNewDevice);
462
if (err == noErr) {
463
DisposeGWorld(offscreen);
464
465
dsp_agp_available = SDL_TRUE;
}
466
#endif
467
}
468
469
}
470
static int
471
DSp_GetMainDevice(_THIS, GDHandle * device)
472
{
473
474
#if TARGET_API_MAC_OSX
475
/* DSpUserSelectContext not available on OS X */
476
*device = GetMainDevice();
477
return 0;
478
479
#else
480
481
482
483
484
485
DSpContextAttributes attrib;
DSpContextReference context;
DisplayIDType display_id;
GDHandle main_device;
GDHandle device_list;
486
487
device_list = GetDeviceList();
main_device = GetMainDevice();
488
489
490
491
492
493
494
/* Quick check to avoid slower method when only one display exists */
if ((**device_list).gdNextGD == NULL) {
*device = main_device;
return 0;
}
495
SDL_memset(&attrib, 0, sizeof(DSpContextAttributes));
496
497
498
499
500
501
502
503
504
505
506
/* These attributes are hopefully supported on all devices... */
attrib.displayWidth = 640;
attrib.displayHeight = 480;
attrib.displayBestDepth = 8;
attrib.backBufferBestDepth = 8;
attrib.displayDepthMask = kDSpDepthMask_All;
attrib.backBufferDepthMask = kDSpDepthMask_All;
attrib.colorNeeds = kDSpColorNeeds_Require;
attrib.pageCount = 1;
507
if (noErr != DMGetDisplayIDByGDevice(main_device, &display_id, SDL_FALSE)) {
508
509
510
511
512
513
SDL_SetError
("Display Manager couldn't associate GDevice with a Display ID");
return (-1);
}
/* Put up dialog on main display to select which display to use */
514
515
if (noErr != DSpUserSelectContext(&attrib, display_id, NULL, &context)) {
SDL_SetError("DrawSprocket couldn't create a context");
516
517
518
return (-1);
}
519
520
if (noErr != DSpContext_GetDisplayID(context, &display_id)) {
SDL_SetError("DrawSprocket couldn't get display ID");
521
522
523
return (-1);
}
524
if (noErr != DMGetGDeviceByDisplayID(display_id, &main_device, SDL_FALSE)) {
525
526
527
528
529
530
531
SDL_SetError
("Display Manager couldn't associate Display ID with GDevice");
return (-1);
}
*device = main_device;
return (0);
532
533
534
#endif
}
535
static int
536
DSp_VideoInit(_THIS, SDL_PixelFormat * vformat)
537
{
538
539
NumVersion dsp_version = { 0x01, 0x00, 0x00, 0x00 };
540
#if UNIVERSAL_INTERFACES_VERSION > 0x0320
541
dsp_version = DSpGetVersion();
542
#endif
543
544
545
546
547
548
549
550
551
if ((dsp_version.majorRev == 1 && dsp_version.minorAndBugRev < 0x73) ||
(dsp_version.majorRev < 1)) {
/* StandardAlert (kAlertStopAlert, "\pError!",
"\pI need DrawSprocket 1.7.3 or later!\n"
"You can find a newer version at http://www.apple.com/swupdates.",
NULL, NULL);
*/
552
SDL_SetError("DrawSprocket version is too old. Need 1.7.3 or later.");
553
554
555
return (-1);
}
556
557
if (DSpStartup() != noErr) {
SDL_SetError("DrawSprocket couldn't startup");
558
559
560
561
return (-1);
}
/* Start DSpintosh events */
562
Mac_InitEvents(this);
563
564
/* Get a handle to the main monitor, or choose one on multiple monitor setups */
565
if (DSp_GetMainDevice(this, &SDL_Display) < 0)
566
567
568
return (-1);
/* Determine pixel format */
569
vformat->BitsPerPixel = GetPixDepth((**SDL_Display).gdPMap);
570
571
572
573
574
575
576
577
578
579
580
581
dsp_old_depth = vformat->BitsPerPixel;
switch (vformat->BitsPerPixel) {
case 16:
vformat->Rmask = 0x00007c00;
vformat->Gmask = 0x000003e0;
vformat->Bmask = 0x0000001f;
break;
default:
break;
}
582
583
if (DSp_CreatePalette(this) < 0) {
SDL_SetError("Could not create palette");
584
585
586
587
return (-1);
}
/* Get a list of available fullscreen modes */
588
589
590
SDL_modelist = DSp_BuildModeList(SDL_Display,
&this->info.current_w,
&this->info.current_h);
591
if (SDL_modelist == NULL) {
592
SDL_SetError("DrawSprocket could not build a mode list");
593
594
595
596
return (-1);
}
/* Check for VRAM and AGP GWorlds for HW Blitting */
597
DSp_IsHWAvailable(this, vformat);
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
this->info.wm_available = 0;
if (dsp_vram_available || dsp_agp_available) {
this->info.hw_available = SDL_TRUE;
this->CheckHWBlit = DSp_CheckHWBlit;
this->info.blit_hw = SDL_TRUE;
this->FillHWRect = DSp_FillHWRect;
this->info.blit_fill = SDL_TRUE;
#ifdef DSP_TRY_CC_AND_AA
this->SetHWColorKey = DSp_SetHWColorKey;
this->info.blit_hw_CC = SDL_TRUE;
this->SetHWAlpha = DSp_SetHWAlpha;
this->info.blit_hw_A = SDL_TRUE;
#endif
}
return (0);
622
623
}
624
static SDL_Rect **
625
DSp_ListModes(_THIS, SDL_PixelFormat * format, Uint32 flags)
626
{
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
static SDL_Rect *dsp_modes[16];
int i = 0, j = 0;
if (format->BitsPerPixel == 0)
return ((SDL_Rect **) NULL);
while (SDL_modelist[i] != NULL) {
if (SDL_modelist[i]->x & format->BitsPerPixel) {
dsp_modes[j] = SDL_modelist[i];
j++;
}
i++;
}
dsp_modes[j] = NULL;
return dsp_modes;
645
646
647
}
/* Various screen update functions available */
648
static void DSp_DirectUpdate(_THIS, int numrects, SDL_Rect * rects);
649
650
651
#if ! TARGET_API_MAC_OSX
652
653
static volatile unsigned int retrace_count = 0; /* -dw- need volatile because it updates asychronously */
654
Boolean
655
DSp_VBLProc(DSpContextReference context, void *ref_con)
656
{
657
658
659
retrace_count++;
return 1; /* Darrell, is this right? */
660
661
}
662
static void
663
DSp_SetHWError(OSStatus err, int is_agp)
664
{
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
char message[1024];
const char *fmt, *mem;
if (is_agp) {
mem = "AGP Memory";
} else {
mem = "VRAM";
}
switch (err) {
case memFullErr:
fmt = "Hardware surface possible but not enough %s available";
break;
case cDepthErr:
fmt = "Hardware surface possible but invalid color depth";
break;
default:
fmt = "Hardware surface could not be allocated in %s - unknown error";
break;
}
684
685
SDL_snprintf(message, SDL_arraysize(message), fmt, mem);
SDL_SetError(message);
686
}
687
#endif // TARGET_API_MAC_OSX
688
689
/* put up a dialog to verify display change */
690
static int
691
DSp_ConfirmSwitch()
692
693
694
695
696
697
698
699
700
701
702
703
704
{
/* resource id's for dialog */
const int rDialog = 1002;
const int bCancel = 1;
const int bOK = 2;
DialogPtr dialog;
OSStatus err;
SInt32 response;
DialogItemIndex item = 0;
GrafPtr savePort;
705
GetPort(&savePort);
706
707
dialog = GetNewDialog(rDialog, NULL, (WindowPtr) - 1);
708
709
if (dialog == NULL)
return (0);
710
711
#if TARGET_API_MAC_CARBON
712
SetPort(GetDialogPort(dialog));
713
#else
714
SetPort((WindowPtr) dialog);
715
#endif
716
717
718
SetDialogDefaultItem(dialog, bCancel);
SetDialogCancelItem(dialog, bCancel);
719
720
721
SetEventMask(everyEvent);
FlushEvents(everyEvent, 0);
722
723
724
725
/* On MacOS 8.5 or later, we can make the dialog go away after 15 seconds */
/* This is good since it's possible user can't even see the dialog! */
/* Requires linking to DialogsLib */
726
err = Gestalt(gestaltSystemVersion, &response);
727
if (err == noErr && response >= 0x00000850) {
728
SetDialogTimeout(dialog, bCancel, 15);
729
730
731
732
}
do {
733
ModalDialog(NULL, &item);
734
735
736
737
738
}
while (item != bCancel && item != bOK && err != noErr);
739
740
DisposeDialog(dialog);
SetPort(savePort);
741
742
743
SetEventMask(everyEvent - autoKeyMask);
FlushEvents(everyEvent, 0);
744
745
return (item - 1);
746
747
}
748
static void
749
DSp_UnsetVideoMode(_THIS, SDL_Surface * current)
750
{
751
752
753
if (current->flags & SDL_INTERNALOPENGL) {
754
Mac_GL_Quit(this);
755
756
757
758
759
}
if (dsp_context != NULL) {
GWorldPtr front;
760
DSpContext_GetFrontBuffer(dsp_context, &front);
761
762
if (front != dsp_back_buffer)
763
DisposeGWorld(dsp_back_buffer);
764
765
if (current->hwdata)
766
SDL_free(current->hwdata);
767
768
769
DSpContext_SetState(dsp_context, kDSpContextState_Inactive);
DSpContext_Release(dsp_context);
770
771
772
773
dsp_context = NULL;
}
774
if (SDL_Window != NULL) {
775
DisposeWindow(SDL_Window);
776
SDL_Window = NULL;
777
778
}
779
current->pixels = NULL;
780
current->flags = 0;
781
782
}
783
static SDL_Surface *
784
785
786
DSp_SetVideoMode(_THIS,
SDL_Surface * current, int width, int height, int bpp,
Uint32 flags)
787
{
788
789
#if !TARGET_API_MAC_OSX
790
791
DisplayIDType display_id;
Fixed freq;
792
#endif
793
794
795
796
797
798
799
800
801
DSpContextAttributes attrib;
OSStatus err;
UInt32 rmask = 0, gmask = 0, bmask = 0;
int page_count;
int double_buf;
int hw_surface;
int use_dsp_back_buffer;
802
DSp_UnsetVideoMode(this, current);
803
804
if (bpp != dsp_old_depth)
805
DSp_DestroyPalette(this);
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
double_buf = (flags & SDL_DOUBLEBUF) != 0;
hw_surface = (flags & SDL_HWSURFACE) != 0;
use_dsp_back_buffer = !dsp_vram_available || !hw_surface;
current->flags |= SDL_FULLSCREEN;
rebuild:
if (double_buf && use_dsp_back_buffer) {
page_count = 2;
} else {
page_count = 1;
}
821
SDL_memset(&attrib, 0, sizeof(DSpContextAttributes));
822
823
824
825
826
827
828
829
830
831
832
attrib.displayWidth = width;
attrib.displayHeight = height;
attrib.displayBestDepth = bpp;
attrib.backBufferBestDepth = bpp;
attrib.displayDepthMask = kDSpDepthMask_All;
attrib.backBufferDepthMask = kDSpDepthMask_All;
attrib.colorNeeds = kDSpColorNeeds_Require;
attrib.colorTable = 0;
attrib.pageCount = page_count;
#if TARGET_API_MAC_OSX || UNIVERSAL_INTERFACES_VERSION == 0x0320
833
834
if (DSpFindBestContext(&attrib, &dsp_context) != noErr) {
SDL_SetError("DrawSprocket couldn't find a context");
835
836
837
return NULL;
}
#else
838
if (noErr != DMGetDisplayIDByGDevice(SDL_Display, &display_id, SDL_FALSE)) {
839
840
841
842
SDL_SetError
("Display Manager couldn't associate GDevice with display_id");
return NULL;
}
843
if (DSpFindBestContextOnDisplayID(&attrib, &dsp_context, display_id) !=
844
845
846
847
848
849
noErr) {
SDL_SetError
("DrawSprocket couldn't find a suitable context on given display");
return NULL;
}
#endif
850
if (DSpContext_Reserve(dsp_context, &attrib) != noErr) {
851
852
853
854
855
856
SDL_SetError
("DrawSprocket couldn't get the needed resources to build the display");
return NULL;
}
if ((err =
857
DSpContext_SetState(dsp_context, kDSpContextState_Active)) != noErr)
858
859
860
861
{
if (err == kDSpConfirmSwitchWarning) {
862
if (!DSp_ConfirmSwitch()) {
863
864
DSpContext_Release(dsp_context);
865
dsp_context = NULL;
866
SDL_SetError("User cancelled display switch");
867
868
869
return NULL;
} else
/* Have to reactivate context. Why? */
870
DSpContext_SetState(dsp_context, kDSpContextState_Active);
871
872
} else {
873
SDL_SetError("DrawSprocket couldn't activate the context");
874
875
876
return NULL;
}
}
877
878
879
880
if (bpp != dsp_old_depth) {
881
DSp_CreatePalette(this);
882
883
884
885
886
887
888
889
/* update format if display depth changed */
if (bpp == 16) {
rmask = 0x00007c00;
gmask = 0x000003e0;
bmask = 0x0000001f;
}
890
if (!SDL_ReallocFormat(current, bpp, rmask, gmask, bmask, 0)) {
891
892
SDL_SetError("Could not reallocate video format.");
893
894
895
896
897
898
899
return (NULL);
}
}
if (!double_buf) {
/* single-buffer context */
900
DSpContext_GetFrontBuffer(dsp_context, &dsp_back_buffer);
901
902
current->hwdata =
903
(private_hwdata *) SDL_malloc(sizeof(private_hwdata));
904
if (current->hwdata == NULL) {
905
SDL_OutOfMemory();
906
907
908
909
910
911
912
return NULL;
}
current->hwdata->offscreen = dsp_back_buffer;
current->flags |= SDL_HWSURFACE;
this->UpdateRects = DSp_DirectUpdate;
} else if (use_dsp_back_buffer) {
913
914
DSpContext_GetBackBuffer(dsp_context, kDSpBufferKind_Normal,
&dsp_back_buffer);
915
916
917
918
919
920
921
current->flags |= SDL_DOUBLEBUF | SDL_SWSURFACE; /* only front buffer is in VRAM */
this->UpdateRects = DSp_DSpUpdate;
} else if (DSp_NewHWSurface
(this, &dsp_back_buffer, bpp, width - 1, height - 1) == 0) {
current->hwdata =
922
(private_hwdata *) SDL_malloc(sizeof(private_hwdata));
923
if (current->hwdata == NULL) {
924
SDL_OutOfMemory();
925
926
927
return NULL;
}
928
SDL_memset(current->hwdata, 0, sizeof(private_hwdata));
929
930
931
932
933
current->hwdata->offscreen = dsp_back_buffer;
current->flags |= SDL_DOUBLEBUF | SDL_HWSURFACE;
this->UpdateRects = DSp_DirectUpdate; /* hardware doesn't do update rects, must be page-flipped */
} else {
934
DSpContext_Release(dsp_context);
935
936
937
938
use_dsp_back_buffer = SDL_TRUE;
goto rebuild;
}
939
940
current->pitch = GetPortPixRowBytes(dsp_back_buffer) & 0x3FFF;
current->pixels = GetPixBaseAddr(GetPortPixMap(dsp_back_buffer));
941
942
943
944
945
946
947
948
current->w = width;
current->h = height;
#if ! TARGET_API_MAC_OSX
if (use_dsp_back_buffer) {
949
950
DSpContext_GetMonitorFrequency(dsp_context, &freq);
DSpContext_SetMaxFrameRate(dsp_context, freq >> 16);
951
952
953
954
955
}
if ((current->flags & SDL_HWSURFACE)
|| (current->flags & SDL_INTERNALOPENGL))
956
DSpContext_SetVBLProc(dsp_context, DSp_VBLProc, NULL);
957
958
959
960
961
962
963
964
965
966
967
#endif
if (bpp == 8)
current->flags |= SDL_HWPALETTE;
if (flags & SDL_INTERNALOPENGL) {
Rect rect;
RGBColor rgb = { 0.0, 0.0, 0.0 };
GrafPtr save_port;
968
SetRect(&rect, 0, 0, width, height);
969
SDL_Window =
970
971
NewCWindow(nil, &((**SDL_Display).gdRect), "\p", SDL_TRUE,
plainDBox, (WindowPtr) - 1, SDL_FALSE, 0);
972
973
974
975
976
977
978
979
980
if (SDL_Window == NULL) {
SDL_SetError
("DSp_SetVideoMode : OpenGL window could not be created.");
return NULL;
}
/* Set window color to black to avoid white flash */
981
GetPort(&save_port);
982
#if TARGET_API_MAC_CARBON
983
SetPort(GetWindowPort(SDL_Window));
984
#else
985
SetPort(SDL_Window);
986
#endif
987
988
989
RGBForeColor(&rgb);
PaintRect(&rect);
SetPort(save_port);
990
991
992
SetPortWindowPort(SDL_Window);
SelectWindow(SDL_Window);
993
994
if (Mac_GL_Init(this) < 0) {
995
996
997
998
999
1000
SDL_SetError
("DSp_SetVideoMode : could not create OpenGL context.");
return NULL;
}