nv2a: Handle SIZE_IN > SIZE_OUT case

`NV_PVIDEO_SIZE_IN` is set to 0xFFFFFFFF during initialization and teardown
of the PVIDEO overlay. In some cases this can happen before the overlay is
explicitly stopped, leading to an assert. On hardware SIZE_IN values larger
than SIZE_OUT are capped (content is not scaled).

Fixes #330

[Test](https://github.com/abaire/nxdk_pgraph_tests/blob/main/src/tests/pvideo_tests.cpp)
This commit is contained in:
Erik Abair 2022-07-08 09:35:57 -07:00 committed by mborgerson
parent 8d274e5f9a
commit a675666051
2 changed files with 18 additions and 5 deletions

View File

@ -278,6 +278,7 @@ static void nv2a_reset(NV2AState *d)
memset(d->pfifo.regs, 0, sizeof(d->pfifo.regs));
memset(d->pgraph.regs, 0, sizeof(d->pgraph.regs));
memset(d->pvideo.regs, 0, sizeof(d->pvideo.regs));
d->pcrtc.start = 0;
d->pramdac.core_clock_coeff = 0x00011C01; /* 189MHz...? */

View File

@ -5054,8 +5054,9 @@ static uint8_t *convert_texture_data__CR8YB8CB8YA8(const uint8_t *data,
int x, y;
for (y = 0; y < height; y++) {
const uint8_t *line = &data[y * pitch];
const uint32_t row_offset = y * width;
for (x = 0; x < width; x++) {
uint8_t *pixel = &converted_data[(y * width + x) * 4];
uint8_t *pixel = &converted_data[(row_offset + x) * 4];
convert_yuy2_to_rgb(line, x, &pixel[0], &pixel[1], &pixel[2]);
pixel[3] = 255;
}
@ -5093,14 +5094,25 @@ static void pgraph_render_display_pvideo_overlay(NV2AState *d)
int in_color =
GET_MASK(d->pvideo.regs[NV_PVIDEO_FORMAT], NV_PVIDEO_FORMAT_COLOR);
/* TODO: support other color formats */
assert(in_color == NV_PVIDEO_FORMAT_COLOR_LE_CR8YB8CB8YA8);
assert(in_pitch >= in_width * 2);
unsigned int out_width =
GET_MASK(d->pvideo.regs[NV_PVIDEO_SIZE_OUT], NV_PVIDEO_SIZE_OUT_WIDTH);
unsigned int out_height =
GET_MASK(d->pvideo.regs[NV_PVIDEO_SIZE_OUT], NV_PVIDEO_SIZE_OUT_HEIGHT);
// On HW, setting NV_PVIDEO_SIZE_IN larger than NV_PVIDEO_SIZE_OUT results
// in them being capped to the output size, content is not scaled. This is
// particularly important as NV_PVIDEO_SIZE_IN may be set to 0xFFFFFFFF
// during initialization or teardown.
if (in_width > out_width) {
in_width = out_width;
}
if (in_height > out_height) {
in_height = out_height;
}
/* TODO: support other color formats */
assert(in_color == NV_PVIDEO_FORMAT_COLOR_LE_CR8YB8CB8YA8);
unsigned int out_x =
GET_MASK(d->pvideo.regs[NV_PVIDEO_POINT_OUT], NV_PVIDEO_POINT_OUT_X);
unsigned int out_y =