diff --git a/src/hw/pvr/pvr_regs.inc b/src/hw/pvr/pvr_regs.inc index 25164843..5d52c557 100644 --- a/src/hw/pvr/pvr_regs.inc +++ b/src/hw/pvr/pvr_regs.inc @@ -45,7 +45,7 @@ PVR_REG(0x005f80e4, TEXT_CONTROL, 0x00000000, union text_control) PVR_REG(0x005f80e8, VO_CONTROL, 0x00000108, uint32_t) PVR_REG(0x005f80ec, VO_STARTX, 0x0000009d, uint32_t) PVR_REG(0x005f80f0, VO_STARTY, 0x00000015, uint32_t) -PVR_REG(0x005f80f4, SCALER_CTL, 0x00000400, uint32_t) +PVR_REG(0x005f80f4, SCALER_CTL, 0x00000400, union scaler_ctl) PVR_REG(0x005f8108, PAL_RAM_CTRL, 0x00000000, union pal_ram_ctrl) PVR_REG(0x005f810c, SPG_STATUS, 0x00000000, union spg_status) PVR_REG(0x005f8110, FB_BURSTCTRL, 0x00090639, uint32_t) diff --git a/src/hw/pvr/pvr_types.h b/src/hw/pvr/pvr_types.h index 44e72a7e..585684cc 100644 --- a/src/hw/pvr/pvr_types.h +++ b/src/hw/pvr/pvr_types.h @@ -156,6 +156,17 @@ union text_control { }; }; +union scaler_ctl { + uint32_t full; + struct { + uint32_t scale_y : 16; + uint32_t scale_x : 1; + uint32_t interlace : 1; + uint32_t field_select : 1; + uint32_t : 13; + }; +}; + union pal_ram_ctrl { uint32_t full; struct { diff --git a/src/hw/pvr/ta.c b/src/hw/pvr/ta.c index 1b94228a..9fc68441 100644 --- a/src/hw/pvr/ta.c +++ b/src/hw/pvr/ta.c @@ -557,10 +557,10 @@ static void ta_save_state(struct ta *ta, struct tile_ctx *ctx) { /* texture palette pixel format */ ctx->pal_pxl_format = pvr->PAL_RAM_CTRL->pixel_format; - /* write out video width to help with unprojecting the screen space + /* save out video width / height in order to unproject the screen space coordinates */ - if (pvr->SPG_CONTROL->interlace || - (!pvr->SPG_CONTROL->NTSC && !pvr->SPG_CONTROL->PAL)) { + if (!(pvr->SPG_CONTROL->NTSC || pvr->SPG_CONTROL->PAL) || + pvr->SPG_CONTROL->interlace) { /* interlaced and VGA mode both render at full resolution */ ctx->video_width = 640; ctx->video_height = 480; @@ -569,6 +569,15 @@ static void ta_save_state(struct ta *ta, struct tile_ctx *ctx) { ctx->video_height = 240; } + /* scale_x signals to scale the image down by half */ + if (pvr->SCALER_CTL->scale_x) { + ctx->video_width *= 2; + } + + /* scale_y is a fixed-point scaler, with 6-bits in the integer and 10-bits + in the decimal */ + ctx->video_height = (ctx->video_height * pvr->SCALER_CTL->scale_y) >> 10; + /* according to the hardware docs, this is the correct calculation of the background ISP address. however, in practice, the second TA buffer's ISP address comes out to be 0x800000 when booting the bios and the vram is