Merged DGA video surface handling improvements, unified locking code.

Fixed matrox blit bug where src Y less than dst Y
Fixed hardware surface init when no resolution change

--HG--
extra : convert_revision : svn%3Ac70aab31-4412-0410-b14c-859654838e24/trunk%40107
This commit is contained in:
Sam Lantinga 2001-07-13 10:19:51 +00:00
parent 7ddaf6cf9a
commit a079e29715
4 changed files with 179 additions and 113 deletions

View File

@ -32,18 +32,6 @@ static char rcsid =
#include "3dfx_mmio.h"
static int LockHWSurface(_THIS, SDL_Surface *surface)
{
if ( surface == SDL_VideoSurface ) {
tdfx_waitidle();
}
return(0);
}
static void UnlockHWSurface(_THIS, SDL_Surface *surface)
{
return;
}
/* Wait for vertical retrace */
static void WaitVBL(_THIS)
{
@ -55,6 +43,10 @@ static void WaitVBL(_THIS)
while( (tdfx_in32(TDFX_STATUS) & STATUS_RETRACE) == 0 )
;
}
static void WaitIdle(_THIS)
{
tdfx_waitidle();
}
/* Sets video mem colorkey and accelerated blit function */
static int SetHWColorKey(_THIS, SDL_Surface *surface, Uint32 key)
@ -86,6 +78,9 @@ static int FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color)
tdfx_out32(COMMAND_2D, COMMAND_2D_FILLRECT);
tdfx_out32(DSTSIZE, rect->w | (rect->h << 16));
tdfx_out32(LAUNCH_2D, dstX | (dstY << 16));
FB_AddBusySurface(dst);
return(0);
}
@ -151,6 +146,9 @@ static int HWAccelBlit(SDL_Surface *src, SDL_Rect *srcrect,
tdfx_out32(DSTXY, dstX | (dstY << 16));
tdfx_out32(LAUNCH_2D, srcX | (srcY << 16));
FB_AddBusySurface(src);
FB_AddBusySurface(dst);
return(0);
}
@ -185,9 +183,8 @@ void FB_3DfxAccel(_THIS, __u32 card)
{
/* We have hardware accelerated surface functions */
this->CheckHWBlit = CheckHWBlit;
this->LockHWSurface = LockHWSurface;
this->UnlockHWSurface = UnlockHWSurface;
wait_vbl = WaitVBL;
wait_idle = WaitIdle;
/* Reset the 3Dfx controller */
tdfx_out32(BRESERROR0, 0);

View File

@ -32,18 +32,6 @@ static char rcsid =
#include "matrox_mmio.h"
static int LockHWSurface(_THIS, SDL_Surface *surface)
{
if ( surface == SDL_VideoSurface ) {
mga_waitidle();
}
return(0);
}
static void UnlockHWSurface(_THIS, SDL_Surface *surface)
{
return;
}
/* Wait for vertical retrace - taken from the XFree86 Matrox driver */
static void WaitVBL(_THIS)
{
@ -60,6 +48,10 @@ static void WaitVBL(_THIS)
while ( mga_in32(0x1E20) < count )
;
}
static void WaitIdle(_THIS)
{
mga_waitidle();
}
/* Sets video mem colorkey and accelerated blit function */
static int SetHWColorKey(_THIS, SDL_Surface *surface, Uint32 key)
@ -91,8 +83,7 @@ static int FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color)
}
/* Set up the X/Y base coordinates */
dstX = 0;
dstY = ((char *)dst->pixels - mapped_mem) / SDL_VideoSurface->pitch;
FB_dst_to_xy(this, dst, &dstX, &dstY);
/* Adjust for the current rectangle */
dstX += rect->x;
@ -104,19 +95,6 @@ static int FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color)
/* Set up the Y boundaries */
ydstlen = (rect->h | (dstY << 16));
#if 0 /* This old way doesn't work on the Matrox G450 */
/* Set up for color fill operation */
fillop = MGADWG_TRAP | MGADWG_SOLID |
MGADWG_ARZERO | MGADWG_SGNZERO | MGADWG_SHIFTZERO |
MGADWG_BFCOL | MGADWG_BLK;
/* Execute the operations! */
mga_wait(4);
mga_out32(MGAREG_FCOL, color);
mga_out32(MGAREG_FXBNDRY, fxbndry);
mga_out32(MGAREG_YDSTLEN, ydstlen);
mga_out32(MGAREG_DWGCTL + MGAREG_EXEC, fillop);
#else
/* Set up for color fill operation */
fillop = MGADWG_TRAP | MGADWG_SOLID |
MGADWG_ARZERO | MGADWG_SGNZERO | MGADWG_SHIFTZERO;
@ -127,7 +105,8 @@ static int FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color)
mga_out32(MGAREG_FCOL, color);
mga_out32(MGAREG_FXBNDRY, fxbndry);
mga_out32(MGAREG_YDSTLEN + MGAREG_EXEC, ydstlen);
#endif
FB_AddBusySurface(dst);
return(0);
}
@ -136,12 +115,12 @@ static int HWAccelBlit(SDL_Surface *src, SDL_Rect *srcrect,
SDL_Surface *dst, SDL_Rect *dstrect)
{
SDL_VideoDevice *this;
int bpp;
int pitch, w, h;
int srcX, srcY;
int dstX, dstY;
Uint32 sign;
Uint32 sstart, sstop;
int sskip;
Uint32 start, stop;
int skip;
Uint32 blitop;
/* FIXME: For now, only blit to display surface */
@ -151,16 +130,17 @@ static int HWAccelBlit(SDL_Surface *src, SDL_Rect *srcrect,
/* Calculate source and destination base coordinates (in pixels) */
this = current_video;
srcX= 0; /* FIXME: Calculate this from memory offset */
srcY = ((char *)src->pixels - mapped_mem) / SDL_VideoSurface->pitch;
dstX = 0; /* FIXME: Calculate this from memory offset */
dstY = ((char *)dst->pixels - mapped_mem) / SDL_VideoSurface->pitch;
w = dstrect->w;
h = dstrect->h;
FB_dst_to_xy(this, src, &srcX, &srcY);
FB_dst_to_xy(this, dst, &dstX, &dstY);
/* Adjust for the current blit rectangles */
srcX += srcrect->x;
srcY += srcrect->y;
dstX += dstrect->x;
dstY += dstrect->y;
pitch = dst->pitch/dst->format->BytesPerPixel;
/* Set up the blit direction (sign) flags */
sign = 0;
@ -169,19 +149,21 @@ static int HWAccelBlit(SDL_Surface *src, SDL_Rect *srcrect,
}
if ( srcY < dstY ) {
sign |= 4;
srcY += (h - 1);
dstY += (h - 1);
}
/* Set up the blit source row start, end, and skip (in pixels) */
bpp = src->format->BytesPerPixel;
sstop = sstart = ((srcY * SDL_VideoSurface->pitch)/bpp) + srcX;
stop = start = (srcY * pitch) + srcX;
if ( srcX < dstX ) {
sstart += (dstrect->w - 1);
start += (w - 1);
} else {
sstop += (dstrect->w - 1);
stop += (w - 1);
}
sskip = src->pitch/bpp;
if ( srcY < dstY ) {
sskip = -sskip;
skip = -pitch;
} else {
skip = pitch;
}
/* Set up the blit operation */
@ -209,13 +191,16 @@ static int HWAccelBlit(SDL_Surface *src, SDL_Rect *srcrect,
}
mga_wait(7);
mga_out32(MGAREG_SGN, sign);
mga_out32(MGAREG_AR3, sstart);
mga_out32(MGAREG_AR0, sstop);
mga_out32(MGAREG_AR5, sskip);
mga_out32(MGAREG_FXBNDRY, (dstX | ((dstX + dstrect->w-1) << 16)));
mga_out32(MGAREG_YDSTLEN, (dstY << 16) | dstrect->h);
mga_out32(MGAREG_AR3, start);
mga_out32(MGAREG_AR0, stop);
mga_out32(MGAREG_AR5, skip);
mga_out32(MGAREG_FXBNDRY, (dstX | ((dstX + w-1) << 16)));
mga_out32(MGAREG_YDSTLEN, (dstY << 16) | h);
mga_out32(MGAREG_DWGCTL + MGAREG_EXEC, blitop);
FB_AddBusySurface(src);
FB_AddBusySurface(dst);
return(0);
}
@ -250,9 +235,8 @@ void FB_MatroxAccel(_THIS, __u32 card)
{
/* We have hardware accelerated surface functions */
this->CheckHWBlit = CheckHWBlit;
this->LockHWSurface = LockHWSurface;
this->UnlockHWSurface = UnlockHWSurface;
wait_vbl = WaitVBL;
wait_idle = WaitIdle;
/* The Matrox has an accelerated color fill */
this->info.blit_fill = 1;

View File

@ -133,13 +133,14 @@ static int FB_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors);
static void FB_VideoQuit(_THIS);
/* Hardware surface functions */
static int FB_InitHWSurfaces(_THIS, char *base, int size);
static int FB_InitHWSurfaces(_THIS, SDL_Surface *screen, char *base, int size);
static void FB_FreeHWSurfaces(_THIS);
static int FB_AllocHWSurface(_THIS, SDL_Surface *surface);
static int FB_LockHWSurface(_THIS, SDL_Surface *surface);
static void FB_UnlockHWSurface(_THIS, SDL_Surface *surface);
static void FB_FreeHWSurface(_THIS, SDL_Surface *surface);
static void FB_WaitVBL(_THIS);
static void FB_WaitIdle(_THIS);
static int FB_FlipHWSurface(_THIS, SDL_Surface *surface);
/* Internal palette functions */
@ -191,6 +192,7 @@ static SDL_VideoDevice *FB_CreateDevice(int devindex)
}
memset(this->hidden, 0, (sizeof *this->hidden));
wait_vbl = FB_WaitVBL;
wait_idle = FB_WaitIdle;
mouse_fd = -1;
keyboard_fd = -1;
@ -665,7 +667,7 @@ static SDL_Surface *FB_SetVGA16Mode(_THIS, SDL_Surface *current,
if ( ! SDL_ReallocFormat(current, bpp, 0, 0, 0, 0) ) {
return(NULL);
}
current->format->palette->ncolors = 16;
current->format->palette->ncolors = 16;
/* Get the fixed information about the console hardware.
This is necessary since finfo.line_length changes.
@ -759,6 +761,18 @@ static SDL_Surface *FB_SetVideoMode(_THIS, SDL_Surface *current,
return(NULL);
}
}
} else {
int maxheight;
/* Figure out how much video memory is available */
if ( flags & SDL_DOUBLEBUF ) {
maxheight = height*2;
} else {
maxheight = height;
}
if ( vinfo.yres_virtual > maxheight ) {
vinfo.yres_virtual = maxheight;
}
}
cache_vinfo = vinfo;
#ifdef FBCON_DEBUG
@ -803,6 +817,13 @@ static SDL_Surface *FB_SetVideoMode(_THIS, SDL_Surface *current,
current->pitch = finfo.line_length;
current->pixels = mapped_mem+mapped_offset;
/* Set up the information for hardware surfaces */
surfaces_mem = (char *)current->pixels +
vinfo.yres_virtual*current->pitch;
surfaces_len = (mapped_memlen-(surfaces_mem-mapped_mem));
FB_FreeHWSurfaces(this);
FB_InitHWSurfaces(this, current, surfaces_mem, surfaces_len);
/* Let the application know we have a hardware palette */
switch (finfo.visual) {
case FB_VISUAL_PSEUDOCOLOR:
@ -820,17 +841,12 @@ static SDL_Surface *FB_SetVideoMode(_THIS, SDL_Surface *current,
flip_address[0] = (char *)current->pixels;
flip_address[1] = (char *)current->pixels+
current->h*current->pitch;
this->screen = current;
FB_FlipHWSurface(this, current);
this->screen = NULL;
}
}
/* Set up the information for hardware surfaces */
surfaces_mem = (char *)current->pixels +
vinfo.yres_virtual*current->pitch;
surfaces_len = (mapped_memlen-(surfaces_mem-mapped_mem));
FB_FreeHWSurfaces(this);
FB_InitHWSurfaces(this, surfaces_mem, surfaces_len);
/* Set the update rectangle function */
this->UpdateRects = FB_DirectUpdate;
@ -867,15 +883,36 @@ void FB_DumpHWSurfaces(_THIS)
}
#endif
static int FB_InitHWSurfaces(_THIS, char *base, int size)
static int FB_InitHWSurfaces(_THIS, SDL_Surface *screen, char *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 FB_FreeHWSurfaces(_THIS)
@ -956,12 +993,14 @@ surface->pitch = SDL_VideoSurface->pitch;
/* Set the current bucket values and return it! */
bucket->used = 1;
bucket->size = size;
bucket->dirty = 0;
#ifdef FBCON_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;
surface->hwdata = (struct private_hwdata *)bucket;
return(0);
}
static void FB_FreeHWSurface(_THIS, SDL_Surface *surface)
@ -970,58 +1009,64 @@ static void FB_FreeHWSurface(_THIS, SDL_Surface *surface)
/* Look for the bucket in the current list */
for ( bucket=&surfaces; bucket; bucket=bucket->next ) {
if ( bucket->base == (char *)surface->pixels ) {
if ( bucket == (vidmem_bucket *)surface->hwdata ) {
break;
}
}
if ( (bucket == NULL) || ! bucket->used ) {
return;
}
/* Add the memory back to the total */
#ifdef FBCON_DEBUG
if ( bucket && bucket->used ) {
/* Add the memory back to the total */
#ifdef DGA_DEBUG
printf("Freeing bucket of %d bytes\n", bucket->size);
#endif
surfaces_memleft += bucket->size;
surfaces_memleft += bucket->size;
/* Can we merge the space with surrounding buckets? */
bucket->used = 0;
if ( bucket->next && ! bucket->next->used ) {
#ifdef FBCON_DEBUG
/* Can we merge the space with surrounding buckets? */
bucket->used = 0;
if ( bucket->next && ! bucket->next->used ) {
#ifdef DGA_DEBUG
printf("Merging with next bucket, for %d total bytes\n", bucket->size+bucket->next->size);
#endif
freeable = bucket->next;
bucket->size += bucket->next->size;
bucket->next = bucket->next->next;
if ( bucket->next ) {
bucket->next->prev = bucket;
freeable = bucket->next;
bucket->size += bucket->next->size;
bucket->next = bucket->next->next;
if ( bucket->next ) {
bucket->next->prev = bucket;
}
free(freeable);
}
free(freeable);
}
if ( bucket->prev && ! bucket->prev->used ) {
#ifdef FBCON_DEBUG
if ( bucket->prev && ! bucket->prev->used ) {
#ifdef DGA_DEBUG
printf("Merging with previous bucket, for %d total bytes\n", bucket->prev->size+bucket->size);
#endif
freeable = bucket;
bucket->prev->size += bucket->size;
bucket->prev->next = bucket->next;
if ( bucket->next ) {
bucket->next->prev = bucket->prev;
freeable = bucket;
bucket->prev->size += bucket->size;
bucket->prev->next = bucket->next;
if ( bucket->next ) {
bucket->next->prev = bucket->prev;
}
free(freeable);
}
free(freeable);
}
surface->pixels = NULL;
surface->hwdata = NULL;
}
static int FB_LockHWSurface(_THIS, SDL_Surface *surface)
{
if ( surface == SDL_VideoSurface ) {
if ( surface == this->screen ) {
SDL_mutexP(hw_lock);
if ( FB_IsSurfaceBusy(surface) ) {
FB_WaitBusySurfaces(this);
}
} else {
if ( FB_IsSurfaceBusy(surface) ) {
FB_WaitBusySurfaces(this);
}
}
return(0);
}
static void FB_UnlockHWSurface(_THIS, SDL_Surface *surface)
{
if ( surface == SDL_VideoSurface ) {
if ( surface == this->screen ) {
SDL_mutexV(hw_lock);
}
}
@ -1034,10 +1079,18 @@ static void FB_WaitVBL(_THIS)
return;
}
static void FB_WaitIdle(_THIS)
{
return;
}
static int FB_FlipHWSurface(_THIS, SDL_Surface *surface)
{
/* Wait for vertical retrace and then flip display */
cache_vinfo.yoffset = flip_page*surface->h;
if ( FB_IsSurfaceBusy(this->screen) ) {
FB_WaitBusySurfaces(this);
}
wait_vbl(this);
if ( ioctl(console_fd, FBIOPAN_DISPLAY, &cache_vinfo) < 0 ) {
SDL_SetError("ioctl(FBIOPAN_DISPLAY) failed");

View File

@ -43,18 +43,13 @@ static char rcsid =
/* 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;
char *base;
unsigned int size;
struct vidmem_bucket *next;
} vidmem_bucket;
/* Information about the location of the surface in hardware memory */
struct private_hwdata {
int x;
int y;
};
/* Private display data */
struct SDL_PrivateVideoData {
int console_fd;
@ -90,6 +85,7 @@ struct SDL_PrivateVideoData {
SDL_mutex *hw_lock;
void (*wait_vbl)(_THIS);
void (*wait_idle)(_THIS);
};
/* Old variable names */
#define console_fd (this->hidden->console_fd)
@ -117,6 +113,7 @@ struct SDL_PrivateVideoData {
#define surfaces_memleft (this->hidden->surfaces_memleft)
#define hw_lock (this->hidden->hw_lock)
#define wait_vbl (this->hidden->wait_vbl)
#define wait_idle (this->hidden->wait_idle)
/* Accelerator types that are supported by the driver, but are not
necessarily in the kernel headers on the system we compile on.
@ -132,4 +129,39 @@ struct SDL_PrivateVideoData {
extern void FB_SavePaletteTo(_THIS, int palette_len, __u16 *area);
extern void FB_RestorePaletteFrom(_THIS, int palette_len, __u16 *area);
/* These are utility functions for working with video surfaces */
static __inline__ void FB_AddBusySurface(SDL_Surface *surface)
{
((vidmem_bucket *)surface->hwdata)->dirty = 1;
}
static __inline__ int FB_IsSurfaceBusy(SDL_Surface *surface)
{
return ((vidmem_bucket *)surface->hwdata)->dirty;
}
static __inline__ void FB_WaitBusySurfaces(_THIS)
{
vidmem_bucket *bucket;
/* Wait for graphic operations to complete */
wait_idle(this);
/* Clear all surface dirty bits */
for ( bucket=&surfaces; bucket; bucket=bucket->next ) {
bucket->dirty = 0;
}
}
static __inline__ void FB_dst_to_xy(_THIS, SDL_Surface *dst, int *x, int *y)
{
*x = (long)((char *)dst->pixels - mapped_mem)%this->screen->pitch;
*y = (long)((char *)dst->pixels - mapped_mem)/this->screen->pitch;
if ( dst == this->screen ) {
*x += this->offset_x;
*y += this->offset_y;
}
}
#endif /* _SDL_fbvideo_h */