/
SDL_dgavideo.c
1074 lines (962 loc) · 28.4 KB
1
2
/*
SDL - Simple DirectMedia Layer
3
Copyright (C) 1997-2004 Sam Lantinga
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
20
slouken@libsdl.org
21
22
23
24
25
26
27
28
29
30
31
32
33
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id$";
#endif
/* DGA 2.0 based SDL video driver implementation.
*/
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
34
#include <Xext/extensions/xf86dga.h>
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#endif
#include "SDL.h"
#include "SDL_error.h"
#include "SDL_video.h"
#include "SDL_mouse.h"
#include "SDL_sysvideo.h"
#include "SDL_pixels_c.h"
#include "SDL_events_c.h"
#include "SDL_dgavideo.h"
#include "SDL_dgamouse_c.h"
#include "SDL_dgaevents_c.h"
51
52
53
/* get function pointers... */
#include "../x11/SDL_x11dyn.h"
54
55
56
57
58
59
60
61
62
63
/* Initialization/Query functions */
static int DGA_VideoInit(_THIS, SDL_PixelFormat *vformat);
static SDL_Rect **DGA_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
static SDL_Surface *DGA_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
static int DGA_SetColors(_THIS, int firstcolor, int ncolors,
SDL_Color *colors);
static int DGA_SetGammaRamp(_THIS, Uint16 *ramp);
static void DGA_VideoQuit(_THIS);
/* Hardware surface functions */
64
static int DGA_InitHWSurfaces(_THIS, SDL_Surface *screen, Uint8 *base, int size);
65
66
67
68
69
70
71
72
73
74
75
76
77
static void DGA_FreeHWSurfaces(_THIS);
static int DGA_AllocHWSurface(_THIS, SDL_Surface *surface);
static int DGA_FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color);
static int DGA_CheckHWBlit(_THIS, SDL_Surface *src, SDL_Surface *dst);
static int DGA_LockHWSurface(_THIS, SDL_Surface *surface);
static void DGA_UnlockHWSurface(_THIS, SDL_Surface *surface);
static void DGA_FreeHWSurface(_THIS, SDL_Surface *surface);
static int DGA_FlipHWSurface(_THIS, SDL_Surface *surface);
/* DGA driver bootstrap functions */
static int DGA_Available(void)
{
78
79
80
const char *display = NULL;
Display *dpy = NULL;
int available = 0;
81
82
83
84
/* The driver is available is available if the display is local
and the DGA 2.0+ extension is available, and we can map mem.
*/
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
if ( SDL_X11_LoadSymbols() ) {
if ( (strncmp(pXDisplayName(display), ":", 1) == 0) ||
(strncmp(pXDisplayName(display), "unix:", 5) == 0) ) {
dpy = pXOpenDisplay(display);
if ( dpy ) {
int events, errors, major, minor;
if ( SDL_NAME(XDGAQueryExtension)(dpy, &events, &errors) &&
SDL_NAME(XDGAQueryVersion)(dpy, &major, &minor) ) {
int screen;
screen = DefaultScreen(dpy);
if ( (major >= 2) &&
SDL_NAME(XDGAOpenFramebuffer)(dpy, screen) ) {
available = 1;
SDL_NAME(XDGACloseFramebuffer)(dpy, screen);
}
102
}
103
pXCloseDisplay(dpy);
104
105
}
}
106
SDL_X11_UnloadSymbols();
107
108
109
110
111
112
}
return(available);
}
static void DGA_DeleteDevice(SDL_VideoDevice *device)
{
113
114
115
116
117
if (device != NULL) {
free(device->hidden);
free(device);
SDL_X11_UnloadSymbols();
}
118
119
120
121
}
static SDL_VideoDevice *DGA_CreateDevice(int devindex)
{
122
SDL_VideoDevice *device = NULL;
123
124
/* Initialize all variables that we clean on shutdown */
125
126
if (SDL_X11_LoadSymbols()) {
device = (SDL_VideoDevice *)malloc(sizeof(SDL_VideoDevice));
127
if ( device ) {
128
129
130
memset(device, 0, (sizeof *device));
device->hidden = (struct SDL_PrivateVideoData *)
malloc((sizeof *device->hidden));
131
}
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
if ( (device == NULL) || (device->hidden == NULL) ) {
SDL_OutOfMemory();
if ( device ) {
free(device);
}
SDL_X11_UnloadSymbols();
return(0);
}
memset(device->hidden, 0, (sizeof *device->hidden));
/* Set the function pointers */
device->VideoInit = DGA_VideoInit;
device->ListModes = DGA_ListModes;
device->SetVideoMode = DGA_SetVideoMode;
device->SetColors = DGA_SetColors;
device->UpdateRects = NULL;
device->VideoQuit = DGA_VideoQuit;
device->AllocHWSurface = DGA_AllocHWSurface;
device->CheckHWBlit = DGA_CheckHWBlit;
device->FillHWRect = DGA_FillHWRect;
device->SetHWColorKey = NULL;
device->SetHWAlpha = NULL;
device->LockHWSurface = DGA_LockHWSurface;
device->UnlockHWSurface = DGA_UnlockHWSurface;
device->FlipHWSurface = DGA_FlipHWSurface;
device->FreeHWSurface = DGA_FreeHWSurface;
device->SetGammaRamp = DGA_SetGammaRamp;
device->GetGammaRamp = NULL;
device->SetCaption = NULL;
device->SetIcon = NULL;
device->IconifyWindow = NULL;
device->GrabInput = NULL;
device->GetWMInfo = NULL;
device->InitOSKeymap = DGA_InitOSKeymap;
device->PumpEvents = DGA_PumpEvents;
device->free = DGA_DeleteDevice;
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
}
return device;
}
VideoBootStrap DGA_bootstrap = {
"dga", "XFree86 DGA 2.0",
DGA_Available, DGA_CreateDevice
};
static int DGA_AddMode(_THIS, int bpp, int w, int h)
{
SDL_Rect *mode;
int i, index;
int next_mode;
/* Check to see if we already have this mode */
if ( bpp < 8 ) { /* Not supported */
return(0);
}
index = ((bpp+7)/8)-1;
for ( i=0; i<SDL_nummodes[index]; ++i ) {
mode = SDL_modelist[index][i];
if ( (mode->w == w) && (mode->h == h) ) {
return(0);
}
}
/* Set up the new video mode rectangle */
mode = (SDL_Rect *)malloc(sizeof *mode);
if ( mode == NULL ) {
SDL_OutOfMemory();
return(-1);
}
mode->x = 0;
mode->y = 0;
mode->w = w;
mode->h = h;
/* Allocate the new list of modes, and fill in the new mode */
next_mode = SDL_nummodes[index];
SDL_modelist[index] = (SDL_Rect **)
realloc(SDL_modelist[index], (1+next_mode+1)*sizeof(SDL_Rect *));
if ( SDL_modelist[index] == NULL ) {
SDL_OutOfMemory();
SDL_nummodes[index] = 0;
free(mode);
return(-1);
}
SDL_modelist[index][next_mode] = mode;
SDL_modelist[index][next_mode+1] = NULL;
SDL_nummodes[index]++;
return(0);
}
/* This whole function is a hack. :) */
static Uint32 get_video_size(_THIS)
{
/* This is a non-exported function from libXxf86dga.a */
229
extern unsigned char *SDL_NAME(XDGAGetMappedMemory)(int screen);
230
231
232
233
234
235
FILE *proc;
unsigned long mem;
unsigned start, stop;
char line[BUFSIZ];
Uint32 size;
236
mem = (unsigned long)SDL_NAME(XDGAGetMappedMemory)(DGA_Screen);
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
size = 0;
proc = fopen("/proc/self/maps", "r");
if ( proc ) {
while ( fgets(line, sizeof(line)-1, proc) ) {
sscanf(line, "%x-%x", &start, &stop);
if ( start == mem ) {
size = (Uint32)((stop-start)/1024);
break;
}
}
fclose(proc);
}
return(size);
}
#ifdef DGA_DEBUG
253
static void PrintMode(SDL_NAME(XDGAMode) *mode)
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
{
printf("Mode: %s (%dx%d) at %d bpp (%f refresh, %d pitch) num: %d\n",
mode->name,
mode->viewportWidth, mode->viewportHeight,
mode->depth == 24 ? mode->bitsPerPixel : mode->depth,
mode->verticalRefresh, mode->bytesPerScanline, mode->num);
printf("\tRGB: 0x%8.8x 0x%8.8x 0x%8.8x (%d - %s)\n",
mode->redMask, mode->greenMask, mode->blueMask,
mode->visualClass,
mode->visualClass == TrueColor ? "truecolor" :
mode->visualClass == DirectColor ? "directcolor" :
mode->visualClass == PseudoColor ? "pseudocolor" : "unknown");
printf("\tFlags: ");
if ( mode->flags & XDGAConcurrentAccess )
printf(" XDGAConcurrentAccess");
if ( mode->flags & XDGASolidFillRect )
printf(" XDGASolidFillRect");
if ( mode->flags & XDGABlitRect )
printf(" XDGABlitRect");
if ( mode->flags & XDGABlitTransRect )
printf(" XDGABlitTransRect");
if ( mode->flags & XDGAPixmap )
printf(" XDGAPixmap");
if ( mode->flags & XDGAInterlaced )
printf(" XDGAInterlaced");
if ( mode->flags & XDGADoublescan )
printf(" XDGADoublescan");
if ( mode->viewportFlags & XDGAFlipRetrace )
printf(" XDGAFlipRetrace");
if ( mode->viewportFlags & XDGAFlipImmediate )
printf(" XDGAFlipImmediate");
printf("\n");
}
#endif /* DGA_DEBUG */
static int cmpmodes(const void *va, const void *vb)
{
291
292
const SDL_NAME(XDGAMode) *a = (const SDL_NAME(XDGAMode) *)va;
const SDL_NAME(XDGAMode) *b = (const SDL_NAME(XDGAMode) *)vb;
293
294
295
296
/* Prefer DirectColor visuals for otherwise equal modes */
if ( (a->viewportWidth == b->viewportWidth) &&
(b->viewportHeight == a->viewportHeight) ) {
297
if ( a->visualClass == DirectColor )
298
return -1;
299
300
301
302
if ( b->visualClass == DirectColor )
return 1;
return 0;
} else if ( a->viewportWidth == b->viewportWidth ) {
303
return b->viewportHeight - a->viewportHeight;
304
305
} else {
return b->viewportWidth - a->viewportWidth;
306
307
}
}
308
static void UpdateHWInfo(_THIS, SDL_NAME(XDGAMode) *mode)
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
{
this->info.wm_available = 0;
this->info.hw_available = 1;
if ( mode->flags & XDGABlitRect ) {
this->info.blit_hw = 1;
} else {
this->info.blit_hw = 0;
}
if ( mode->flags & XDGABlitTransRect ) {
this->info.blit_hw_CC = 1;
} else {
this->info.blit_hw_CC = 0;
}
if ( mode->flags & XDGASolidFillRect ) {
this->info.blit_fill = 1;
} else {
this->info.blit_fill = 0;
}
this->info.video_mem = get_video_size(this);
}
static int DGA_VideoInit(_THIS, SDL_PixelFormat *vformat)
{
const char *display;
int event_base, error_base;
int major_version, minor_version;
Visual *visual;
336
SDL_NAME(XDGAMode) *modes;
337
338
339
340
341
int i, num_modes;
/* Open the X11 display */
display = NULL; /* Get it from DISPLAY environment variable */
342
DGA_Display = pXOpenDisplay(display);
343
344
345
346
347
348
if ( DGA_Display == NULL ) {
SDL_SetError("Couldn't open X11 display");
return(-1);
}
/* Check for the DGA extension */
349
350
if ( ! SDL_NAME(XDGAQueryExtension)(DGA_Display, &event_base, &error_base) ||
! SDL_NAME(XDGAQueryVersion)(DGA_Display, &major_version, &minor_version) ) {
351
SDL_SetError("DGA extension not available");
352
pXCloseDisplay(DGA_Display);
353
354
355
356
return(-1);
}
if ( major_version < 2 ) {
SDL_SetError("DGA driver requires DGA 2.0 or newer");
357
pXCloseDisplay(DGA_Display);
358
359
360
361
362
363
364
365
366
367
368
return(-1);
}
DGA_event_base = event_base;
/* Determine the current screen depth */
visual = DefaultVisual(DGA_Display, DGA_Screen);
{
XPixmapFormatValues *pix_format;
int i, num_formats;
vformat->BitsPerPixel = DefaultDepth(DGA_Display, DGA_Screen);
369
pix_format = pXListPixmapFormats(DGA_Display, &num_formats);
370
371
if ( pix_format == NULL ) {
SDL_SetError("Couldn't determine screen formats");
372
pXCloseDisplay(DGA_Display);
373
374
375
376
377
378
379
380
return(-1);
}
for ( i=0; i<num_formats; ++i ) {
if ( vformat->BitsPerPixel == pix_format[i].depth )
break;
}
if ( i != num_formats )
vformat->BitsPerPixel = pix_format[i].bits_per_pixel;
381
pXFree((char *)pix_format);
382
383
384
385
386
387
388
389
}
if ( vformat->BitsPerPixel > 8 ) {
vformat->Rmask = visual->red_mask;
vformat->Gmask = visual->green_mask;
vformat->Bmask = visual->blue_mask;
}
/* Open access to the framebuffer */
390
if ( ! SDL_NAME(XDGAOpenFramebuffer)(DGA_Display, DGA_Screen) ) {
391
SDL_SetError("Unable to map the video memory");
392
pXCloseDisplay(DGA_Display);
393
394
395
396
return(-1);
}
/* Query for the list of available video modes */
397
modes = SDL_NAME(XDGAQueryModes)(DGA_Display, DGA_Screen, &num_modes);
398
399
400
401
402
403
404
405
406
407
408
409
410
411
qsort(modes, num_modes, sizeof *modes, cmpmodes);
for ( i=0; i<num_modes; ++i ) {
#ifdef DGA_DEBUG
PrintMode(&modes[i]);
#endif
if ( (modes[i].visualClass == PseudoColor) ||
(modes[i].visualClass == DirectColor) ||
(modes[i].visualClass == TrueColor) ) {
DGA_AddMode(this, modes[i].bitsPerPixel,
modes[i].viewportWidth,
modes[i].viewportHeight);
}
}
UpdateHWInfo(this, modes);
412
pXFree(modes);
413
414
415
416
417
418
419
420
421
/* Create the hardware surface lock mutex */
hw_lock = SDL_CreateMutex();
if ( hw_lock == NULL ) {
SDL_SetError("Unable to create lock mutex");
DGA_VideoQuit(this);
return(-1);
}
422
423
424
425
426
#ifdef LOCK_DGA_DISPLAY
/* Create the event lock so we're thread-safe.. :-/ */
event_lock = SDL_CreateMutex();
#endif /* LOCK_DGA_DISPLAY */
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
/* We're done! */
return(0);
}
SDL_Rect **DGA_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
{
return(SDL_modelist[((format->BitsPerPixel+7)/8)-1]);
}
/* Various screen update functions available */
static void DGA_DirectUpdate(_THIS, int numrects, SDL_Rect *rects);
SDL_Surface *DGA_SetVideoMode(_THIS, SDL_Surface *current,
int width, int height, int bpp, Uint32 flags)
{
442
SDL_NAME(XDGAMode) *modes;
443
int i, num_modes;
444
SDL_NAME(XDGADevice) *mode;
445
446
447
448
449
450
int screen_len;
Uint8 *surfaces_mem;
int surfaces_len;
/* Free any previous colormap */
if ( DGA_colormap ) {
451
pXFreeColormap(DGA_Display, DGA_colormap);
452
453
454
455
DGA_colormap = 0;
}
/* Search for a matching video mode */
456
modes = SDL_NAME(XDGAQueryModes)(DGA_Display, DGA_Screen, &num_modes);
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
qsort(modes, num_modes, sizeof *modes, cmpmodes);
for ( i=0; i<num_modes; ++i ) {
int depth;
depth = modes[i].depth;
if ( depth == 24 ) { /* Distinguish between 24 and 32 bpp */
depth = modes[i].bitsPerPixel;
}
if ( (depth == bpp) &&
(modes[i].viewportWidth == width) &&
(modes[i].viewportHeight == height) &&
((modes[i].visualClass == PseudoColor) ||
(modes[i].visualClass == DirectColor) ||
(modes[i].visualClass == TrueColor)) ) {
break;
}
}
if ( i == num_modes ) {
SDL_SetError("No matching video mode found");
return(NULL);
}
/* Set the video mode */
481
mode = SDL_NAME(XDGASetMode)(DGA_Display, DGA_Screen, modes[i].num);
482
pXFree(modes);
483
484
485
486
if ( mode == NULL ) {
SDL_SetError("Unable to switch to requested mode");
return(NULL);
}
487
DGA_visualClass = mode->mode.visualClass;
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
memory_base = (Uint8 *)mode->data;
memory_pitch = mode->mode.bytesPerScanline;
/* Set up the new mode framebuffer */
current->flags = (SDL_FULLSCREEN|SDL_HWSURFACE);
current->w = mode->mode.viewportWidth;
current->h = mode->mode.viewportHeight;
current->pitch = memory_pitch;
current->pixels = memory_base;
if ( ! SDL_ReallocFormat(current, mode->mode.bitsPerPixel,
mode->mode.redMask,
mode->mode.greenMask,
mode->mode.blueMask, 0) ) {
return(NULL);
}
screen_len = current->h*current->pitch;
/* Create a colormap if necessary */
if ( (DGA_visualClass == PseudoColor) ||
(DGA_visualClass == DirectColor) ) {
508
DGA_colormap = SDL_NAME(XDGACreateColormap)(DGA_Display, DGA_Screen,
509
510
511
512
513
514
515
516
517
518
519
mode, AllocAll);
if ( DGA_visualClass == PseudoColor ) {
current->flags |= SDL_HWPALETTE;
} else {
/* Initialize the colormap to the identity mapping */
SDL_GetGammaRamp(0, 0, 0);
this->screen = current;
DGA_SetGammaRamp(this, this->gamma);
this->screen = NULL;
}
} else {
520
DGA_colormap = SDL_NAME(XDGACreateColormap)(DGA_Display, DGA_Screen,
521
522
mode, AllocNone);
}
523
SDL_NAME(XDGAInstallColormap)(DGA_Display, DGA_Screen, DGA_colormap);
524
525
526
527
528
529
530
531
532
/* Update the hardware capabilities */
UpdateHWInfo(this, &mode->mode);
/* Set up the information for hardware surfaces */
surfaces_mem = (Uint8 *)current->pixels + screen_len;
surfaces_len = (mode->mode.imageHeight*current->pitch - screen_len);
/* Update for double-buffering, if we can */
533
SDL_NAME(XDGASetViewport)(DGA_Display, DGA_Screen, 0, 0, XDGAFlipRetrace);
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
if ( flags & SDL_DOUBLEBUF ) {
if ( mode->mode.imageHeight >= (current->h*2) ) {
current->flags |= SDL_DOUBLEBUF;
flip_page = 0;
flip_yoffset[0] = 0;
flip_yoffset[1] = current->h;
flip_address[0] = memory_base;
flip_address[1] = memory_base+screen_len;
surfaces_mem += screen_len;
surfaces_len -= screen_len;
}
}
/* Allocate memory tracking for hardware surfaces */
DGA_FreeHWSurfaces(this);
if ( surfaces_len < 0 ) {
surfaces_len = 0;
}
552
DGA_InitHWSurfaces(this, current, surfaces_mem, surfaces_len);
553
554
555
556
557
558
559
560
/* Expose the back buffer as surface memory */
if ( current->flags & SDL_DOUBLEBUF ) {
this->screen = current;
DGA_FlipHWSurface(this, current);
this->screen = NULL;
}
561
562
563
564
565
566
567
568
/* Set the update rectangle function */
this->UpdateRects = DGA_DirectUpdate;
/* Enable mouse and keyboard support */
{ long input_mask;
input_mask = (KeyPressMask | KeyReleaseMask);
input_mask |= (ButtonPressMask | ButtonReleaseMask);
input_mask |= PointerMotionMask;
569
SDL_NAME(XDGASelectInput)(DGA_Display, DGA_Screen, input_mask);
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
}
/* We're done */
return(current);
}
#ifdef DGA_DEBUG
static void DGA_DumpHWSurfaces(_THIS)
{
vidmem_bucket *bucket;
printf("Memory left: %d (%d total)\n", surfaces_memleft, surfaces_memtotal);
printf("\n");
printf(" Base Size\n");
for ( bucket=&surfaces; bucket; bucket=bucket->next ) {
printf("Bucket: %p, %d (%s)\n", bucket->base, bucket->size, bucket->used ? "used" : "free");
if ( bucket->prev ) {
if ( bucket->base != bucket->prev->base+bucket->prev->size ) {
printf("Warning, corrupt bucket list! (prev)\n");
}
} else {
if ( bucket != &surfaces ) {
printf("Warning, corrupt bucket list! (!prev)\n");
}
}
if ( bucket->next ) {
if ( bucket->next->base != bucket->base+bucket->size ) {
printf("Warning, corrupt bucket list! (next)\n");
}
}
}
printf("\n");
}
#endif
605
static int DGA_InitHWSurfaces(_THIS, SDL_Surface *screen, Uint8 *base, int size)
606
{
607
608
vidmem_bucket *bucket;
609
610
surfaces_memtotal = size;
surfaces_memleft = size;
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
if ( surfaces_memleft > 0 ) {
bucket = (vidmem_bucket *)malloc(sizeof(*bucket));
if ( bucket == NULL ) {
SDL_OutOfMemory();
return(-1);
}
bucket->prev = &surfaces;
bucket->used = 0;
bucket->dirty = 0;
bucket->base = base;
bucket->size = size;
bucket->next = NULL;
} else {
bucket = NULL;
}
surfaces.prev = NULL;
surfaces.used = 1;
surfaces.dirty = 0;
surfaces.base = screen->pixels;
surfaces.size = (unsigned int)((long)base - (long)surfaces.base);
surfaces.next = bucket;
screen->hwdata = (struct private_hwdata *)&surfaces;
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
return(0);
}
static void DGA_FreeHWSurfaces(_THIS)
{
vidmem_bucket *bucket, *freeable;
bucket = surfaces.next;
while ( bucket ) {
freeable = bucket;
bucket = bucket->next;
free(freeable);
}
surfaces.next = NULL;
}
650
static __inline__ void DGA_AddBusySurface(SDL_Surface *surface)
651
652
653
654
{
((vidmem_bucket *)surface->hwdata)->dirty = 1;
}
655
static __inline__ int DGA_IsSurfaceBusy(SDL_Surface *surface)
656
657
658
659
{
return ((vidmem_bucket *)surface->hwdata)->dirty;
}
660
static __inline__ void DGA_WaitBusySurfaces(_THIS)
661
662
663
664
{
vidmem_bucket *bucket;
/* Wait for graphic operations to complete */
665
SDL_NAME(XDGASync)(DGA_Display, DGA_Screen);
666
667
668
669
670
671
672
/* Clear all surface dirty bits */
for ( bucket=&surfaces; bucket; bucket=bucket->next ) {
bucket->dirty = 0;
}
}
673
674
675
676
677
static int DGA_AllocHWSurface(_THIS, SDL_Surface *surface)
{
vidmem_bucket *bucket;
int size;
int extra;
678
int retval = 0;
679
680
681
682
683
684
685
686
687
688
689
690
691
692
/* Temporarily, we only allow surfaces the same width as display.
Some blitters require the pitch between two hardware surfaces
to be the same. Others have interesting alignment restrictions.
*/
if ( surface->pitch > SDL_VideoSurface->pitch ) {
SDL_SetError("Surface requested wider than screen");
return(-1);
}
surface->pitch = SDL_VideoSurface->pitch;
size = surface->h * surface->pitch;
#ifdef DGA_DEBUG
fprintf(stderr, "Allocating bucket of %d bytes\n", size);
#endif
693
LOCK_DISPLAY();
694
695
696
697
/* Quick check for available mem */
if ( size > surfaces_memleft ) {
SDL_SetError("Not enough video memory");
698
699
retval = -1;
goto done;
700
701
702
703
704
705
706
707
708
709
}
/* Search for an empty bucket big enough */
for ( bucket=&surfaces; bucket; bucket=bucket->next ) {
if ( ! bucket->used && (size <= bucket->size) ) {
break;
}
}
if ( bucket == NULL ) {
SDL_SetError("Video memory too fragmented");
710
711
retval = -1;
goto done;
712
713
714
715
716
717
718
719
720
721
722
723
724
}
/* Create a new bucket for left-over memory */
extra = (bucket->size - size);
if ( extra ) {
vidmem_bucket *newbucket;
#ifdef DGA_DEBUG
fprintf(stderr, "Adding new free bucket of %d bytes\n", extra);
#endif
newbucket = (vidmem_bucket *)malloc(sizeof(*newbucket));
if ( newbucket == NULL ) {
SDL_OutOfMemory();
725
726
retval = -1;
goto done;
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
}
newbucket->prev = bucket;
newbucket->used = 0;
newbucket->base = bucket->base+size;
newbucket->size = extra;
newbucket->next = bucket->next;
if ( bucket->next ) {
bucket->next->prev = newbucket;
}
bucket->next = newbucket;
}
/* Set the current bucket values and return it! */
bucket->used = 1;
bucket->size = size;
742
bucket->dirty = 0;
743
744
745
746
747
748
#ifdef DGA_DEBUG
fprintf(stderr, "Allocated %d bytes at %p\n", bucket->size, bucket->base);
#endif
surfaces_memleft -= size;
surface->flags |= SDL_HWSURFACE;
surface->pixels = bucket->base;
749
750
751
752
surface->hwdata = (struct private_hwdata *)bucket;
done:
UNLOCK_DISPLAY();
return(retval);
753
754
755
756
757
758
}
static void DGA_FreeHWSurface(_THIS, SDL_Surface *surface)
{
vidmem_bucket *bucket, *freeable;
/* Look for the bucket in the current list */
759
760
761
762
for ( bucket=&surfaces; bucket; bucket=bucket->next ) {
if ( bucket == (vidmem_bucket *)surface->hwdata ) {
break;
}
763
}
764
765
if ( bucket && bucket->used ) {
/* Add the memory back to the total */
766
767
768
#ifdef DGA_DEBUG
printf("Freeing bucket of %d bytes\n", bucket->size);
#endif
769
surfaces_memleft += bucket->size;
770
771
772
773
/* Can we merge the space with surrounding buckets? */
bucket->used = 0;
if ( bucket->next && ! bucket->next->used ) {
774
775
776
#ifdef DGA_DEBUG
printf("Merging with next bucket, for %d total bytes\n", bucket->size+bucket->next->size);
#endif
777
778
779
780
781
782
783
freeable = bucket->next;
bucket->size += bucket->next->size;
bucket->next = bucket->next->next;
if ( bucket->next ) {
bucket->next->prev = bucket;
}
free(freeable);
784
}
785
if ( bucket->prev && ! bucket->prev->used ) {
786
787
788
#ifdef DGA_DEBUG
printf("Merging with previous bucket, for %d total bytes\n", bucket->prev->size+bucket->size);
#endif
789
790
791
792
793
794
795
freeable = bucket;
bucket->prev->size += bucket->size;
bucket->prev->next = bucket->next;
if ( bucket->next ) {
bucket->next->prev = bucket->prev;
}
free(freeable);
796
797
798
}
}
surface->pixels = NULL;
799
surface->hwdata = NULL;
800
801
}
802
static __inline__ void DGA_dst_to_xy(_THIS, SDL_Surface *dst, int *x, int *y)
803
804
805
806
807
808
809
810
811
812
813
{
*x = (long)((Uint8 *)dst->pixels - memory_base)%memory_pitch;
*y = (long)((Uint8 *)dst->pixels - memory_base)/memory_pitch;
}
static int DGA_FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color)
{
int x, y;
unsigned int w, h;
/* Don't fill the visible part of the screen, wait until flipped */
814
LOCK_DISPLAY();
815
if ( was_flipped && (dst == this->screen) ) {
816
while ( SDL_NAME(XDGAGetViewportStatus)(DGA_Display, DGA_Screen) )
817
818
819
/* Keep waiting for the hardware ... */ ;
was_flipped = 0;
}
820
DGA_dst_to_xy(this, dst, &x, &y);
821
822
823
824
825
826
827
x += rect->x;
y += rect->y;
w = rect->w;
h = rect->h;
#if 0
printf("Hardware accelerated rectangle fill: %dx%d at %d,%d\n", w, h, x, y);
#endif
828
SDL_NAME(XDGAFillRectangle)(DGA_Display, DGA_Screen, x, y, w, h, color);
829
if ( !(this->screen->flags & SDL_DOUBLEBUF) ) {
830
pXFlush(DGA_Display);
831
}
832
DGA_AddBusySurface(dst);
833
UNLOCK_DISPLAY();
834
835
836
837
838
839
840
841
842
843
844
845
846
return(0);
}
static int HWAccelBlit(SDL_Surface *src, SDL_Rect *srcrect,
SDL_Surface *dst, SDL_Rect *dstrect)
{
SDL_VideoDevice *this;
int srcx, srcy;
int dstx, dsty;
unsigned int w, h;
this = current_video;
/* Don't blit to the visible part of the screen, wait until flipped */
847
LOCK_DISPLAY();
848
if ( was_flipped && (dst == this->screen) ) {
849
while ( SDL_NAME(XDGAGetViewportStatus)(DGA_Display, DGA_Screen) )
850
851
852
/* Keep waiting for the hardware ... */ ;
was_flipped = 0;
}
853
DGA_dst_to_xy(this, src, &srcx, &srcy);
854
855
srcx += srcrect->x;
srcy += srcrect->y;
856
DGA_dst_to_xy(this, dst, &dstx, &dsty);
857
858
859
860
861
862
863
864
dstx += dstrect->x;
dsty += dstrect->y;
w = srcrect->w;
h = srcrect->h;
#if 0
printf("Blitting %dx%d from %d,%d to %d,%d\n", w, h, srcx, srcy, dstx, dsty);
#endif
if ( (src->flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) {
865
SDL_NAME(XDGACopyTransparentArea)(DGA_Display, DGA_Screen,
866
867
srcx, srcy, w, h, dstx, dsty, src->format->colorkey);
} else {
868
SDL_NAME(XDGACopyArea)(DGA_Display, DGA_Screen,
869
870
srcx, srcy, w, h, dstx, dsty);
}
871
if ( !(this->screen->flags & SDL_DOUBLEBUF) ) {
872
pXFlush(DGA_Display);
873
}
874
875
DGA_AddBusySurface(src);
DGA_AddBusySurface(dst);
876
UNLOCK_DISPLAY();
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
return(0);
}
static int DGA_CheckHWBlit(_THIS, SDL_Surface *src, SDL_Surface *dst)
{
int accelerated;
/* Set initial acceleration on */
src->flags |= SDL_HWACCEL;
/* Set the surface attributes */
if ( (src->flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
if ( ! this->info.blit_hw_A ) {
src->flags &= ~SDL_HWACCEL;
}
}
if ( (src->flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) {
if ( ! this->info.blit_hw_CC ) {
src->flags &= ~SDL_HWACCEL;
}
}
/* Check to see if final surface blit is accelerated */
accelerated = !!(src->flags & SDL_HWACCEL);
if ( accelerated ) {
src->map->hw_blit = HWAccelBlit;
}
return(accelerated);
}
907
static __inline__ void DGA_WaitFlip(_THIS)
908
909
{
if ( was_flipped ) {
910
while ( SDL_NAME(XDGAGetViewportStatus)(DGA_Display, DGA_Screen) )
911
912
913
914
915
916
917
/* Keep waiting for the hardware ... */ ;
was_flipped = 0;
}
}
static int DGA_LockHWSurface(_THIS, SDL_Surface *surface)
{
918
if ( surface == this->screen ) {
919
SDL_mutexP(hw_lock);
920
LOCK_DISPLAY();
921
922
if ( DGA_IsSurfaceBusy(surface) ) {
DGA_WaitBusySurfaces(this);
923
924
925
926
}
DGA_WaitFlip(this);
UNLOCK_DISPLAY();
} else {
927
if ( DGA_IsSurfaceBusy(surface) ) {
928
LOCK_DISPLAY();
929
DGA_WaitBusySurfaces(this);
930
931
UNLOCK_DISPLAY();
}
932
933
934
935
936
}
return(0);
}
static void DGA_UnlockHWSurface(_THIS, SDL_Surface *surface)
{
937
if ( surface == this->screen ) {
938
939
940
941
942
943
944
SDL_mutexV(hw_lock);
}
}
static int DGA_FlipHWSurface(_THIS, SDL_Surface *surface)
{
/* Wait for vertical retrace and then flip display */
945
LOCK_DISPLAY();
946
947
if ( DGA_IsSurfaceBusy(this->screen) ) {
DGA_WaitBusySurfaces(this);
948
949
}
DGA_WaitFlip(this);
950
SDL_NAME(XDGASetViewport)(DGA_Display, DGA_Screen,
951
0, flip_yoffset[flip_page], XDGAFlipRetrace);
952
pXFlush(DGA_Display);
953
UNLOCK_DISPLAY();
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
was_flipped = 1;
flip_page = !flip_page;
surface->pixels = flip_address[flip_page];
return(0);
}
static void DGA_DirectUpdate(_THIS, int numrects, SDL_Rect *rects)
{
/* The application is already updating the visible video memory */
return;
}
static int DGA_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
{
int i;
XColor *xcmap;
/* This happens on initialization */
if ( ! DGA_colormap ) {
return(0);
}
xcmap = (XColor *)alloca(ncolors*sizeof(*xcmap));
for ( i=0; i<ncolors; ++i ) {
xcmap[i].pixel = firstcolor + i;
xcmap[i].red = (colors[i].r<<8)|colors[i].r;
xcmap[i].green = (colors[i].g<<8)|colors[i].g;
xcmap[i].blue = (colors[i].b<<8)|colors[i].b;
xcmap[i].flags = (DoRed|DoGreen|DoBlue);
}
984
LOCK_DISPLAY();
985
986
pXStoreColors(DGA_Display, DGA_colormap, xcmap, ncolors);
pXSync(DGA_Display, False);
987
UNLOCK_DISPLAY();
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* That was easy. :) */
return(1);
}
int DGA_SetGammaRamp(_THIS, Uint16 *ramp)
{
int i, ncolors;
XColor xcmap[256];
/* See if actually setting the gamma is supported */
if ( DGA_visualClass != DirectColor ) {
SDL_SetError("Gamma correction not supported on this visual");