From e53b23c07315e09b8fffb2caff281c6e786d586a Mon Sep 17 00:00:00 2001 From: Anthony Pesch Date: Sat, 25 Nov 2017 23:30:54 -0500 Subject: [PATCH] updated pvr_video_size to calculate internal resolution based on FB_R_SIZE --- src/guest/pvr/pvr.c | 103 ++++++++++++++++++++----------------- src/guest/pvr/pvr_regs.inc | 2 +- src/guest/pvr/pvr_types.h | 46 ++++++++++------- 3 files changed, 84 insertions(+), 67 deletions(-) diff --git a/src/guest/pvr/pvr.c b/src/guest/pvr/pvr.c index a74a0fdd..cd38631a 100644 --- a/src/guest/pvr/pvr.c +++ b/src/guest/pvr/pvr.c @@ -48,6 +48,29 @@ static uint32_t VRAM64(uint32_t addr32) { memory is copied and passed to the client to render */ #define PVR_FB_COOKIE 0xdeadbeef +static void pvr_framebuffer_size(struct pvr *pvr, int *width, int *height) { + *width = pvr->FB_R_SIZE->x + 1; + *height = pvr->FB_R_SIZE->y + 1; + + /* FB_R_SIZE specifies x in 32-bit units, scale as necessary if framebuffer + depth is less than 32-bit */ + switch (pvr->FB_R_CTRL->fb_depth) { + case 0: + case 1: + *width *= 2; + break; + case 2: + *width *= 4; + *width /= 3; + break; + } + + /* if interlacing, full framebuffer height is double */ + if (pvr->SPG_CONTROL->interlace) { + *height *= 2; + } +} + static int pvr_test_framebuffer(struct pvr *pvr, uint32_t addr) { uint32_t data = *(uint32_t *)&pvr->vram[VRAM64(addr)]; return data != PVR_FB_COOKIE; @@ -92,30 +115,20 @@ static int pvr_update_framebuffer(struct pvr *pvr) { return 0; } - /* values in FB_R_SIZE are in 32-bit units */ - int line_mod = (pvr->FB_R_SIZE->mod << 2) - 4; - int x_size = (pvr->FB_R_SIZE->x + 1) << 2; - int y_size = (pvr->FB_R_SIZE->y + 1); - - pvr->framebuffer_w = pvr->FB_R_SIZE->x + 1; - pvr->framebuffer_h = pvr->FB_R_SIZE->y + 1; - - /* final fb will be 2x height when interlacing */ - if (pvr->SPG_CONTROL->interlace) { - pvr->framebuffer_h *= 2; - } + pvr_framebuffer_size(pvr, &pvr->framebuffer_w, &pvr->framebuffer_h); /* convert framebuffer into a 24-bit RGB pixel buffer */ uint8_t *dst = pvr->framebuffer; uint8_t *src = pvr->vram; + /* values in FB_R_SIZE are in 32-bit units */ + int line_mod = (pvr->FB_R_SIZE->mod << 2) - 4; + int x_size = (pvr->FB_R_SIZE->x + 1) << 2; + int y_size = (pvr->FB_R_SIZE->y + 1); + switch (pvr->FB_R_CTRL->fb_depth) { case 0: case 1: { - /* FB_R_SIZE specifies x in 32-bit units, if the framebuffer is using a - 16-bit format this needs to be doubled */ - pvr->framebuffer_w *= 2; - for (int y = 0; y < y_size; y++) { for (int n = 0; n < num_fields; n++) { for (int x = 0; x < x_size; x += 2) { @@ -274,11 +287,11 @@ static void pvr_reconfigure_spg(struct pvr *pvr) { } LOG_INFO( - "pvr_reconfigure_spg mode=%s pixel_clock=%d line_clock=%d vcount=%d " - "hcount=%d interlace=%d vbstart=%d vbend=%d", - mode, pixel_clock, pvr->line_clock, pvr->SPG_LOAD->vcount, - pvr->SPG_LOAD->hcount, pvr->SPG_CONTROL->interlace, - pvr->SPG_VBLANK->vbstart, pvr->SPG_VBLANK->vbend); + "pvr_reconfigure_spg mode=%s interlace=%d pixel_clock=%d line_clock=%d " + "hcount=%d hbstart=%d hbend=%d vcount=%d vbstart=%d vbend=%d", + mode, pvr->SPG_CONTROL->interlace, pixel_clock, pvr->line_clock, + pvr->SPG_LOAD->hcount, pvr->SPG_HBLANK->hbstart, pvr->SPG_HBLANK->hbend, + pvr->SPG_LOAD->vcount, pvr->SPG_VBLANK->vbstart, pvr->SPG_VBLANK->vbend); if (pvr->line_timer) { sched_cancel_timer(sched, pvr->line_timer); @@ -361,37 +374,31 @@ uint32_t pvr_reg_read(struct pvr *pvr, uint32_t addr, uint32_t mask) { return pvr->reg[offset]; } -void pvr_video_size(struct pvr *pvr, int *video_width, int *video_height) { - int vga_mode = !pvr->SPG_CONTROL->NTSC && !pvr->SPG_CONTROL->PAL && - !pvr->SPG_CONTROL->interlace; +void pvr_video_size(struct pvr *pvr, int *width, int *height) { + /* calculate the original internal resolution used by the game based on the + framebuffer size. this is used to scale the screen space x,y coordinates + passed to the ta when rendering */ + pvr_framebuffer_size(pvr, width, height); - if (vga_mode) { - *video_width = 640; - *video_height = 480; - } else { - *video_width = 640; - *video_height = 240; - } - - if (pvr->VO_CONTROL->pixel_double) { - *video_width /= 2; - } - - if (pvr->SPG_CONTROL->interlace) { - *video_height *= 2; - } - - /* scale_x signals to scale the framebuffer down by half. do so by scaling - up the width used by the projection matrix */ + /* scale_x signals to scale down the accumulation buffer by half when copying + to the framebuffer (providing horizontal fsaa), meaning the original video + width is double the framebufffer width */ if (pvr->SCALER_CTL->scale_x) { - *video_width *= 2; + *width *= 2; } - /* scale_y is a fixed-point scaler, with 6-bits in the integer and 10-bits - in the decimal. this scale value is ignored when used for interlacing - which is not emulated */ - if (!pvr->SCALER_CTL->interlace) { - *video_height = (*video_height * pvr->SCALER_CTL->scale_y) >> 10; + /* scale_y is a fixed-point scaler, with 6-bits in the integer and 10-bits in + the decimal. the accumulation buffer is scaled by 1/scale_y, for example: + 0x200: 2.0x scale + 0x400: 1.0x scale + 0x800: 0.5x scale + reversing this operation should give us the original video height */ + *height = (*height * pvr->SCALER_CTL->scale_y) >> 10; + + /* if flicker-free type B interlacing is being used, scale the height back + down, nullifying the effect of scale_y */ + if (pvr->SCALER_CTL->interlace) { + *height /= 2; } } diff --git a/src/guest/pvr/pvr_regs.inc b/src/guest/pvr/pvr_regs.inc index 5a809ad4..9a9ba5f4 100644 --- a/src/guest/pvr/pvr_regs.inc +++ b/src/guest/pvr/pvr_regs.inc @@ -37,7 +37,7 @@ PVR_REG(0x005f80c4, SPG_TRIGGER_POS, 0x00000000, uint32_t) PVR_REG(0x005f80c8, SPG_HBLANK_INT, 0x031d0000, union spg_hblank_int) PVR_REG(0x005f80cc, SPG_VBLANK_INT, 0x01500104, union spg_vblank_int) PVR_REG(0x005f80d0, SPG_CONTROL, 0x00000000, union spg_control) -PVR_REG(0x005f80d4, SPG_HBLANK, 0x007e0345, uint32_t) +PVR_REG(0x005f80d4, SPG_HBLANK, 0x007e0345, union spg_hblank) PVR_REG(0x005f80d8, SPG_LOAD, 0x01060359, union spg_load) PVR_REG(0x005f80dc, SPG_VBLANK, 0x01500104, union spg_vblank) PVR_REG(0x005f80e0, SPG_WIDTH, 0x07f1933f, uint32_t) diff --git a/src/guest/pvr/pvr_types.h b/src/guest/pvr/pvr_types.h index f845987f..db9c7d7d 100644 --- a/src/guest/pvr/pvr_types.h +++ b/src/guest/pvr/pvr_types.h @@ -11,7 +11,7 @@ union param_base { uint32_t full; struct { uint32_t base_address : 24; - uint32_t reserved : 8; + uint32_t : 8; }; }; @@ -58,7 +58,7 @@ union fpu_shad_scale { struct { uint32_t scale_factor : 8; uint32_t intensity_volume_mode : 1; - uint32_t reserved : 23; + uint32_t : 23; }; }; @@ -69,7 +69,7 @@ union fpu_param_cfg { uint32_t ptr_burst_size : 4; uint32_t isp_burst_threshold : 6; uint32_t tsp_burst_threshold : 6; - uint32_t reserved : 1; + uint32_t : 1; uint32_t region_header_type : 1; uint32_t reserved1 : 10; }; @@ -90,7 +90,7 @@ union isp_feed_cfg { uint32_t full; struct { uint32_t presort : 1; - uint32_t reserved : 2; + uint32_t : 2; uint32_t discard : 1; uint32_t punch_size : 10; uint32_t cache_size : 10; @@ -102,9 +102,9 @@ union spg_hblank_int { uint32_t full; struct { uint32_t line_comp_val : 10; - uint32_t reserved : 2; + uint32_t : 2; uint32_t hblank_int_mode : 2; - uint32_t reserved2 : 2; + uint32_t : 2; uint32_t hblank_in_interrupt : 10; uint32_t reserved3 : 6; }; @@ -114,9 +114,9 @@ union spg_vblank_int { uint32_t full; struct { uint32_t vblank_in_line_number : 10; - uint32_t reserved : 6; + uint32_t : 6; uint32_t vblank_out_line_number : 10; - uint32_t reserved2 : 6; + uint32_t : 6; }; }; @@ -133,7 +133,7 @@ union spg_control { uint32_t PAL : 1; uint32_t sync_direction : 1; uint32_t csync_on_h : 1; - uint32_t reserved : 22; + uint32_t : 22; }; }; @@ -141,9 +141,19 @@ union spg_load { uint32_t full; struct { uint32_t hcount : 10; - uint32_t reserved : 6; + uint32_t : 6; uint32_t vcount : 10; - uint32_t reserved2 : 6; + uint32_t : 6; + }; +}; + +union spg_hblank { + uint32_t full; + struct { + uint32_t hbstart : 10; + uint32_t : 6; + uint32_t hbend : 10; + uint32_t : 6; }; }; @@ -151,9 +161,9 @@ union spg_vblank { uint32_t full; struct { uint32_t vbstart : 10; - uint32_t reserved : 6; + uint32_t : 6; uint32_t vbend : 10; - uint32_t reserved2 : 6; + uint32_t : 6; }; }; @@ -161,9 +171,9 @@ union text_control { uint32_t full; struct { uint32_t stride : 5; - uint32_t reserved : 3; + uint32_t : 3; uint32_t bankbit : 5; - uint32_t reserved2 : 3; + uint32_t : 3; uint32_t index_endian : 1; uint32_t codebook_endian : 1; uint32_t reserved3 : 14; @@ -212,7 +222,7 @@ union spg_status { uint32_t blank : 1; uint32_t hsync : 1; uint32_t vsync : 1; - uint32_t reserved : 18; + uint32_t : 18; }; }; @@ -228,7 +238,7 @@ union ta_isp_base { uint32_t full; struct { uint32_t base_address : 24; - uint32_t reserved : 8; + uint32_t : 8; }; }; @@ -236,7 +246,7 @@ union ta_yuv_tex_base { uint32_t full; struct { uint32_t base_address : 24; - uint32_t reserved : 8; + uint32_t : 8; }; };