src/video/dga/SDL_dgavideo.c
changeset 101 825b2fa28e2e
parent 91 e85e03f195b4
child 102 9162d62280b5
     1.1 --- a/src/video/dga/SDL_dgavideo.c	Wed Jul 11 20:18:52 2001 +0000
     1.2 +++ b/src/video/dga/SDL_dgavideo.c	Thu Jul 12 20:42:22 2001 +0000
     1.3 @@ -58,7 +58,7 @@
     1.4  static void DGA_VideoQuit(_THIS);
     1.5  
     1.6  /* Hardware surface functions */
     1.7 -static int DGA_InitHWSurfaces(_THIS, Uint8 *base, int size);
     1.8 +static int DGA_InitHWSurfaces(_THIS, SDL_Surface *screen, Uint8 *base, int size);
     1.9  static void DGA_FreeHWSurfaces(_THIS);
    1.10  static int DGA_AllocHWSurface(_THIS, SDL_Surface *surface);
    1.11  static int DGA_FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color);
    1.12 @@ -409,6 +409,11 @@
    1.13  		return(-1);
    1.14  	}
    1.15  
    1.16 +#ifdef LOCK_DGA_DISPLAY
    1.17 +	/* Create the event lock so we're thread-safe.. :-/ */
    1.18 +	event_lock = SDL_CreateMutex();
    1.19 +#endif /* LOCK_DGA_DISPLAY */
    1.20 +
    1.21  	/* We're done! */
    1.22  	return(0);
    1.23  }
    1.24 @@ -535,7 +540,7 @@
    1.25  	if ( surfaces_len < 0 ) {
    1.26  		surfaces_len = 0;
    1.27  	}
    1.28 -	DGA_InitHWSurfaces(this, surfaces_mem, surfaces_len);
    1.29 +	DGA_InitHWSurfaces(this, current, surfaces_mem, surfaces_len);
    1.30  
    1.31  	/* Set the update rectangle function */
    1.32  	this->UpdateRects = DGA_DirectUpdate;
    1.33 @@ -581,15 +586,36 @@
    1.34  }
    1.35  #endif
    1.36  
    1.37 -static int DGA_InitHWSurfaces(_THIS, Uint8 *base, int size)
    1.38 +static int DGA_InitHWSurfaces(_THIS, SDL_Surface *screen, Uint8 *base, int size)
    1.39  {
    1.40 -	surfaces.prev = NULL;
    1.41 -	surfaces.used = 0;
    1.42 -	surfaces.base = base;
    1.43 -	surfaces.size = size;
    1.44 -	surfaces.next = NULL;
    1.45 +	vidmem_bucket *bucket;
    1.46 +
    1.47  	surfaces_memtotal = size;
    1.48  	surfaces_memleft = size;
    1.49 +
    1.50 +	if ( surfaces_memleft > 0 ) {
    1.51 +		bucket = (vidmem_bucket *)malloc(sizeof(*bucket));
    1.52 +		if ( bucket == NULL ) {
    1.53 +			SDL_OutOfMemory();
    1.54 +			return(-1);
    1.55 +		}
    1.56 +		bucket->prev = &surfaces;
    1.57 +		bucket->used = 0;
    1.58 +		bucket->dirty = 0;
    1.59 +		bucket->base = base;
    1.60 +		bucket->size = size;
    1.61 +		bucket->next = NULL;
    1.62 +	} else {
    1.63 +		bucket = NULL;
    1.64 +	}
    1.65 +
    1.66 +	surfaces.prev = NULL;
    1.67 +	surfaces.used = 1;
    1.68 +	surfaces.dirty = 0;
    1.69 +	surfaces.base = screen->pixels;
    1.70 +	surfaces.size = (unsigned int)((long)base - (long)surfaces.base);
    1.71 +	surfaces.next = bucket;
    1.72 +	screen->hwdata = (struct private_hwdata *)&surfaces;
    1.73  	return(0);
    1.74  }
    1.75  static void DGA_FreeHWSurfaces(_THIS)
    1.76 @@ -605,11 +631,35 @@
    1.77  	surfaces.next = NULL;
    1.78  }
    1.79  
    1.80 +static __inline__ void DGA_AddDirtySurface(SDL_Surface *surface)
    1.81 +{
    1.82 +	((vidmem_bucket *)surface->hwdata)->dirty = 1;
    1.83 +}
    1.84 +
    1.85 +static __inline__ int DGA_IsSurfaceDirty(SDL_Surface *surface)
    1.86 +{
    1.87 +	return ((vidmem_bucket *)surface->hwdata)->dirty;
    1.88 +}
    1.89 +
    1.90 +static __inline__ void DGA_WaitDirtySurfaces(_THIS)
    1.91 +{
    1.92 +	vidmem_bucket *bucket;
    1.93 +
    1.94 +	/* Wait for graphic operations to complete */
    1.95 +	XDGASync(DGA_Display, DGA_Screen);
    1.96 +
    1.97 +	/* Clear all surface dirty bits */
    1.98 +	for ( bucket=&surfaces; bucket; bucket=bucket->next ) {
    1.99 +		bucket->dirty = 0;
   1.100 +	}
   1.101 +}
   1.102 +
   1.103  static int DGA_AllocHWSurface(_THIS, SDL_Surface *surface)
   1.104  {
   1.105  	vidmem_bucket *bucket;
   1.106  	int size;
   1.107  	int extra;
   1.108 +	int retval = 0;
   1.109  
   1.110  /* Temporarily, we only allow surfaces the same width as display.
   1.111     Some blitters require the pitch between two hardware surfaces
   1.112 @@ -624,11 +674,13 @@
   1.113  #ifdef DGA_DEBUG
   1.114  	fprintf(stderr, "Allocating bucket of %d bytes\n", size);
   1.115  #endif
   1.116 +	LOCK_DISPLAY();
   1.117  
   1.118  	/* Quick check for available mem */
   1.119  	if ( size > surfaces_memleft ) {
   1.120  		SDL_SetError("Not enough video memory");
   1.121 -		return(-1);
   1.122 +		retval = -1;
   1.123 +		goto done;
   1.124  	}
   1.125  
   1.126  	/* Search for an empty bucket big enough */
   1.127 @@ -639,7 +691,8 @@
   1.128  	}
   1.129  	if ( bucket == NULL ) {
   1.130  		SDL_SetError("Video memory too fragmented");
   1.131 -		return(-1);
   1.132 +		retval = -1;
   1.133 +		goto done;
   1.134  	}
   1.135  
   1.136  	/* Create a new bucket for left-over memory */
   1.137 @@ -653,7 +706,8 @@
   1.138  		newbucket = (vidmem_bucket *)malloc(sizeof(*newbucket));
   1.139  		if ( newbucket == NULL ) {
   1.140  			SDL_OutOfMemory();
   1.141 -			return(-1);
   1.142 +			retval = -1;
   1.143 +			goto done;
   1.144  		}
   1.145  		newbucket->prev = bucket;
   1.146  		newbucket->used = 0;
   1.147 @@ -669,24 +723,24 @@
   1.148  	/* Set the current bucket values and return it! */
   1.149  	bucket->used = 1;
   1.150  	bucket->size = size;
   1.151 +	bucket->dirty = 0;
   1.152  #ifdef DGA_DEBUG
   1.153  	fprintf(stderr, "Allocated %d bytes at %p\n", bucket->size, bucket->base);
   1.154  #endif
   1.155  	surfaces_memleft -= size;
   1.156  	surface->flags |= SDL_HWSURFACE;
   1.157  	surface->pixels = bucket->base;
   1.158 -	return(0);
   1.159 +	surface->hwdata = (struct private_hwdata *)bucket;
   1.160 +done:
   1.161 +	UNLOCK_DISPLAY();
   1.162 +	return(retval);
   1.163  }
   1.164  static void DGA_FreeHWSurface(_THIS, SDL_Surface *surface)
   1.165  {
   1.166  	vidmem_bucket *bucket, *freeable;
   1.167  
   1.168  	/* Look for the bucket in the current list */
   1.169 -	for ( bucket=&surfaces; bucket; bucket=bucket->next ) {
   1.170 -		if ( bucket->base == (Uint8 *)surface->pixels ) {
   1.171 -			break;
   1.172 -		}
   1.173 -	}
   1.174 +	bucket = (vidmem_bucket *)surface->hwdata;
   1.175  	if ( (bucket == NULL) || ! bucket->used ) {
   1.176  		return;
   1.177  	}
   1.178 @@ -724,6 +778,7 @@
   1.179  		free(freeable);
   1.180  	}
   1.181  	surface->pixels = NULL;
   1.182 +	surface->hwdata = NULL;
   1.183  }
   1.184  
   1.185  static __inline__ void dst_to_xy(_THIS, SDL_Surface *dst, int *x, int *y)
   1.186 @@ -742,6 +797,7 @@
   1.187  	unsigned int w, h;
   1.188  
   1.189  	/* Don't fill the visible part of the screen, wait until flipped */
   1.190 +	LOCK_DISPLAY();
   1.191  	if ( was_flipped && (dst == this->screen) ) {
   1.192  		while ( XDGAGetViewportStatus(DGA_Display, DGA_Screen) )
   1.193  			/* Keep waiting for the hardware ... */ ;
   1.194 @@ -756,8 +812,9 @@
   1.195    printf("Hardware accelerated rectangle fill: %dx%d at %d,%d\n", w, h, x, y);
   1.196  #endif
   1.197  	XDGAFillRectangle(DGA_Display, DGA_Screen, x, y, w, h, color);
   1.198 -	sync_needed++;
   1.199  	XFlush(DGA_Display);
   1.200 +	DGA_AddDirtySurface(dst);
   1.201 +	UNLOCK_DISPLAY();
   1.202  	return(0);
   1.203  }
   1.204  
   1.205 @@ -771,6 +828,7 @@
   1.206  
   1.207  	this = current_video;
   1.208  	/* Don't blit to the visible part of the screen, wait until flipped */
   1.209 +	LOCK_DISPLAY();
   1.210  	if ( was_flipped && (dst == this->screen) ) {
   1.211  		while ( XDGAGetViewportStatus(DGA_Display, DGA_Screen) )
   1.212  			/* Keep waiting for the hardware ... */ ;
   1.213 @@ -794,8 +852,10 @@
   1.214  		XDGACopyArea(DGA_Display, DGA_Screen,
   1.215  			srcx, srcy, w, h, dstx, dsty);
   1.216  	}
   1.217 -	sync_needed++;
   1.218  	XFlush(DGA_Display);
   1.219 +	DGA_AddDirtySurface(src);
   1.220 +	DGA_AddDirtySurface(dst);
   1.221 +	UNLOCK_DISPLAY();
   1.222  	return(0);
   1.223  }
   1.224  
   1.225 @@ -826,12 +886,8 @@
   1.226  	return(accelerated);
   1.227  }
   1.228  
   1.229 -static __inline__ void DGA_WaitHardware(_THIS)
   1.230 +static __inline__ void DGA_WaitFlip(_THIS)
   1.231  {
   1.232 -	if ( sync_needed ) {
   1.233 -		XDGASync(DGA_Display, DGA_Screen);
   1.234 -		sync_needed = 0;
   1.235 -	}
   1.236  	if ( was_flipped ) {
   1.237  		while ( XDGAGetViewportStatus(DGA_Display, DGA_Screen) )
   1.238  			/* Keep waiting for the hardware ... */ ;
   1.239 @@ -841,15 +897,26 @@
   1.240  
   1.241  static int DGA_LockHWSurface(_THIS, SDL_Surface *surface)
   1.242  {
   1.243 -	if ( surface == SDL_VideoSurface ) {
   1.244 +	if ( surface == this->screen ) {
   1.245  		SDL_mutexP(hw_lock);
   1.246 -		DGA_WaitHardware(this);
   1.247 +		LOCK_DISPLAY();
   1.248 +		if ( DGA_IsSurfaceDirty(surface) ) {
   1.249 +			DGA_WaitDirtySurfaces(this);
   1.250 +		}
   1.251 +		DGA_WaitFlip(this);
   1.252 +		UNLOCK_DISPLAY();
   1.253 +	} else {
   1.254 +		if ( DGA_IsSurfaceDirty(surface) ) {
   1.255 +			LOCK_DISPLAY();
   1.256 +			DGA_WaitDirtySurfaces(this);
   1.257 +			UNLOCK_DISPLAY();
   1.258 +		}
   1.259  	}
   1.260  	return(0);
   1.261  }
   1.262  static void DGA_UnlockHWSurface(_THIS, SDL_Surface *surface)
   1.263  {
   1.264 -	if ( surface == SDL_VideoSurface ) {
   1.265 +	if ( surface == this->screen ) {
   1.266  		SDL_mutexV(hw_lock);
   1.267  	}
   1.268  }
   1.269 @@ -857,10 +924,15 @@
   1.270  static int DGA_FlipHWSurface(_THIS, SDL_Surface *surface)
   1.271  {
   1.272  	/* Wait for vertical retrace and then flip display */
   1.273 -	DGA_WaitHardware(this);
   1.274 +	LOCK_DISPLAY();
   1.275 +	if ( DGA_IsSurfaceDirty(this->screen) ) {
   1.276 +		DGA_WaitDirtySurfaces(this);
   1.277 +	}
   1.278 +	DGA_WaitFlip(this);
   1.279  	XDGASetViewport(DGA_Display, DGA_Screen,
   1.280  	                0, flip_yoffset[flip_page], XDGAFlipRetrace);
   1.281  	XFlush(DGA_Display);
   1.282 +	UNLOCK_DISPLAY();
   1.283  	was_flipped = 1;
   1.284  	flip_page = !flip_page;
   1.285  
   1.286 @@ -891,8 +963,10 @@
   1.287  		xcmap[i].blue  = (colors[i].b<<8)|colors[i].b;
   1.288  		xcmap[i].flags = (DoRed|DoGreen|DoBlue);
   1.289  	}
   1.290 +	LOCK_DISPLAY();
   1.291  	XStoreColors(DGA_Display, DGA_colormap, xcmap, ncolors);
   1.292  	XSync(DGA_Display, False);
   1.293 +	UNLOCK_DISPLAY();
   1.294  
   1.295  	/* That was easy. :) */
   1.296  	return(1);
   1.297 @@ -923,8 +997,10 @@
   1.298  		xcmap[i].blue  = ramp[2*256+c];
   1.299  		xcmap[i].flags = (DoRed|DoGreen|DoBlue);
   1.300  	}
   1.301 +	LOCK_DISPLAY();
   1.302  	XStoreColors(DGA_Display, DGA_colormap, xcmap, ncolors);
   1.303  	XSync(DGA_Display, False);
   1.304 +	UNLOCK_DISPLAY();
   1.305  	return(0);
   1.306  }
   1.307  
   1.308 @@ -952,6 +1028,13 @@
   1.309  			SDL_DestroyMutex(hw_lock);
   1.310  			hw_lock = NULL;
   1.311  		}
   1.312 +#ifdef LOCK_DGA_DISPLAY
   1.313 +		if ( event_lock != NULL ) {
   1.314 +			SDL_DestroyMutex(event_lock);
   1.315 +			event_lock = NULL;
   1.316 +		}
   1.317 +#endif /* LOCK_DGA_DISPLAY */
   1.318 +
   1.319  
   1.320  		/* Clean up defined video modes */
   1.321  		for ( i=0; i<NUM_MODELISTS; ++i ) {