Mercurial > sdl-ios-xcode
changeset 101:825b2fa28e2e
DGA video driver is now thread-safe
Improved DGA hardware acceleration code
author | Sam Lantinga <slouken@lokigames.com> |
---|---|
date | Thu, 12 Jul 2001 20:42:22 +0000 |
parents | a1c973c35fef |
children | 9162d62280b5 |
files | src/video/dga/SDL_dgaevents.c src/video/dga/SDL_dgavideo.c src/video/dga/SDL_dgavideo.h |
diffstat | 3 files changed, 129 insertions(+), 29 deletions(-) [+] |
line wrap: on
line diff
--- a/src/video/dga/SDL_dgaevents.c Wed Jul 11 20:18:52 2001 +0000 +++ b/src/video/dga/SDL_dgaevents.c Thu Jul 12 20:42:22 2001 +0000 @@ -97,9 +97,11 @@ void DGA_PumpEvents(_THIS) { /* Keep processing pending events */ + LOCK_DISPLAY(); while ( X11_Pending(DGA_Display) ) { DGA_DispatchEvent(this); } + UNLOCK_DISPLAY(); } void DGA_InitOSKeymap(_THIS)
--- a/src/video/dga/SDL_dgavideo.c Wed Jul 11 20:18:52 2001 +0000 +++ b/src/video/dga/SDL_dgavideo.c Thu Jul 12 20:42:22 2001 +0000 @@ -58,7 +58,7 @@ static void DGA_VideoQuit(_THIS); /* Hardware surface functions */ -static int DGA_InitHWSurfaces(_THIS, Uint8 *base, int size); +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); @@ -409,6 +409,11 @@ return(-1); } +#ifdef LOCK_DGA_DISPLAY + /* Create the event lock so we're thread-safe.. :-/ */ + event_lock = SDL_CreateMutex(); +#endif /* LOCK_DGA_DISPLAY */ + /* We're done! */ return(0); } @@ -535,7 +540,7 @@ if ( surfaces_len < 0 ) { surfaces_len = 0; } - DGA_InitHWSurfaces(this, surfaces_mem, surfaces_len); + DGA_InitHWSurfaces(this, current, surfaces_mem, surfaces_len); /* Set the update rectangle function */ this->UpdateRects = DGA_DirectUpdate; @@ -581,15 +586,36 @@ } #endif -static int DGA_InitHWSurfaces(_THIS, Uint8 *base, int size) +static int DGA_InitHWSurfaces(_THIS, SDL_Surface *screen, Uint8 *base, int size) { - surfaces.prev = NULL; - surfaces.used = 0; - surfaces.base = base; - surfaces.size = size; - surfaces.next = NULL; + vidmem_bucket *bucket; + surfaces_memtotal = size; surfaces_memleft = size; + + 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; return(0); } static void DGA_FreeHWSurfaces(_THIS) @@ -605,11 +631,35 @@ surfaces.next = NULL; } +static __inline__ void DGA_AddDirtySurface(SDL_Surface *surface) +{ + ((vidmem_bucket *)surface->hwdata)->dirty = 1; +} + +static __inline__ int DGA_IsSurfaceDirty(SDL_Surface *surface) +{ + return ((vidmem_bucket *)surface->hwdata)->dirty; +} + +static __inline__ void DGA_WaitDirtySurfaces(_THIS) +{ + vidmem_bucket *bucket; + + /* Wait for graphic operations to complete */ + XDGASync(DGA_Display, DGA_Screen); + + /* Clear all surface dirty bits */ + for ( bucket=&surfaces; bucket; bucket=bucket->next ) { + bucket->dirty = 0; + } +} + static int DGA_AllocHWSurface(_THIS, SDL_Surface *surface) { vidmem_bucket *bucket; int size; int extra; + int retval = 0; /* Temporarily, we only allow surfaces the same width as display. Some blitters require the pitch between two hardware surfaces @@ -624,11 +674,13 @@ #ifdef DGA_DEBUG fprintf(stderr, "Allocating bucket of %d bytes\n", size); #endif + LOCK_DISPLAY(); /* Quick check for available mem */ if ( size > surfaces_memleft ) { SDL_SetError("Not enough video memory"); - return(-1); + retval = -1; + goto done; } /* Search for an empty bucket big enough */ @@ -639,7 +691,8 @@ } if ( bucket == NULL ) { SDL_SetError("Video memory too fragmented"); - return(-1); + retval = -1; + goto done; } /* Create a new bucket for left-over memory */ @@ -653,7 +706,8 @@ newbucket = (vidmem_bucket *)malloc(sizeof(*newbucket)); if ( newbucket == NULL ) { SDL_OutOfMemory(); - return(-1); + retval = -1; + goto done; } newbucket->prev = bucket; newbucket->used = 0; @@ -669,24 +723,24 @@ /* Set the current bucket values and return it! */ bucket->used = 1; bucket->size = size; + bucket->dirty = 0; #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; - return(0); + surface->hwdata = (struct private_hwdata *)bucket; +done: + UNLOCK_DISPLAY(); + return(retval); } static void DGA_FreeHWSurface(_THIS, SDL_Surface *surface) { vidmem_bucket *bucket, *freeable; /* Look for the bucket in the current list */ - for ( bucket=&surfaces; bucket; bucket=bucket->next ) { - if ( bucket->base == (Uint8 *)surface->pixels ) { - break; - } - } + bucket = (vidmem_bucket *)surface->hwdata; if ( (bucket == NULL) || ! bucket->used ) { return; } @@ -724,6 +778,7 @@ free(freeable); } surface->pixels = NULL; + surface->hwdata = NULL; } static __inline__ void dst_to_xy(_THIS, SDL_Surface *dst, int *x, int *y) @@ -742,6 +797,7 @@ unsigned int w, h; /* Don't fill the visible part of the screen, wait until flipped */ + LOCK_DISPLAY(); if ( was_flipped && (dst == this->screen) ) { while ( XDGAGetViewportStatus(DGA_Display, DGA_Screen) ) /* Keep waiting for the hardware ... */ ; @@ -756,8 +812,9 @@ printf("Hardware accelerated rectangle fill: %dx%d at %d,%d\n", w, h, x, y); #endif XDGAFillRectangle(DGA_Display, DGA_Screen, x, y, w, h, color); - sync_needed++; XFlush(DGA_Display); + DGA_AddDirtySurface(dst); + UNLOCK_DISPLAY(); return(0); } @@ -771,6 +828,7 @@ this = current_video; /* Don't blit to the visible part of the screen, wait until flipped */ + LOCK_DISPLAY(); if ( was_flipped && (dst == this->screen) ) { while ( XDGAGetViewportStatus(DGA_Display, DGA_Screen) ) /* Keep waiting for the hardware ... */ ; @@ -794,8 +852,10 @@ XDGACopyArea(DGA_Display, DGA_Screen, srcx, srcy, w, h, dstx, dsty); } - sync_needed++; XFlush(DGA_Display); + DGA_AddDirtySurface(src); + DGA_AddDirtySurface(dst); + UNLOCK_DISPLAY(); return(0); } @@ -826,12 +886,8 @@ return(accelerated); } -static __inline__ void DGA_WaitHardware(_THIS) +static __inline__ void DGA_WaitFlip(_THIS) { - if ( sync_needed ) { - XDGASync(DGA_Display, DGA_Screen); - sync_needed = 0; - } if ( was_flipped ) { while ( XDGAGetViewportStatus(DGA_Display, DGA_Screen) ) /* Keep waiting for the hardware ... */ ; @@ -841,15 +897,26 @@ static int DGA_LockHWSurface(_THIS, SDL_Surface *surface) { - if ( surface == SDL_VideoSurface ) { + if ( surface == this->screen ) { SDL_mutexP(hw_lock); - DGA_WaitHardware(this); + LOCK_DISPLAY(); + if ( DGA_IsSurfaceDirty(surface) ) { + DGA_WaitDirtySurfaces(this); + } + DGA_WaitFlip(this); + UNLOCK_DISPLAY(); + } else { + if ( DGA_IsSurfaceDirty(surface) ) { + LOCK_DISPLAY(); + DGA_WaitDirtySurfaces(this); + UNLOCK_DISPLAY(); + } } return(0); } static void DGA_UnlockHWSurface(_THIS, SDL_Surface *surface) { - if ( surface == SDL_VideoSurface ) { + if ( surface == this->screen ) { SDL_mutexV(hw_lock); } } @@ -857,10 +924,15 @@ static int DGA_FlipHWSurface(_THIS, SDL_Surface *surface) { /* Wait for vertical retrace and then flip display */ - DGA_WaitHardware(this); + LOCK_DISPLAY(); + if ( DGA_IsSurfaceDirty(this->screen) ) { + DGA_WaitDirtySurfaces(this); + } + DGA_WaitFlip(this); XDGASetViewport(DGA_Display, DGA_Screen, 0, flip_yoffset[flip_page], XDGAFlipRetrace); XFlush(DGA_Display); + UNLOCK_DISPLAY(); was_flipped = 1; flip_page = !flip_page; @@ -891,8 +963,10 @@ xcmap[i].blue = (colors[i].b<<8)|colors[i].b; xcmap[i].flags = (DoRed|DoGreen|DoBlue); } + LOCK_DISPLAY(); XStoreColors(DGA_Display, DGA_colormap, xcmap, ncolors); XSync(DGA_Display, False); + UNLOCK_DISPLAY(); /* That was easy. :) */ return(1); @@ -923,8 +997,10 @@ xcmap[i].blue = ramp[2*256+c]; xcmap[i].flags = (DoRed|DoGreen|DoBlue); } + LOCK_DISPLAY(); XStoreColors(DGA_Display, DGA_colormap, xcmap, ncolors); XSync(DGA_Display, False); + UNLOCK_DISPLAY(); return(0); } @@ -952,6 +1028,13 @@ SDL_DestroyMutex(hw_lock); hw_lock = NULL; } +#ifdef LOCK_DGA_DISPLAY + if ( event_lock != NULL ) { + SDL_DestroyMutex(event_lock); + event_lock = NULL; + } +#endif /* LOCK_DGA_DISPLAY */ + /* Clean up defined video modes */ for ( i=0; i<NUM_MODELISTS; ++i ) {
--- a/src/video/dga/SDL_dgavideo.h Wed Jul 11 20:18:52 2001 +0000 +++ b/src/video/dga/SDL_dgavideo.h Thu Jul 12 20:42:22 2001 +0000 @@ -37,11 +37,22 @@ /* Hidden "this" pointer for the video functions */ #define _THIS SDL_VideoDevice *this +/* Define this if you need the DGA driver to be thread-safe */ +#define LOCK_DGA_DISPLAY +#ifdef LOCK_DGA_DISPLAY +#define LOCK_DISPLAY() SDL_mutexP(event_lock) +#define UNLOCK_DISPLAY() SDL_mutexV(event_lock) +#else +#define LOCK_DISPLAY() +#define UNLOCK_DISPLAY() +#endif + /* This is the structure we use to keep track of video memory */ typedef struct vidmem_bucket { struct vidmem_bucket *prev; - unsigned int used; + int used; + int dirty; Uint8 *base; unsigned int size; struct vidmem_bucket *next; @@ -82,6 +93,9 @@ /* Used to handle DGA events */ int event_base; +#ifdef LOCK_DGA_DISPLAY + SDL_mutex *event_lock; +#endif }; /* Old variable names */ #define DGA_Display (this->hidden->DGA_Display) @@ -102,5 +116,6 @@ #define surfaces_memleft (this->hidden->surfaces_memleft) #define hw_lock (this->hidden->hw_lock) #define DGA_event_base (this->hidden->event_base) +#define event_lock (this->hidden->event_lock) #endif /* _SDL_dgavideo_h */