Commit 3d9ea4a0 authored by Sam Lantinga's avatar Sam Lantinga

Added hardware stretching code to scale 640x480 to TV resolution

There's a bug of some kind in the 16bpp code. ??

--HG--
extra : convert_revision : svn%3Ac70aab31-4412-0410-b14c-859654838e24/trunk%40137
parent 76c91275
...@@ -79,7 +79,7 @@ static void GS_MoveCursor(_THIS, SDL_Cursor *cursor, int x, int y) ...@@ -79,7 +79,7 @@ static void GS_MoveCursor(_THIS, SDL_Cursor *cursor, int x, int y)
screen->pixels = mapped_mem + screen->offset; screen->pixels = mapped_mem + screen->offset;
screen_updated = 0; screen_updated = 0;
if ( cursor_drawn ) { if ( cursor_drawn ) {
SDL_EraseCursorNoLock(this->screen); SDL_EraseCursorNoLock(screen);
cursor_drawn = 0; cursor_drawn = 0;
screen_updated = 1; screen_updated = 1;
} }
...@@ -114,10 +114,17 @@ static void GS_MoveCursor(_THIS, SDL_Cursor *cursor, int x, int y) ...@@ -114,10 +114,17 @@ static void GS_MoveCursor(_THIS, SDL_Cursor *cursor, int x, int y)
mouse_y2 = area.y+area.h; mouse_y2 = area.y+area.h;
} }
image = screen_image; 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.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); 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 */ /* We're finished */
......
...@@ -235,6 +235,59 @@ static inline int loadimage_nonblock(int fd, struct ps2_image *image, int size, ...@@ -235,6 +235,59 @@ static inline int loadimage_nonblock(int fd, struct ps2_image *image, int size,
return ioctl(fd, PS2IOC_SENDL, &plist); 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) static int GS_VideoInit(_THIS, SDL_PixelFormat *vformat)
{ {
struct ps2_screeninfo vinfo; struct ps2_screeninfo vinfo;
...@@ -261,13 +314,6 @@ static int GS_VideoInit(_THIS, SDL_PixelFormat *vformat) ...@@ -261,13 +314,6 @@ static int GS_VideoInit(_THIS, SDL_PixelFormat *vformat)
SDL_SetError("Couldn't get console pixel format"); SDL_SetError("Couldn't get console pixel format");
return(-1); 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) { switch (vinfo.psm) {
/* Supported pixel formats */ /* Supported pixel formats */
case PS2_GS_PSMCT32: case PS2_GS_PSMCT32:
...@@ -308,11 +354,6 @@ static int GS_VideoInit(_THIS, SDL_PixelFormat *vformat) ...@@ -308,11 +354,6 @@ static int GS_VideoInit(_THIS, SDL_PixelFormat *vformat)
static SDL_Rect **GS_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags) 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[] = { static SDL_Rect GS_vesa_mode_list[] = {
{ 0, 0, 1280, 1024 }, { 0, 0, 1280, 1024 },
{ 0, 0, 1024, 768 }, { 0, 0, 1024, 768 },
...@@ -326,24 +367,44 @@ static SDL_Rect **GS_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags) ...@@ -326,24 +367,44 @@ static SDL_Rect **GS_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
&GS_vesa_mode_list[3], &GS_vesa_mode_list[3],
NULL NULL
}; };
static SDL_Rect GS_tvout_stretch;
static SDL_Rect GS_tvout_mode;
static SDL_Rect *GS_tvout_modes[3];
SDL_Rect **modes = NULL; SDL_Rect **modes = NULL;
if ( saved_vinfo.mode == PS2_GS_VESA ) { switch (format->BitsPerPixel) {
switch (format->BitsPerPixel) { case 16:
case 16: case 24:
case 24: case 32:
case 32: if ( saved_vinfo.mode == PS2_GS_VESA ) {
modes = GS_vesa_modes; modes = GS_vesa_modes;
break; } else {
default: int i, j = 0;
break;
} // FIXME - what's wrong with the stretch code at 16 bpp?
} else { if ( format->BitsPerPixel != 32 ) break;
if ( GS_formatmap[format->BitsPerPixel/8] == saved_vinfo.psm ) { /* 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.w = saved_vinfo.w;
GS_tvout_mode.h = saved_vinfo.h; 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; modes = GS_tvout_modes;
} }
break;
default:
break;
} }
return(modes); return(modes);
} }
...@@ -368,27 +429,30 @@ static SDL_Surface *GS_SetVideoMode(_THIS, SDL_Surface *current, ...@@ -368,27 +429,30 @@ static SDL_Surface *GS_SetVideoMode(_THIS, SDL_Surface *current,
} }
if ( (vinfo.w != width) || (vinfo.h != height) || if ( (vinfo.w != width) || (vinfo.h != height) ||
(GS_pixelmasks[vinfo.psm].bpp != bpp) ) { (GS_pixelmasks[vinfo.psm].bpp != bpp) ) {
switch (width) { /* If we're not in VESA mode, we have to scale resolution */
case 640: if ( saved_vinfo.mode == PS2_GS_VESA ) {
vinfo.res = PS2_GS_640x480; switch (width) {
break; case 640:
case 800: vinfo.res = PS2_GS_640x480;
vinfo.res = PS2_GS_800x600; break;
break; case 800:
case 1024: vinfo.res = PS2_GS_800x600;
vinfo.res = PS2_GS_1024x768; break;
break; case 1024:
case 1280: vinfo.res = PS2_GS_1024x768;
vinfo.res = PS2_GS_1280x1024; break;
break; case 1280:
default: vinfo.res = PS2_GS_1280x1024;
SDL_SetError("Unsupported resolution: %dx%d\n", break;
width, height); default:
return(NULL); 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.fbp = 0;
vinfo.psm = GS_formatmap[bpp/8]; vinfo.psm = GS_formatmap[bpp/8];
if ( vinfo.psm < 0 ) { if ( vinfo.psm < 0 ) {
...@@ -415,8 +479,8 @@ static SDL_Surface *GS_SetVideoMode(_THIS, SDL_Surface *current, ...@@ -415,8 +479,8 @@ static SDL_Surface *GS_SetVideoMode(_THIS, SDL_Surface *current,
/* Set up the new mode framebuffer */ /* Set up the new mode framebuffer */
current->flags = SDL_FULLSCREEN; current->flags = SDL_FULLSCREEN;
current->w = vinfo.w; current->w = width;
current->h = vinfo.h; current->h = height;
current->pitch = SDL_CalculatePitch(current); current->pitch = SDL_CalculatePitch(current);
/* Memory map the DMA area for block memory transfer */ /* Memory map the DMA area for block memory transfer */
...@@ -425,6 +489,9 @@ static SDL_Surface *GS_SetVideoMode(_THIS, SDL_Surface *current, ...@@ -425,6 +489,9 @@ static SDL_Surface *GS_SetVideoMode(_THIS, SDL_Surface *current,
mapped_len = pixels_len + mapped_len = pixels_len +
/* Screen update DMA command area */ /* Screen update DMA command area */
sizeof(head_tags) + ((2 * MAXTAGS) * 16); 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, mapped_mem = mmap(0, mapped_len, PROT_READ|PROT_WRITE,
MAP_SHARED, memory_fd, 0); MAP_SHARED, memory_fd, 0);
if ( mapped_mem == MAP_FAILED ) { if ( mapped_mem == MAP_FAILED ) {
...@@ -440,12 +507,17 @@ static SDL_Surface *GS_SetVideoMode(_THIS, SDL_Surface *current, ...@@ -440,12 +507,17 @@ static SDL_Surface *GS_SetVideoMode(_THIS, SDL_Surface *current,
screen_image.fbw = (vinfo.w + 63) / 64; screen_image.fbw = (vinfo.w + 63) / 64;
screen_image.psm = vinfo.psm; screen_image.psm = vinfo.psm;
screen_image.x = 0; screen_image.x = 0;
screen_image.y = 0; if ( vinfo.h == height ) {
screen_image.w = vinfo.w; screen_image.y = 0;
screen_image.h = vinfo.h; } 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) */ /* 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) { switch (screen_image.psm) {
case PS2_GS_PSMCT32: case PS2_GS_PSMCT32:
screen_image_size *= 4; screen_image_size *= 4;
...@@ -465,6 +537,28 @@ static SDL_Surface *GS_SetVideoMode(_THIS, SDL_Surface *current, ...@@ -465,6 +537,28 @@ static SDL_Surface *GS_SetVideoMode(_THIS, SDL_Surface *current,
image_tags_mem = (unsigned long long *) image_tags_mem = (unsigned long long *)
((caddr_t)head_tags_mem + sizeof(head_tags)); ((caddr_t)head_tags_mem + sizeof(head_tags));
memcpy(head_tags_mem, head_tags, 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; current->pixels = NULL;
if ( getenv("SDL_FULLSCREEN_UPDATE") ) { if ( getenv("SDL_FULLSCREEN_UPDATE") ) {
...@@ -554,7 +648,14 @@ static void GS_DMAFullUpdate(_THIS, int numrects, SDL_Rect *rects) ...@@ -554,7 +648,14 @@ static void GS_DMAFullUpdate(_THIS, int numrects, SDL_Rect *rects)
loadimage_nonblock(console_fd, loadimage_nonblock(console_fd,
&screen_image, screen_image_size, &screen_image, screen_image_size,
head_tags_mem, image_tags_mem); 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! */ /* We're finished! */
SDL_UnlockCursor(); SDL_UnlockCursor();
......
...@@ -67,6 +67,8 @@ struct SDL_PrivateVideoData { ...@@ -67,6 +67,8 @@ struct SDL_PrivateVideoData {
int screen_image_size; int screen_image_size;
unsigned long long *head_tags_mem; unsigned long long *head_tags_mem;
unsigned long long *image_tags_mem; unsigned long long *image_tags_mem;
unsigned long long *tex_tags_mem;
unsigned long long *scale_tags_mem;
int dma_pending; int dma_pending;
}; };
/* Old variable names */ /* Old variable names */
...@@ -87,6 +89,11 @@ struct SDL_PrivateVideoData { ...@@ -87,6 +89,11 @@ struct SDL_PrivateVideoData {
#define screen_image_size (this->hidden->screen_image_size) #define screen_image_size (this->hidden->screen_image_size)
#define head_tags_mem (this->hidden->head_tags_mem) #define head_tags_mem (this->hidden->head_tags_mem)
#define image_tags_mem (this->hidden->image_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) #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 */ #endif /* _SDL_gsvideo_h */
...@@ -223,7 +223,7 @@ SDL_Overlay *GS_CreateYUVOverlay(_THIS, int width, int height, Uint32 format, SD ...@@ -223,7 +223,7 @@ SDL_Overlay *GS_CreateYUVOverlay(_THIS, int width, int height, Uint32 format, SD
fbp = screen_image.fbp; fbp = screen_image.fbp;
fbw = screen_image.fbw; fbw = screen_image.fbw;
psm = screen_image.psm; 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 ) { for ( h=height/16; h; --h ) {
x = 0; /* Visible video memory */ x = 0; /* Visible video memory */
for ( w=width/16; w; --w ) { for ( w=width/16; w; --w ) {
...@@ -273,7 +273,7 @@ SDL_Overlay *GS_CreateYUVOverlay(_THIS, int width, int height, Uint32 format, SD ...@@ -273,7 +273,7 @@ SDL_Overlay *GS_CreateYUVOverlay(_THIS, int width, int height, Uint32 format, SD
tex_packet.len = 8 * sizeof(*tags); tex_packet.len = 8 * sizeof(*tags);
tags[0] = 3 | (1LL << 60); /* GIFtag */ tags[0] = 3 | (1LL << 60); /* GIFtag */
tags[1] = 0x0e; /* A+D */ 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)fbw << 14) +
((unsigned long long)psm << 20) + ((unsigned long long)psm << 20) +
((unsigned long long)power_of_2(width) << 26) + ((unsigned long long)power_of_2(width) << 26) +
...@@ -437,6 +437,7 @@ int GS_DisplayYUVOverlay(_THIS, SDL_Overlay *overlay, SDL_Rect *dstrect) ...@@ -437,6 +437,7 @@ int GS_DisplayYUVOverlay(_THIS, SDL_Overlay *overlay, SDL_Rect *dstrect)
screen->format->BytesPerPixel; screen->format->BytesPerPixel;
y += (screen->offset / screen->pitch); y += (screen->offset / screen->pitch);
} }
y += screen_image.y;
*hwdata->stretch_x1y1 = (x * 16) + ((y * 16) << 16); *hwdata->stretch_x1y1 = (x * 16) + ((y * 16) << 16);
x += (unsigned int)dstrect->w; x += (unsigned int)dstrect->w;
y += (unsigned int)dstrect->h; y += (unsigned int)dstrect->h;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment