Added hardware stretching code to scale 640x480 to TV resolution
authorSam Lantinga <slouken@libsdl.org>
Wed, 01 Aug 2001 08:41:45 +0000
changeset 136 717f739d6ec1
parent 135 0bfcf0d2b874
child 137 4738ea544d7a
Added hardware stretching code to scale 640x480 to TV resolution There's a bug of some kind in the 16bpp code. ??
src/video/ps2gs/SDL_gsmouse.c
src/video/ps2gs/SDL_gsvideo.c
src/video/ps2gs/SDL_gsvideo.h
src/video/ps2gs/SDL_gsyuv.c
--- a/src/video/ps2gs/SDL_gsmouse.c	Wed Aug 01 05:01:08 2001 +0000
+++ b/src/video/ps2gs/SDL_gsmouse.c	Wed Aug 01 08:41:45 2001 +0000
@@ -79,7 +79,7 @@
 	screen->pixels = mapped_mem + screen->offset;
 	screen_updated = 0;
 	if ( cursor_drawn ) {
-		SDL_EraseCursorNoLock(this->screen);
+		SDL_EraseCursorNoLock(screen);
 		cursor_drawn = 0;
 		screen_updated = 1;
 	}
@@ -114,10 +114,17 @@
 			mouse_y2 = area.y+area.h;
 		}
 		image = screen_image;
-		image.y = screen->offset / screen->pitch + mouse_y1;
+		image.y += screen->offset / screen->pitch + mouse_y1;
 		image.h = mouse_y2 - mouse_y1;
-		image.ptr = mapped_mem + image.y * screen->pitch;
+		image.ptr = mapped_mem +
+		            (image.y - screen_image.y) * screen->pitch;
 		ioctl(console_fd, PS2IOC_LOADIMAGE, &image);
+
+		/* Need to scale offscreen image to TV output */
+		if ( image.y > 0 ) {
+			scaleimage_nonblock(console_fd,
+			                    tex_tags_mem, scale_tags_mem);
+		}
 	}
 
 	/* We're finished */
--- a/src/video/ps2gs/SDL_gsvideo.c	Wed Aug 01 05:01:08 2001 +0000
+++ b/src/video/ps2gs/SDL_gsvideo.c	Wed Aug 01 08:41:45 2001 +0000
@@ -235,6 +235,59 @@
 	return ioctl(fd, PS2IOC_SENDL, &plist);
 }
 
+static unsigned long long tex_tags[] __attribute__((aligned(16))) = {
+	3 | (1LL << 60),	/* GIFtag */
+	0x0e,			/* A+D */
+	0,			/* 2 */
+	PS2_GS_TEX0_1,
+	(1 << 5) + (1 << 6),
+	PS2_GS_TEX1_1,
+	0,
+	PS2_GS_TEXFLUSH
+};
+static unsigned long long scale_tags[] __attribute__((aligned(16))) = {
+	5 | (1LL << 60),	/* GIFtag */
+	0x0e,			/* A+D */
+	6 + (1 << 4) + (1 << 8),
+	PS2_GS_PRIM,
+	((unsigned long long)0 * 16) + (((unsigned long long)0 * 16) << 16),
+	PS2_GS_UV,
+	((unsigned long long)0 * 16) + (((unsigned long long)0 * 16) << 16),
+	PS2_GS_XYZ2,
+	0,			/* 8 */
+	PS2_GS_UV,
+	0,			/* 10 */
+	PS2_GS_XYZ2
+};
+
+
+int scaleimage_nonblock(int fd, unsigned long long *tm, unsigned long long *sm)
+{
+	struct ps2_plist plist;
+	struct ps2_packet packet[2];
+
+	/* initialize the variables */
+	plist.num = 2;
+	plist.packet = packet;
+
+	packet[0].ptr = tm;
+	packet[0].len = sizeof(tex_tags);
+	packet[1].ptr = sm;
+	packet[1].len = sizeof(scale_tags);
+
+	return ioctl(fd, PS2IOC_SENDL, &plist);
+}
+
+static int power_of_2(int value)
+{
+	int shift;
+
+	for ( shift = 0; (1<<shift) < value; ++shift ) {
+		/* Keep looking */ ;
+	}
+	return(shift);
+}
+
 static int GS_VideoInit(_THIS, SDL_PixelFormat *vformat)
 {
 	struct ps2_screeninfo vinfo;
@@ -261,13 +314,6 @@
 		SDL_SetError("Couldn't get console pixel format");
 		return(-1);
 	}
