/
SDL_dgavideo.c
1101 lines (988 loc) · 29.6 KB
1
/*
2
SDL - Simple DirectMedia Layer
3
Copyright (C) 1997-2012 Sam Lantinga
4
5
6
7
8
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
9
10
11
12
13
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
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
20
Sam Lantinga
slouken@libsdl.org
21
*/
22
#include "SDL_config.h"
23
24
25
26
/* DGA 2.0 based SDL video driver implementation.
*/
27
28
#include <stdio.h>
29
#include <X11/Xlib.h>
30
#include "../Xext/extensions/xf86dga.h"
31
32
33
#include "SDL_video.h"
#include "SDL_mouse.h"
34
35
36
#include "../SDL_sysvideo.h"
#include "../SDL_pixels_c.h"
#include "../../events/SDL_events_c.h"
37
38
39
40
#include "SDL_dgavideo.h"
#include "SDL_dgamouse_c.h"
#include "SDL_dgaevents_c.h"
41
42
43
/* get function pointers... */
#include "../x11/SDL_x11dyn.h"
44
45
/*#define DGA_DEBUG*/
46
47
48
49
50
51
52
53
54
55
/* 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 */
56
static int DGA_InitHWSurfaces(_THIS, SDL_Surface *screen, Uint8 *base, int size);
57
58
59
60
61
62
63
64
65
66
67
68
69
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)
{
70
71
72
const char *display = NULL;
Display *dpy = NULL;
int available = 0;
73
74
75
76
/* The driver is available is available if the display is local
and the DGA 2.0+ extension is available, and we can map mem.
*/
77
if ( SDL_X11_LoadSymbols() ) {
78
79
80
if ( (SDL_strncmp(XDisplayName(display), ":", 1) == 0) ||
(SDL_strncmp(XDisplayName(display), "unix:", 5) == 0) ) {
dpy = XOpenDisplay(display);
81
82
83
84
85
86
87
88
89
90
91
92
93
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);
}
94
}
95
XCloseDisplay(dpy);
96
97
}
}
98
SDL_X11_UnloadSymbols();
99
100
101
102
103
104
}
return(available);
}
static void DGA_DeleteDevice(SDL_VideoDevice *device)
{
105
if (device != NULL) {
106
107
SDL_free(device->hidden);
SDL_free(device);
108
109
SDL_X11_UnloadSymbols();
}
110
111
112
113
}
static SDL_VideoDevice *DGA_CreateDevice(int devindex)
{
114
SDL_VideoDevice *device = NULL;
115
116
/* Initialize all variables that we clean on shutdown */
117
if (SDL_X11_LoadSymbols()) {
118
device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice));
119
if ( device ) {
120
SDL_memset(device, 0, (sizeof *device));
121
device->hidden = (struct SDL_PrivateVideoData *)
122
SDL_malloc((sizeof *device->hidden));
123
}
124
125
126
if ( (device == NULL) || (device->hidden == NULL) ) {
SDL_OutOfMemory();
if ( device ) {
127
SDL_free(device);
128
129
130
131
}
SDL_X11_UnloadSymbols();
return(0);
}
132
SDL_memset(device->hidden, 0, (sizeof *device->hidden));
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
/* 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;
161
162
163
164
165
166
167
168
169
170
171
172
173
}
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;
174
int index;
175
176
177
178
179
180
181
int next_mode;
/* Check to see if we already have this mode */
if ( bpp < 8 ) { /* Not supported */
return(0);
}
index = ((bpp+7)/8)-1;
182
183
if ( SDL_nummodes[index] > 0 ) {
mode = SDL_modelist[index][SDL_nummodes[index]-1];
184
185
186
187
188
189
if ( (mode->w == w) && (mode->h == h) ) {
return(0);
}
}
/* Set up the new video mode rectangle */
190
mode = (SDL_Rect *)SDL_malloc(sizeof *mode);
191
192
193
194
195
196
197
198
199
200
201
202
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 **)
203
SDL_realloc(SDL_modelist[index], (1+next_mode+1)*sizeof(SDL_Rect *));
204
205
206
if ( SDL_modelist[index] == NULL ) {
SDL_OutOfMemory();
SDL_nummodes[index] = 0;
207
SDL_free(mode);
208
209
210
211
212
213
214
215
216
217
218
219
220
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 */
221
extern unsigned char *SDL_NAME(XDGAGetMappedMemory)(int screen);
222
223
224
225
226
227
FILE *proc;
unsigned long mem;
unsigned start, stop;
char line[BUFSIZ];
Uint32 size;
228
mem = (unsigned long)SDL_NAME(XDGAGetMappedMemory)(DGA_Screen);
229
230
231
232
size = 0;
proc = fopen("/proc/self/maps", "r");
if ( proc ) {
while ( fgets(line, sizeof(line)-1, proc) ) {
233
SDL_sscanf(line, "%x-%x", &start, &stop);
234
235
236
237
238
239
240
241
242
243
244
if ( start == mem ) {
size = (Uint32)((stop-start)/1024);
break;
}
}
fclose(proc);
}
return(size);
}
#ifdef DGA_DEBUG
245
static void PrintMode(SDL_NAME(XDGAMode) *mode)
246
247
248
249
250
251
252
253
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
{
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)
{
283
284
const SDL_NAME(XDGAMode) *a = (const SDL_NAME(XDGAMode) *)va;
const SDL_NAME(XDGAMode) *b = (const SDL_NAME(XDGAMode) *)vb;
285
286
287
if ( (a->viewportWidth == b->viewportWidth) &&
(b->viewportHeight == a->viewportHeight) ) {
288
289
290
291
292
293
294
295
/* Prefer 32 bpp over 24 bpp, 16 bpp over 15 bpp */
int a_bpp = a->depth == 24 ? a->bitsPerPixel : a->depth;
int b_bpp = b->depth == 24 ? b->bitsPerPixel : b->depth;
if ( a_bpp != b_bpp ) {
return b_bpp - a_bpp;
}
/* Prefer DirectColor visuals, for gamma support */
if ( a->visualClass == DirectColor && b->visualClass != DirectColor )
296
return -1;
297
if ( b->visualClass == DirectColor && a->visualClass != DirectColor )
298
return 1;
299
300
/* Maintain server refresh rate sorting */
return a->num - b->num;
301
} else if ( a->viewportWidth == b->viewportWidth ) {
302
return b->viewportHeight - a->viewportHeight;
303
304
} else {
return b->viewportWidth - a->viewportWidth;
305
306
}
}
307
static void UpdateHWInfo(_THIS, SDL_NAME(XDGAMode) *mode)
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
{
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)
{
331
const char *env;
332
333
334
335
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 = XOpenDisplay(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
XCloseDisplay(DGA_Display);
353
354
355
356
return(-1);
}
if ( major_version < 2 ) {
SDL_SetError("DGA driver requires DGA 2.0 or newer");
357
XCloseDisplay(DGA_Display);
358
359
360
361
return(-1);
}
DGA_event_base = event_base;
362
363
364
365
/* Determine the current screen size */
this->info.current_w = DisplayWidth(DGA_Display, DGA_Screen);
this->info.current_h = DisplayHeight(DGA_Display, DGA_Screen);
366
367
368
369
370
371
372
/* 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);
373
pix_format = XListPixmapFormats(DGA_Display, &num_formats);
374
375
if ( pix_format == NULL ) {
SDL_SetError("Couldn't determine screen formats");
376
XCloseDisplay(DGA_Display);
377
378
379
380
381
382
383
384
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;
385
XFree((char *)pix_format);
386
387
388
389
390
391
392
393
}
if ( vformat->BitsPerPixel > 8 ) {
vformat->Rmask = visual->red_mask;
vformat->Gmask = visual->green_mask;
vformat->Bmask = visual->blue_mask;
}
/* Open access to the framebuffer */
394
if ( ! SDL_NAME(XDGAOpenFramebuffer)(DGA_Display, DGA_Screen) ) {
395
SDL_SetError("Unable to map the video memory");
396
XCloseDisplay(DGA_Display);
397
398
399
return(-1);
}
400
401
402
403
404
405
406
407
408
409
410
/* Allow environment override of screensaver disable. */
env = SDL_getenv("SDL_VIDEO_ALLOW_SCREENSAVER");
if ( env ) {
allow_screensaver = SDL_atoi(env);
} else {
#ifdef SDL_VIDEO_DISABLE_SCREENSAVER
allow_screensaver = 0;
#else
allow_screensaver = 1;
#endif
}
411
412
/* Query for the list of available video modes */
413
modes = SDL_NAME(XDGAQueryModes)(DGA_Display, DGA_Screen, &num_modes);
414
SDL_qsort(modes, num_modes, sizeof *modes, cmpmodes);
415
for ( i=0; i<num_modes; ++i ) {
416
417
418
419
if ( ((modes[i].visualClass == PseudoColor) ||
(modes[i].visualClass == DirectColor) ||
(modes[i].visualClass == TrueColor)) &&
!(modes[i].flags & (XDGAInterlaced|XDGADoublescan)) ) {
420
#ifdef DGA_DEBUG
421
PrintMode(&modes[i]);
422
423
424
425
426
427
428
#endif
DGA_AddMode(this, modes[i].bitsPerPixel,
modes[i].viewportWidth,
modes[i].viewportHeight);
}
}
UpdateHWInfo(this, modes);
429
XFree(modes);
430
431
432
433
434
435
436
437
438
/* 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);
}
439
440
441
442
443
#ifdef LOCK_DGA_DISPLAY
/* Create the event lock so we're thread-safe.. :-/ */
event_lock = SDL_CreateMutex();
#endif /* LOCK_DGA_DISPLAY */
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
/* 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)
{
459
SDL_NAME(XDGAMode) *modes;
460
int i, num_modes;
461
SDL_NAME(XDGADevice) *mode;
462
463
464
465
466
467
int screen_len;
Uint8 *surfaces_mem;
int surfaces_len;
/* Free any previous colormap */
if ( DGA_colormap ) {
468
XFreeColormap(DGA_Display, DGA_colormap);
469
470
471
472
DGA_colormap = 0;
}
/* Search for a matching video mode */
473
modes = SDL_NAME(XDGAQueryModes)(DGA_Display, DGA_Screen, &num_modes);
474
SDL_qsort(modes, num_modes, sizeof *modes, cmpmodes);
475
476
477
478
479
480
481
482
483
484
485
486
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) ||
487
488
(modes[i].visualClass == TrueColor)) &&
!(modes[i].flags & (XDGAInterlaced|XDGADoublescan)) ) {
489
490
491
492
493
494
495
break;
}
}
if ( i == num_modes ) {
SDL_SetError("No matching video mode found");
return(NULL);
}
496
497
498
#ifdef DGA_DEBUG
PrintMode(&modes[i]);
#endif
499
500
/* Set the video mode */
501
mode = SDL_NAME(XDGASetMode)(DGA_Display, DGA_Screen, modes[i].num);
502
XFree(modes);
503
504
505
506
if ( mode == NULL ) {
SDL_SetError("Unable to switch to requested mode");
return(NULL);
}
507
DGA_visualClass = mode->mode.visualClass;
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
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) ) {
528
DGA_colormap = SDL_NAME(XDGACreateColormap)(DGA_Display, DGA_Screen,
529
530
531
532
533
534
535
536
537
538
539
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 {
540
DGA_colormap = SDL_NAME(XDGACreateColormap)(DGA_Display, DGA_Screen,
541
542
mode, AllocNone);
}
543
SDL_NAME(XDGAInstallColormap)(DGA_Display, DGA_Screen, DGA_colormap);
544
545
546
547
548
549
550
551
552
/* 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 */
553
SDL_NAME(XDGASetViewport)(DGA_Display, DGA_Screen, 0, 0, XDGAFlipRetrace);
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
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;
}
572
DGA_InitHWSurfaces(this, current, surfaces_mem, surfaces_len);
573
574
575
576
577
578
579
580
/* Expose the back buffer as surface memory */
if ( current->flags & SDL_DOUBLEBUF ) {
this->screen = current;
DGA_FlipHWSurface(this, current);
this->screen = NULL;
}
581
582
583
584
585
586
587
588
/* 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;
589
SDL_NAME(XDGASelectInput)(DGA_Display, DGA_Screen, input_mask);
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
}
/* 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
625
static int DGA_InitHWSurfaces(_THIS, SDL_Surface *screen, Uint8 *base, int size)
626
{
627
628
vidmem_bucket *bucket;
629
630
surfaces_memtotal = size;
surfaces_memleft = size;
631
632
if ( surfaces_memleft > 0 ) {
633
bucket = (vidmem_bucket *)SDL_malloc(sizeof(*bucket));
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
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;
654
screen->hwdata = (struct private_hwdata *)((char*)&surfaces);
655
656
657
658
659
660
661
662
663
664
return(0);
}
static void DGA_FreeHWSurfaces(_THIS)
{
vidmem_bucket *bucket, *freeable;
bucket = surfaces.next;
while ( bucket ) {
freeable = bucket;
bucket = bucket->next;
665
SDL_free(freeable);
666
667
668
669
}
surfaces.next = NULL;
}
670
static __inline__ void DGA_AddBusySurface(SDL_Surface *surface)
671
672
673
674
{
((vidmem_bucket *)surface->hwdata)->dirty = 1;
}
675
static __inline__ int DGA_IsSurfaceBusy(SDL_Surface *surface)
676
677
678
679
{
return ((vidmem_bucket *)surface->hwdata)->dirty;
}
680
static __inline__ void DGA_WaitBusySurfaces(_THIS)
681
682
683
684
{
vidmem_bucket *bucket;
/* Wait for graphic operations to complete */
685
SDL_NAME(XDGASync)(DGA_Display, DGA_Screen);
686
687
688
689
690
691
692
/* Clear all surface dirty bits */
for ( bucket=&surfaces; bucket; bucket=bucket->next ) {
bucket->dirty = 0;
}
}
693
694
695
696
697
static int DGA_AllocHWSurface(_THIS, SDL_Surface *surface)
{
vidmem_bucket *bucket;
int size;
int extra;
698
int retval = 0;
699
700
701
702
703
704
705
706
707
708
709
710
711
712
/* 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
713
LOCK_DISPLAY();
714
715
716
717
/* Quick check for available mem */
if ( size > surfaces_memleft ) {
SDL_SetError("Not enough video memory");
718
719
retval = -1;
goto done;
720
721
722
723
724
725
726
727
728
729
}
/* 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");
730
731
retval = -1;
goto done;
732
733
734
735
736
737
738
739
740
741
}
/* 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
742
newbucket = (vidmem_bucket *)SDL_malloc(sizeof(*newbucket));
743
744
if ( newbucket == NULL ) {
SDL_OutOfMemory();
745
746
retval = -1;
goto done;
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
}
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;
762
bucket->dirty = 0;
763
764
765
766
767
768
#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;
769
770
771
772
surface->hwdata = (struct private_hwdata *)bucket;
done:
UNLOCK_DISPLAY();
return(retval);
773
774
775
776
777
}
static void DGA_FreeHWSurface(_THIS, SDL_Surface *surface)
{
vidmem_bucket *bucket, *freeable;
778
779
780
781
782
783
784
/* Wait for any pending operations involving this surface */
if ( DGA_IsSurfaceBusy(surface) ) {
LOCK_DISPLAY();
DGA_WaitBusySurfaces(this);
UNLOCK_DISPLAY();
}
785
/* Look for the bucket in the current list */
786
787
788
789
for ( bucket=&surfaces; bucket; bucket=bucket->next ) {
if ( bucket == (vidmem_bucket *)surface->hwdata ) {
break;
}
790
}
791
792
if ( bucket && bucket->used ) {
/* Add the memory back to the total */
793
794
795
#ifdef DGA_DEBUG
printf("Freeing bucket of %d bytes\n", bucket->size);
#endif
796
surfaces_memleft += bucket->size;
797
798
799
800
/* Can we merge the space with surrounding buckets? */
bucket->used = 0;
if ( bucket->next && ! bucket->next->used ) {
801
802
803
#ifdef DGA_DEBUG
printf("Merging with next bucket, for %d total bytes\n", bucket->size+bucket->next->size);
#endif
804
805
806
807
808
809
freeable = bucket->next;
bucket->size += bucket->next->size;
bucket->next = bucket->next->next;
if ( bucket->next ) {
bucket->next->prev = bucket;
}
810
SDL_free(freeable);
811
}
812
if ( bucket->prev && ! bucket->prev->used ) {
813
814
815
#ifdef DGA_DEBUG
printf("Merging with previous bucket, for %d total bytes\n", bucket->prev->size+bucket->size);
#endif
816
817
818
819
820
821
freeable = bucket;
bucket->prev->size += bucket->size;
bucket->prev->next = bucket->next;
if ( bucket->next ) {
bucket->next->prev = bucket->prev;
}
822
SDL_free(freeable);
823
824
825
}
}
surface->pixels = NULL;
826
surface->hwdata = NULL;
827
828
}
829
static __inline__ void DGA_dst_to_xy(_THIS, SDL_Surface *dst, int *x, int *y)
830
831
832
833
834
835
836
837
838
839
840
{
*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 */
841
LOCK_DISPLAY();
842
if ( was_flipped && (dst == this->screen) ) {
843
while ( SDL_NAME(XDGAGetViewportStatus)(DGA_Display, DGA_Screen) )
844
845
846
/* Keep waiting for the hardware ... */ ;
was_flipped = 0;
}
847
DGA_dst_to_xy(this, dst, &x, &y);
848
849
850
851
852
853
854
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
855
SDL_NAME(XDGAFillRectangle)(DGA_Display, DGA_Screen, x, y, w, h, color);
856
if ( !(this->screen->flags & SDL_DOUBLEBUF) ) {
857
XFlush(DGA_Display);
858
}
859
DGA_AddBusySurface(dst);
860
UNLOCK_DISPLAY();
861
862
863
864
865
866
867
868
869
870
871
872
873
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 */
874
LOCK_DISPLAY();
875
if ( was_flipped && (dst == this->screen) ) {
876
while ( SDL_NAME(XDGAGetViewportStatus)(DGA_Display, DGA_Screen) )
877
878
879
/* Keep waiting for the hardware ... */ ;
was_flipped = 0;
}
880
DGA_dst_to_xy(this, src, &srcx, &srcy);
881
882
srcx += srcrect->x;
srcy += srcrect->y;
883
DGA_dst_to_xy(this, dst, &dstx, &dsty);
884
885
886
887
888
889
890
891
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 ) {
892
SDL_NAME(XDGACopyTransparentArea)(DGA_Display, DGA_Screen,
893
894
srcx, srcy, w, h, dstx, dsty, src->format->colorkey);
} else {
895
SDL_NAME(XDGACopyArea)(DGA_Display, DGA_Screen,
896
897
srcx, srcy, w, h, dstx, dsty);
}
898
if ( !(this->screen->flags & SDL_DOUBLEBUF) ) {
899
XFlush(DGA_Display);
900
}
901
902
DGA_AddBusySurface(src);
DGA_AddBusySurface(dst);
903
UNLOCK_DISPLAY();
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
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);
}
934
static __inline__ void DGA_WaitFlip(_THIS)
935
936
{
if ( was_flipped ) {
937
while ( SDL_NAME(XDGAGetViewportStatus)(DGA_Display, DGA_Screen) )
938
939
940
941
942
943
944
/* Keep waiting for the hardware ... */ ;
was_flipped = 0;
}
}
static int DGA_LockHWSurface(_THIS, SDL_Surface *surface)
{
945
if ( surface == this->screen ) {
946
SDL_mutexP(hw_lock);
947
LOCK_DISPLAY();
948
949
if ( DGA_IsSurfaceBusy(surface) ) {
DGA_WaitBusySurfaces(this);
950
951
952
953
}
DGA_WaitFlip(this);
UNLOCK_DISPLAY();
} else {
954
if ( DGA_IsSurfaceBusy(surface) ) {
955
LOCK_DISPLAY();
956
DGA_WaitBusySurfaces(this);
957
958
UNLOCK_DISPLAY();
}
959
960
961
962
963
}
return(0);
}
static void DGA_UnlockHWSurface(_THIS, SDL_Surface *surface)
{
964
if ( surface == this->screen ) {
965
966
967
968
969
970
971
SDL_mutexV(hw_lock);
}
}
static int DGA_FlipHWSurface(_THIS, SDL_Surface *surface)
{
/* Wait for vertical retrace and then flip display */
972
LOCK_DISPLAY();
973
974
if ( DGA_IsSurfaceBusy(this->screen) ) {
DGA_WaitBusySurfaces(this);
975
976
}
DGA_WaitFlip(this);
977
SDL_NAME(XDGASetViewport)(DGA_Display, DGA_Screen,
978
0, flip_yoffset[flip_page], XDGAFlipRetrace);
979
XFlush(DGA_Display);
980
UNLOCK_DISPLAY();
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
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 ) {