updated pvr_video_size to calculate internal resolution based on FB_R_SIZE

This commit is contained in:
Anthony Pesch 2017-11-25 23:30:54 -05:00
parent cdfbb58a6b
commit e53b23c073
3 changed files with 84 additions and 67 deletions

View File

@ -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;
}
}

View File

@ -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)

View File

@ -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;
};
};