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