-#if 0
-	if ( vinfo.mode != PS2_GS_VESA ) {
-		GS_VideoQuit(this);
-		SDL_SetError("Console must be in VESA video mode");
-		return(-1);
-	}
-#endif
 	switch (vinfo.psm) {
 	    /* Supported pixel formats */
 	    case PS2_GS_PSMCT32:
@@ -308,11 +354,6 @@
 
 static SDL_Rect **GS_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
 {
-	static SDL_Rect GS_tvout_mode;
-	static SDL_Rect *GS_tvout_modes[] = {
-		&GS_tvout_mode,
-		NULL
-	};
 	static SDL_Rect GS_vesa_mode_list[] = {
 		{ 0, 0, 1280, 1024 },
 		{ 0, 0, 1024, 768 },
@@ -326,24 +367,44 @@
 		&GS_vesa_mode_list[3],
 		NULL
 	};
+	static SDL_Rect GS_tvout_stretch;
+	static SDL_Rect GS_tvout_mode;
+	static SDL_Rect *GS_tvout_modes[3];
 	SDL_Rect **modes = NULL;
 
-	if ( saved_vinfo.mode == PS2_GS_VESA ) {
-		switch (format->BitsPerPixel) {
-		    case 16:
-		    case 24:
-		    case 32:
+	switch (format->BitsPerPixel) {
+	    case 16:
+	    case 24:
+	    case 32:
+		if ( saved_vinfo.mode == PS2_GS_VESA ) {
 			modes = GS_vesa_modes;
-			break;
-		    default:
-			break;
-		}
-	} else {
-		if ( GS_formatmap[format->BitsPerPixel/8] == saved_vinfo.psm ) {
+		} else {
+			int i, j = 0;
+
+// FIXME - what's wrong with the stretch code at 16 bpp?
+if ( format->BitsPerPixel != 32 ) break;
+			/* Add a mode that we could possibly stretch to */
+			for ( i=0; GS_vesa_modes[i]; ++i ) {
+				if ( (GS_vesa_modes[i]->w == saved_vinfo.w) &&
+				     (GS_vesa_modes[i]->h != saved_vinfo.h) ) {
+					GS_tvout_stretch.w=GS_vesa_modes[i]->w;
+					GS_tvout_stretch.h=GS_vesa_modes[i]->h;
+					GS_tvout_modes[j++] = &GS_tvout_stretch;
+					break;
+				}
+			}
+			/* Add the current TV video mode */
 			GS_tvout_mode.w = saved_vinfo.w;
 			GS_tvout_mode.h = saved_vinfo.h;
+			GS_tvout_modes[j++] = &GS_tvout_mode;
+			GS_tvout_modes[j++] = NULL;
+
+			/* Return the created list of modes */
 			modes = GS_tvout_modes;
 		}
+		break;
+	    default:
+		break;
 	}
 	return(modes);
 }
@@ -368,27 +429,30 @@
 	}
 	if ( (vinfo.w != width) || (vinfo.h != height) ||
 	     (GS_pixelmasks[vinfo.psm].bpp != bpp) ) {
-		switch (width) {
-		    case 640:
-			vinfo.res = PS2_GS_640x480;
-			break;
-		    case 800:
-			vinfo.res = PS2_GS_800x600;
-			break;
-		    case 1024:
-			vinfo.res = PS2_GS_1024x768;
-			break;
-		    case 1280:
-			vinfo.res = PS2_GS_1280x1024;
-			break;
-		    default:
-			SDL_SetError("Unsupported resolution: %dx%d\n",
-			             width, height);
-			return(NULL);
+		/* If we're not in VESA mode, we have to scale resolution */
+		if ( saved_vinfo.mode == PS2_GS_VESA ) {
+			switch (width) {
+			    case 640:
+				vinfo.res = PS2_GS_640x480;
+				break;
+			    case 800:
+				vinfo.res = PS2_GS_800x600;
+				break;
+			    case 1024:
+				vinfo.res = PS2_GS_1024x768;
+				break;
+			    case 1280:
+				vinfo.res = PS2_GS_1280x1024;
+				break;
+			    default:
+				SDL_SetError("Unsupported resolution: %dx%d\n",
+					     width, height);
+				return(NULL);
+			}
+			vinfo.res |= (PS2_GS_75Hz << 8);
+			vinfo.w = width;
+			vinfo.h = height;
 		}
-		vinfo.res |= (PS2_GS_75Hz << 8);
-		vinfo.w = width;
-		vinfo.h = height;
 		vinfo.fbp = 0;
 		vinfo.psm = GS_formatmap[bpp/8];
 		if ( vinfo.psm < 0 ) {
@@ -415,8 +479,8 @@
 
 	/* Set up the new mode framebuffer */
 	current->flags = SDL_FULLSCREEN;
-	current->w = vinfo.w;
-	current->h = vinfo.h;
+	current->w = width;
+	current->h = height;
 	current->pitch = SDL_CalculatePitch(current);
 
 	/* Memory map the DMA area for block memory transfer */
@@ -425,6 +489,9 @@
 		mapped_len = pixels_len +
 		             /* Screen update DMA command area */
 		             sizeof(head_tags) + ((2 * MAXTAGS) * 16);
+		if ( saved_vinfo.mode != PS2_GS_VESA ) {
+			mapped_len += sizeof(tex_tags) + sizeof(scale_tags);
+		}
 		mapped_mem = mmap(0, mapped_len, PROT_READ|PROT_WRITE,
 		                  MAP_SHARED, memory_fd, 0);
 		if ( mapped_mem == MAP_FAILED ) {
@@ -440,12 +507,17 @@
 		screen_image.fbw = (vinfo.w + 63) / 64;
 		screen_image.psm = vinfo.psm;
 		screen_image.x = 0;
-		screen_image.y = 0;
-		screen_image.w = vinfo.w;
-		screen_image.h = vinfo.h;
+		if ( vinfo.h == height ) {
+			screen_image.y = 0;
+		} else {
+			/* Put image offscreen and scale to screen height */
+			screen_image.y = vinfo.h;
+		}
+		screen_image.w = current->w;
+		screen_image.h = current->h;
 
 		/* get screen image data size (qword aligned) */
-		screen_image_size = (vinfo.w * vinfo.h);
+		screen_image_size = (screen_image.w * screen_image.h);
 		switch (screen_image.psm) {
 		    case PS2_GS_PSMCT32:
 			screen_image_size *= 4;
@@ -465,6 +537,28 @@
 		image_tags_mem = (unsigned long long *)
 		                 ((caddr_t)head_tags_mem + sizeof(head_tags));
 		memcpy(head_tags_mem, head_tags, sizeof(head_tags));
+		if ( saved_vinfo.mode != PS2_GS_VESA ) {
+			tex_tags_mem = (unsigned long long *)
+		                 ((caddr_t)image_tags_mem + ((2*MAXTAGS)*16));
+			scale_tags_mem = (unsigned long long *)
+		                 ((caddr_t)tex_tags_mem + sizeof(tex_tags));
+			memcpy(tex_tags_mem, tex_tags, sizeof(tex_tags));
+			tex_tags_mem[2] = 
+				(vinfo.h * vinfo.w) / 64 +
+	          		((unsigned long long)screen_image.fbw << 14) +
+	          		((unsigned long long)screen_image.psm << 20) +
+	          		((unsigned long long)power_of_2(screen_image.w) << 26) +
+	          		((unsigned long long)power_of_2(screen_image.h) << 30) +
+	          		((unsigned long long)1 << 34) +
+	          		((unsigned long long)1 << 35);
+			memcpy(scale_tags_mem, scale_tags, sizeof(scale_tags));
+			scale_tags_mem[8] =
+				((unsigned long long)screen_image.w * 16) +
+			         (((unsigned long long)screen_image.h * 16) << 16);
+			scale_tags_mem[10] =
+				((unsigned long long)vinfo.w * 16) +
+			         (((unsigned long long)vinfo.h * 16) << 16);
+		}
 	}
 	current->pixels = NULL;
 	if ( getenv("SDL_FULLSCREEN_UPDATE") ) {
@@ -554,7 +648,14 @@
 	loadimage_nonblock(console_fd,
 	                   &screen_image, screen_image_size,
 	                   head_tags_mem, image_tags_mem);
-	dma_pending = 1;
+	if ( screen_image.y > 0 ) {
+		/* Need to scale offscreen image to TV output */
+		ioctl(console_fd, PS2IOC_SENDQCT, 1);
+		dma_pending = 0;
+		scaleimage_nonblock(console_fd, tex_tags_mem, scale_tags_mem);
+	} else {
+		dma_pending = 1;
+	}
 
 	/* We're finished! */
 	SDL_UnlockCursor();
--- a/src/video/ps2gs/SDL_gsvideo.h	Wed Aug 01 05:01:08 2001 +0000
+++ b/src/video/ps2gs/SDL_gsvideo.h	Wed Aug 01 08:41:45 2001 +0000
@@ -67,6 +67,8 @@
 	int screen_image_size;
 	unsigned long long *head_tags_mem;
 	unsigned long long *image_tags_mem;
+	unsigned long long *tex_tags_mem;
+	unsigned long long *scale_tags_mem;
 	int dma_pending;
 };
 /* Old variable names */
@@ -87,6 +89,11 @@
 #define screen_image_size	(this->hidden->screen_image_size)
 #define head_tags_mem		(this->hidden->head_tags_mem)
 #define image_tags_mem		(this->hidden->image_tags_mem)
+#define tex_tags_mem		(this->hidden->tex_tags_mem)
+#define scale_tags_mem		(this->hidden->scale_tags_mem)
 #define dma_pending		(this->hidden->dma_pending)
 
+/* Shared between the mouse and video code for screen update scaling */
+extern int scaleimage_nonblock(int fd,
+                               unsigned long long *tm, unsigned long long *sm);
 #endif /* _SDL_gsvideo_h */
--- a/src/video/ps2gs/SDL_gsyuv.c	Wed Aug 01 05:01:08 2001 +0000
+++ b/src/video/ps2gs/SDL_gsyuv.c	Wed Aug 01 08:41:45 2001 +0000
@@ -223,7 +223,7 @@
 	fbp = screen_image.fbp;
 	fbw = screen_image.fbw;
 	psm = screen_image.psm;
-	y = screen_image.h;	/* Offscreen video memory */
+	y = screen_image.y + screen_image.h;	/* Offscreen video memory */
 	for ( h=height/16; h; --h ) {
 		x = 0;			/* Visible video memory */
 		for ( w=width/16; w; --w ) {
@@ -273,7 +273,7 @@
 	tex_packet.len = 8 * sizeof(*tags);
 	tags[0] = 3 | (1LL << 60);	/* GIFtag */
 	tags[1] = 0x0e;			/* A+D */
-	tags[2] = (screen_image.h * screen_image.w) / 64 +
+	tags[2] = ((screen_image.y + screen_image.h) * screen_image.w) / 64 +
 	          ((unsigned long long)fbw << 14) +
 	          ((unsigned long long)psm << 20) +
 	          ((unsigned long long)power_of_2(width) << 26) +
@@ -437,6 +437,7 @@
 		     screen->format->BytesPerPixel;
 		y += (screen->offset / screen->pitch);
 	}
+	y += screen_image.y;
 	*hwdata->stretch_x1y1 = (x * 16) + ((y * 16) << 16);
 	x += (unsigned int)dstrect->w;
 	y += (unsigned int)dstrect->h;