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
--- a/src/video/fbcon/SDL_fb3dfx.c Fri Jul 13 10:15:52 2001 +0000
+++ b/src/video/fbcon/SDL_fb3dfx.c Fri Jul 13 10:19:51 2001 +0000
@@ -32,18 +32,6 @@
#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 @@
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 @@
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 @@
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 @@
{
/* 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);
--- a/src/video/fbcon/SDL_fbmatrox.c Fri Jul 13 10:15:52 2001 +0000
+++ b/src/video/fbcon/SDL_fbmatrox.c Fri Jul 13 10:19:51 2001 +0000
@@ -32,18 +32,6 @@
#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 @@
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 @@
}
/* 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 @@
/* 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 @@
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 @@
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 @@
/* 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 @@
}
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 @@
}
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 @@
{
/* 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;
--- a/src/video/fbcon/SDL_fbvideo.c Fri Jul 13 10:15:52 2001 +0000
+++ b/src/video/fbcon/SDL_fbvideo.c Fri Jul 13 10:19:51 2001 +0000
@@ -133,13 +133,14 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
}
#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 @@
/* 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 @@
/* 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 @@
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");
--- a/src/video/fbcon/SDL_fbvideo.h Fri Jul 13 10:15:52 2001 +0000
+++ b/src/video/fbcon/SDL_fbvideo.h Fri Jul 13 10:19:51 2001 +0000
@@ -43,18 +43,13 @@
/* 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 @@
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 @@
#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 @@
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 */