LLE : Get overlay animating by calling UpdateHostDisplay from pvideo_vga_invalidate.
Also added experimental PVIDEO interrupts (didn't seem to help)
This commit is contained in:
parent
5a6a37f5fb
commit
2734bcf212
|
@ -101,6 +101,14 @@ static void update_irq(NV2AState *d)
|
|||
d->pmc.pending_interrupts &= ~NV_PMC_INTR_0_PGRAPH;
|
||||
}
|
||||
|
||||
/* PVIDEO */
|
||||
if (d->pvideo.pending_interrupts & d->pvideo.enabled_interrupts) {
|
||||
d->pmc.pending_interrupts |= NV_PMC_INTR_0_PVIDEO;
|
||||
}
|
||||
else {
|
||||
d->pmc.pending_interrupts &= ~NV_PMC_INTR_0_PVIDEO;
|
||||
}
|
||||
|
||||
/* TODO : PBUS * /
|
||||
if (d->pbus.pending_interrupts & d->pbus.enabled_interrupts) {
|
||||
d->pmc.pending_interrupts |= NV_PMC_INTR_0_PBUS;
|
||||
|
|
|
@ -753,14 +753,14 @@ static void pgraph_handle_method(NV2AState *d,
|
|||
|
||||
// TODO: Fix this (why does it hang?)
|
||||
/* while (true) */ {
|
||||
uint32_t surface = pg->regs[NV_PGRAPH_SURFACE];
|
||||
NV2A_DPRINTF("flip stall read: %d, write: %d, modulo: %d\n",
|
||||
GET_MASK(pg->regs[NV_PGRAPH_SURFACE], NV_PGRAPH_SURFACE_READ_3D),
|
||||
GET_MASK(pg->regs[NV_PGRAPH_SURFACE], NV_PGRAPH_SURFACE_WRITE_3D),
|
||||
GET_MASK(pg->regs[NV_PGRAPH_SURFACE], NV_PGRAPH_SURFACE_MODULO_3D));
|
||||
GET_MASK(surface, NV_PGRAPH_SURFACE_READ_3D),
|
||||
GET_MASK(surface, NV_PGRAPH_SURFACE_WRITE_3D),
|
||||
GET_MASK(surface, NV_PGRAPH_SURFACE_MODULO_3D));
|
||||
|
||||
uint32_t s = pg->regs[NV_PGRAPH_SURFACE];
|
||||
if (GET_MASK(s, NV_PGRAPH_SURFACE_READ_3D)
|
||||
!= GET_MASK(s, NV_PGRAPH_SURFACE_WRITE_3D)) {
|
||||
if (GET_MASK(surface, NV_PGRAPH_SURFACE_READ_3D)
|
||||
!= GET_MASK(surface, NV_PGRAPH_SURFACE_WRITE_3D)) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -768,7 +768,7 @@ static void pgraph_handle_method(NV2AState *d,
|
|||
}
|
||||
|
||||
// TODO: Remove this when the AMD crash is solved in vblank_thread
|
||||
NV2ADevice::SwapBuffers(d);
|
||||
NV2ADevice::UpdateHostDisplay(d);
|
||||
NV2A_DPRINTF("flip stall done\n");
|
||||
break;
|
||||
|
||||
|
@ -965,15 +965,15 @@ static void pgraph_handle_method(NV2AState *d,
|
|||
parameter);
|
||||
break;
|
||||
case NV097_SET_FOG_COLOR: {
|
||||
/* PGRAPH channels are ARGB, parameter channels are ABGR */
|
||||
uint8_t red = GET_MASK(parameter, NV097_SET_FOG_COLOR_RED);
|
||||
uint8_t green = GET_MASK(parameter, NV097_SET_FOG_COLOR_GREEN);
|
||||
uint8_t blue = GET_MASK(parameter, NV097_SET_FOG_COLOR_BLUE);
|
||||
/* parameter channels are ABGR, PGRAPH channels are ARGB */
|
||||
uint8_t alpha = GET_MASK(parameter, NV097_SET_FOG_COLOR_ALPHA);
|
||||
uint8_t blue = GET_MASK(parameter, NV097_SET_FOG_COLOR_BLUE);
|
||||
uint8_t green = GET_MASK(parameter, NV097_SET_FOG_COLOR_GREEN);
|
||||
uint8_t red = GET_MASK(parameter, NV097_SET_FOG_COLOR_RED);
|
||||
SET_MASK(pg->regs[NV_PGRAPH_FOGCOLOR], NV_PGRAPH_FOGCOLOR_ALPHA, alpha);
|
||||
SET_MASK(pg->regs[NV_PGRAPH_FOGCOLOR], NV_PGRAPH_FOGCOLOR_RED, red);
|
||||
SET_MASK(pg->regs[NV_PGRAPH_FOGCOLOR], NV_PGRAPH_FOGCOLOR_GREEN, green);
|
||||
SET_MASK(pg->regs[NV_PGRAPH_FOGCOLOR], NV_PGRAPH_FOGCOLOR_BLUE, blue);
|
||||
SET_MASK(pg->regs[NV_PGRAPH_FOGCOLOR], NV_PGRAPH_FOGCOLOR_ALPHA, alpha);
|
||||
break;
|
||||
}
|
||||
case NV097_SET_ALPHA_TEST_ENABLE:
|
||||
|
@ -1770,9 +1770,12 @@ static void pgraph_handle_method(NV2AState *d,
|
|||
case NV097_SET_BEGIN_END: {
|
||||
lockGL(pg);
|
||||
|
||||
bool depth_test =
|
||||
pg->regs[NV_PGRAPH_CONTROL_0] & NV_PGRAPH_CONTROL_0_ZENABLE;
|
||||
bool stencil_test = pg->regs[NV_PGRAPH_CONTROL_1]
|
||||
uint32_t control_0 = pg->regs[NV_PGRAPH_CONTROL_0];
|
||||
uint32_t control_1 = pg->regs[NV_PGRAPH_CONTROL_1];
|
||||
|
||||
bool depth_test = control_0
|
||||
& NV_PGRAPH_CONTROL_0_ZENABLE;
|
||||
bool stencil_test = control_1
|
||||
& NV_PGRAPH_CONTROL_1_STENCIL_TEST_ENABLE;
|
||||
|
||||
if (pg->opengl_enabled) {
|
||||
|
@ -1890,29 +1893,28 @@ static void pgraph_handle_method(NV2AState *d,
|
|||
|
||||
pg->primitive_mode = parameter;
|
||||
|
||||
uint32_t control_0 = pg->regs[NV_PGRAPH_CONTROL_0];
|
||||
|
||||
bool alpha = control_0 & NV_PGRAPH_CONTROL_0_ALPHA_WRITE_ENABLE;
|
||||
bool red = control_0 & NV_PGRAPH_CONTROL_0_RED_WRITE_ENABLE;
|
||||
bool green = control_0 & NV_PGRAPH_CONTROL_0_GREEN_WRITE_ENABLE;
|
||||
bool blue = control_0 & NV_PGRAPH_CONTROL_0_BLUE_WRITE_ENABLE;
|
||||
glColorMask(red, green, blue, alpha);
|
||||
glDepthMask(!!(control_0 & NV_PGRAPH_CONTROL_0_ZWRITEENABLE));
|
||||
glStencilMask(GET_MASK(pg->regs[NV_PGRAPH_CONTROL_1],
|
||||
glStencilMask(GET_MASK(control_1,
|
||||
NV_PGRAPH_CONTROL_1_STENCIL_MASK_WRITE));
|
||||
|
||||
if (pg->regs[NV_PGRAPH_BLEND] & NV_PGRAPH_BLEND_EN) {
|
||||
uint32_t blend = pg->regs[NV_PGRAPH_BLEND];
|
||||
if (blend & NV_PGRAPH_BLEND_EN) {
|
||||
glEnable(GL_BLEND);
|
||||
uint32_t sfactor = GET_MASK(pg->regs[NV_PGRAPH_BLEND],
|
||||
uint32_t sfactor = GET_MASK(blend,
|
||||
NV_PGRAPH_BLEND_SFACTOR);
|
||||
uint32_t dfactor = GET_MASK(pg->regs[NV_PGRAPH_BLEND],
|
||||
uint32_t dfactor = GET_MASK(blend,
|
||||
NV_PGRAPH_BLEND_DFACTOR);
|
||||
assert(sfactor < ARRAY_SIZE(pgraph_blend_factor_map));
|
||||
assert(dfactor < ARRAY_SIZE(pgraph_blend_factor_map));
|
||||
glBlendFunc(pgraph_blend_factor_map[sfactor],
|
||||
pgraph_blend_factor_map[dfactor]);
|
||||
|
||||
uint32_t equation = GET_MASK(pg->regs[NV_PGRAPH_BLEND],
|
||||
uint32_t equation = GET_MASK(blend,
|
||||
NV_PGRAPH_BLEND_EQN);
|
||||
assert(equation < ARRAY_SIZE(pgraph_blend_equation_map));
|
||||
glBlendEquation(pgraph_blend_equation_map[equation]);
|
||||
|
@ -1927,9 +1929,10 @@ static void pgraph_handle_method(NV2AState *d,
|
|||
}
|
||||
|
||||
/* Face culling */
|
||||
if (pg->regs[NV_PGRAPH_SETUPRASTER]
|
||||
uint32_t setupraster = pg->regs[NV_PGRAPH_SETUPRASTER];
|
||||
if (setupraster
|
||||
& NV_PGRAPH_SETUPRASTER_CULLENABLE) {
|
||||
uint32_t cull_face = GET_MASK(pg->regs[NV_PGRAPH_SETUPRASTER],
|
||||
uint32_t cull_face = GET_MASK(setupraster,
|
||||
NV_PGRAPH_SETUPRASTER_CULLCTRL);
|
||||
assert(cull_face < ARRAY_SIZE(pgraph_cull_face_map));
|
||||
glCullFace(pgraph_cull_face_map[cull_face]);
|
||||
|
@ -1939,31 +1942,31 @@ static void pgraph_handle_method(NV2AState *d,
|
|||
}
|
||||
|
||||
/* Front-face select */
|
||||
glFrontFace(pg->regs[NV_PGRAPH_SETUPRASTER]
|
||||
glFrontFace(setupraster
|
||||
& NV_PGRAPH_SETUPRASTER_FRONTFACE
|
||||
? GL_CCW : GL_CW);
|
||||
|
||||
/* Polygon offset */
|
||||
/* FIXME: GL implementation-specific, maybe do this in VS? */
|
||||
if (pg->regs[NV_PGRAPH_SETUPRASTER] &
|
||||
if (setupraster &
|
||||
NV_PGRAPH_SETUPRASTER_POFFSETFILLENABLE) {
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
} else {
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
}
|
||||
if (pg->regs[NV_PGRAPH_SETUPRASTER] &
|
||||
if (setupraster &
|
||||
NV_PGRAPH_SETUPRASTER_POFFSETLINEENABLE) {
|
||||
glEnable(GL_POLYGON_OFFSET_LINE);
|
||||
} else {
|
||||
glDisable(GL_POLYGON_OFFSET_LINE);
|
||||
}
|
||||
if (pg->regs[NV_PGRAPH_SETUPRASTER] &
|
||||
if (setupraster &
|
||||
NV_PGRAPH_SETUPRASTER_POFFSETPOINTENABLE) {
|
||||
glEnable(GL_POLYGON_OFFSET_POINT);
|
||||
} else {
|
||||
glDisable(GL_POLYGON_OFFSET_POINT);
|
||||
}
|
||||
if (pg->regs[NV_PGRAPH_SETUPRASTER] &
|
||||
if (setupraster &
|
||||
(NV_PGRAPH_SETUPRASTER_POFFSETFILLENABLE |
|
||||
NV_PGRAPH_SETUPRASTER_POFFSETLINEENABLE |
|
||||
NV_PGRAPH_SETUPRASTER_POFFSETPOINTENABLE)) {
|
||||
|
@ -1976,7 +1979,7 @@ static void pgraph_handle_method(NV2AState *d,
|
|||
if (depth_test) {
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
uint32_t depth_func = GET_MASK(pg->regs[NV_PGRAPH_CONTROL_0],
|
||||
uint32_t depth_func = GET_MASK(control_0,
|
||||
NV_PGRAPH_CONTROL_0_ZFUNC);
|
||||
assert(depth_func < ARRAY_SIZE(pgraph_depth_func_map));
|
||||
glDepthFunc(pgraph_depth_func_map[depth_func]);
|
||||
|
@ -1987,17 +1990,18 @@ static void pgraph_handle_method(NV2AState *d,
|
|||
if (stencil_test) {
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
|
||||
uint32_t stencil_func = GET_MASK(pg->regs[NV_PGRAPH_CONTROL_1],
|
||||
uint32_t stencil_func = GET_MASK(control_1,
|
||||
NV_PGRAPH_CONTROL_1_STENCIL_FUNC);
|
||||
uint32_t stencil_ref = GET_MASK(pg->regs[NV_PGRAPH_CONTROL_1],
|
||||
uint32_t stencil_ref = GET_MASK(control_1,
|
||||
NV_PGRAPH_CONTROL_1_STENCIL_REF);
|
||||
uint32_t func_mask = GET_MASK(pg->regs[NV_PGRAPH_CONTROL_1],
|
||||
uint32_t func_mask = GET_MASK(control_1,
|
||||
NV_PGRAPH_CONTROL_1_STENCIL_MASK_READ);
|
||||
uint32_t op_fail = GET_MASK(pg->regs[NV_PGRAPH_CONTROL_2],
|
||||
uint32_t control2 = pg->regs[NV_PGRAPH_CONTROL_2];
|
||||
uint32_t op_fail = GET_MASK(control2,
|
||||
NV_PGRAPH_CONTROL_2_STENCIL_OP_FAIL);
|
||||
uint32_t op_zfail = GET_MASK(pg->regs[NV_PGRAPH_CONTROL_2],
|
||||
uint32_t op_zfail = GET_MASK(control2,
|
||||
NV_PGRAPH_CONTROL_2_STENCIL_OP_ZFAIL);
|
||||
uint32_t op_zpass = GET_MASK(pg->regs[NV_PGRAPH_CONTROL_2],
|
||||
uint32_t op_zpass = GET_MASK(control2,
|
||||
NV_PGRAPH_CONTROL_2_STENCIL_OP_ZPASS);
|
||||
|
||||
assert(stencil_func < ARRAY_SIZE(pgraph_stencil_func_map));
|
||||
|
@ -2021,7 +2025,7 @@ static void pgraph_handle_method(NV2AState *d,
|
|||
|
||||
/* Dither */
|
||||
/* FIXME: GL implementation dependent */
|
||||
if (pg->regs[NV_PGRAPH_CONTROL_0] &
|
||||
if (control_0 &
|
||||
NV_PGRAPH_CONTROL_0_DITHERENABLE) {
|
||||
glEnable(GL_DITHER);
|
||||
} else {
|
||||
|
@ -2078,9 +2082,9 @@ static void pgraph_handle_method(NV2AState *d,
|
|||
bool dma_select =
|
||||
GET_MASK(parameter, NV097_SET_TEXTURE_FORMAT_CONTEXT_DMA) == 2;
|
||||
bool cubemap =
|
||||
GET_MASK(parameter, NV097_SET_TEXTURE_FORMAT_CUBEMAP_ENABLE);
|
||||
unsigned int border_source =
|
||||
GET_MASK(parameter, NV097_SET_TEXTURE_FORMAT_BORDER_SOURCE);
|
||||
parameter & NV097_SET_TEXTURE_FORMAT_CUBEMAP_ENABLE;
|
||||
bool border_source =
|
||||
parameter & NV097_SET_TEXTURE_FORMAT_BORDER_SOURCE;
|
||||
unsigned int dimensionality =
|
||||
GET_MASK(parameter, NV097_SET_TEXTURE_FORMAT_DIMENSIONALITY);
|
||||
unsigned int color_format =
|
||||
|
@ -2919,7 +2923,6 @@ static void pgraph_update_shader_constants(PGRAPHState *pg,
|
|||
*(float*)&pg->regs[NV_PGRAPH_FOGPARAM1]);
|
||||
}
|
||||
|
||||
|
||||
float zclip_max = *(float*)&pg->regs[NV_PGRAPH_ZCLIPMAX];
|
||||
float zclip_min = *(float*)&pg->regs[NV_PGRAPH_ZCLIPMIN];
|
||||
|
||||
|
@ -2931,6 +2934,7 @@ static void pgraph_update_shader_constants(PGRAPHState *pg,
|
|||
GLint* locs;
|
||||
size_t len;
|
||||
} lighting_arrays[] = {
|
||||
// TODO : Change pointers into offset_of(), so this variable can become static
|
||||
{&pg->ltctxa[0][0], &pg->ltctxa_dirty[0], binding->ltctxa_loc, NV2A_LTCTXA_COUNT},
|
||||
{&pg->ltctxb[0][0], &pg->ltctxb_dirty[0], binding->ltctxb_loc, NV2A_LTCTXB_COUNT},
|
||||
{&pg->ltc1[0][0], &pg->ltc1_dirty[0], binding->ltc1_loc, NV2A_LTC1_COUNT},
|
||||
|
@ -3029,13 +3033,15 @@ static void pgraph_bind_shaders(PGRAPHState *pg)
|
|||
|
||||
unsigned int i, j;
|
||||
|
||||
bool vertex_program = GET_MASK(pg->regs[NV_PGRAPH_CSV0_D],
|
||||
uint32_t csv0_d = pg->regs[NV_PGRAPH_CSV0_D];
|
||||
bool vertex_program = GET_MASK(csv0_d,
|
||||
NV_PGRAPH_CSV0_D_MODE) == 2;
|
||||
|
||||
bool fixed_function = GET_MASK(pg->regs[NV_PGRAPH_CSV0_D],
|
||||
bool fixed_function = GET_MASK(csv0_d,
|
||||
NV_PGRAPH_CSV0_D_MODE) == 0;
|
||||
|
||||
int program_start = GET_MASK(pg->regs[NV_PGRAPH_CSV0_C],
|
||||
uint32_t csv0_c = pg->regs[NV_PGRAPH_CSV0_C];
|
||||
int program_start = GET_MASK(csv0_c,
|
||||
NV_PGRAPH_CSV0_C_CHEOPS_PROGRAM_START);
|
||||
|
||||
NV2A_GL_DGROUP_BEGIN("%s (VP: %s FFP: %s)", __func__,
|
||||
|
@ -3051,25 +3057,26 @@ static void pgraph_bind_shaders(PGRAPHState *pg)
|
|||
state.psh.other_stage_input = pg->regs[NV_PGRAPH_SHADERCTL];
|
||||
state.psh.final_inputs_0 = pg->regs[NV_PGRAPH_COMBINESPECFOG0];
|
||||
state.psh.final_inputs_1 = pg->regs[NV_PGRAPH_COMBINESPECFOG1];
|
||||
uint32_t control0 = pg->regs[NV_PGRAPH_CONTROL_0];
|
||||
|
||||
state.psh.alpha_test = pg->regs[NV_PGRAPH_CONTROL_0]
|
||||
state.psh.alpha_test = control0
|
||||
& NV_PGRAPH_CONTROL_0_ALPHATESTENABLE;
|
||||
state.psh.alpha_func = (enum PshAlphaFunc)GET_MASK(pg->regs[NV_PGRAPH_CONTROL_0],
|
||||
state.psh.alpha_func = (enum PshAlphaFunc)GET_MASK(control0,
|
||||
NV_PGRAPH_CONTROL_0_ALPHAFUNC);
|
||||
|
||||
/* fixed function stuff */
|
||||
state.skinning = (enum VshSkinning)GET_MASK(pg->regs[NV_PGRAPH_CSV0_D],
|
||||
state.skinning = (enum VshSkinning)GET_MASK(csv0_d,
|
||||
NV_PGRAPH_CSV0_D_SKIN);
|
||||
state.lighting = GET_MASK(pg->regs[NV_PGRAPH_CSV0_C],
|
||||
NV_PGRAPH_CSV0_C_LIGHTING);
|
||||
state.normalization = pg->regs[NV_PGRAPH_CSV0_C]
|
||||
state.lighting = csv0_c
|
||||
& NV_PGRAPH_CSV0_C_LIGHTING;
|
||||
state.normalization = csv0_c
|
||||
& NV_PGRAPH_CSV0_C_NORMALIZATION_ENABLE;
|
||||
|
||||
state.fixed_function = fixed_function;
|
||||
|
||||
/* vertex program stuff */
|
||||
state.vertex_program = vertex_program;
|
||||
state.z_perspective = pg->regs[NV_PGRAPH_CONTROL_0]
|
||||
state.z_perspective = control0
|
||||
& NV_PGRAPH_CONTROL_0_Z_PERSPECTIVE_ENABLE;
|
||||
|
||||
/* geometry shader stuff */
|
||||
|
@ -3119,7 +3126,7 @@ static void pgraph_bind_shaders(PGRAPHState *pg)
|
|||
/*FIXME: Use CSV0_D? */
|
||||
state.fog_mode = (enum VshFogMode)GET_MASK(pg->regs[NV_PGRAPH_CONTROL_3],
|
||||
NV_PGRAPH_CONTROL_3_FOG_MODE);
|
||||
state.foggen = (enum VshFoggen)GET_MASK(pg->regs[NV_PGRAPH_CSV0_D],
|
||||
state.foggen = (enum VshFoggen)GET_MASK(csv0_d,
|
||||
NV_PGRAPH_CSV0_D_FOGGENMODE);
|
||||
} else {
|
||||
/* FIXME: Do we still pass the fogmode? */
|
||||
|
@ -3135,7 +3142,7 @@ static void pgraph_bind_shaders(PGRAPHState *pg)
|
|||
/* Lighting */
|
||||
if (state.lighting) {
|
||||
for (i = 0; i < NV2A_MAX_LIGHTS; i++) {
|
||||
state.light[i] = (enum VshLight)GET_MASK(pg->regs[NV_PGRAPH_CSV0_D],
|
||||
state.light[i] = (enum VshLight)GET_MASK(csv0_d,
|
||||
NV_PGRAPH_CSV0_D_LIGHT0 << (i * 2));
|
||||
}
|
||||
}
|
||||
|
@ -3571,7 +3578,7 @@ static void pgraph_bind_textures(NV2AState *d)
|
|||
uint32_t address = pg->regs[NV_PGRAPH_TEXADDRESS0 + i*4];
|
||||
uint32_t palette = pg->regs[NV_PGRAPH_TEXPALETTE0 + i*4];
|
||||
|
||||
bool enabled = GET_MASK(ctl_0, NV_PGRAPH_TEXCTL0_0_ENABLE);
|
||||
bool enabled = ctl_0 & NV_PGRAPH_TEXCTL0_0_ENABLE;
|
||||
unsigned int min_mipmap_level =
|
||||
GET_MASK(ctl_0, NV_PGRAPH_TEXCTL0_0_MIN_LOD_CLAMP);
|
||||
unsigned int max_mipmap_level =
|
||||
|
@ -3580,10 +3587,10 @@ static void pgraph_bind_textures(NV2AState *d)
|
|||
unsigned int pitch =
|
||||
GET_MASK(ctl_1, NV_PGRAPH_TEXCTL1_0_IMAGE_PITCH);
|
||||
|
||||
unsigned int dma_select =
|
||||
GET_MASK(fmt, NV_PGRAPH_TEXFMT0_CONTEXT_DMA);
|
||||
bool dma_select =
|
||||
fmt & NV_PGRAPH_TEXFMT0_CONTEXT_DMA;
|
||||
bool cubemap =
|
||||
GET_MASK(fmt, NV_PGRAPH_TEXFMT0_CUBEMAPENABLE);
|
||||
fmt & NV_PGRAPH_TEXFMT0_CUBEMAPENABLE;
|
||||
unsigned int dimensionality =
|
||||
GET_MASK(fmt, NV_PGRAPH_TEXFMT0_DIMENSIONALITY);
|
||||
unsigned int color_format = GET_MASK(fmt, NV_PGRAPH_TEXFMT0_COLOR);
|
||||
|
@ -3608,14 +3615,13 @@ static void pgraph_bind_textures(NV2AState *d)
|
|||
unsigned int addrv = GET_MASK(address, NV_PGRAPH_TEXADDRESS0_ADDRV);
|
||||
unsigned int addrp = GET_MASK(address, NV_PGRAPH_TEXADDRESS0_ADDRP);
|
||||
|
||||
unsigned int border_source = GET_MASK(fmt,
|
||||
NV_PGRAPH_TEXFMT0_BORDER_SOURCE);
|
||||
bool border_source_color = (fmt & NV_PGRAPH_TEXFMT0_BORDER_SOURCE); // != NV_PGRAPH_TEXFMT0_BORDER_SOURCE_TEXTURE;
|
||||
uint32_t border_color = pg->regs[NV_PGRAPH_BORDERCOLOR0 + i*4];
|
||||
|
||||
unsigned int offset = pg->regs[NV_PGRAPH_TEXOFFSET0 + i*4];
|
||||
|
||||
bool palette_dma_select =
|
||||
GET_MASK(palette, NV_PGRAPH_TEXPALETTE0_CONTEXT_DMA);
|
||||
palette & NV_PGRAPH_TEXPALETTE0_CONTEXT_DMA;
|
||||
unsigned int palette_length_index =
|
||||
GET_MASK(palette, NV_PGRAPH_TEXPALETTE0_LENGTH);
|
||||
unsigned int palette_offset =
|
||||
|
@ -3862,7 +3868,7 @@ static void pgraph_bind_textures(NV2AState *d)
|
|||
}
|
||||
|
||||
/* FIXME: Only upload if necessary? [s, t or r = GL_CLAMP_TO_BORDER] */
|
||||
if (border_source == NV_PGRAPH_TEXFMT0_BORDER_SOURCE_COLOR) {
|
||||
if (border_source_color) {
|
||||
GLfloat gl_border_color[] = {
|
||||
/* FIXME: Color channels might be wrong order */
|
||||
((border_color >> 16) & 0xFF) / 255.0f, /* red */
|
||||
|
|
|
@ -6,12 +6,21 @@ static void pvideo_vga_invalidate(NV2AState *d)
|
|||
NV_PVIDEO_SIZE_OUT_HEIGHT);
|
||||
NV2A_DPRINTF("pvideo_vga_invalidate %d %d\n", y1, y2);
|
||||
// TODO : vga_invalidate_scanlines(&d->vga, y1, y2);
|
||||
|
||||
// TODO: Remove this when the AMD crash is solved in vblank_thread
|
||||
NV2ADevice::UpdateHostDisplay(d);
|
||||
}
|
||||
|
||||
DEVICE_READ32(PVIDEO)
|
||||
{
|
||||
DEVICE_READ32_SWITCH() {
|
||||
|
||||
case NV_PVIDEO_INTR:
|
||||
result = d->pvideo.pending_interrupts;
|
||||
break;
|
||||
case NV_PVIDEO_INTR_EN:
|
||||
result = d->pvideo.enabled_interrupts;
|
||||
break;
|
||||
case NV_PVIDEO_STOP:
|
||||
result = 0;
|
||||
break;
|
||||
|
@ -26,9 +35,18 @@ DEVICE_READ32(PVIDEO)
|
|||
DEVICE_WRITE32(PVIDEO)
|
||||
{
|
||||
switch (addr) {
|
||||
case NV_PVIDEO_INTR:
|
||||
d->pvideo.pending_interrupts &= ~value;
|
||||
update_irq(d);
|
||||
// qemu_cond_broadcast(&d->pvideo.interrupt_cond);
|
||||
break;
|
||||
case NV_PVIDEO_INTR_EN:
|
||||
d->pvideo.enabled_interrupts = value;
|
||||
update_irq(d);
|
||||
break;
|
||||
case NV_PVIDEO_BUFFER:
|
||||
d->pvideo.regs[addr] = value;
|
||||
d->enable_overlay = true;
|
||||
d->pvideo.regs[NV_PVIDEO_BUFFER] = value;
|
||||
d->enable_overlay = (value != 0);
|
||||
pvideo_vga_invalidate(d);
|
||||
break;
|
||||
case NV_PVIDEO_STOP:
|
||||
|
|
|
@ -123,6 +123,14 @@ static void update_irq(NV2AState *d)
|
|||
d->pmc.pending_interrupts &= ~NV_PMC_INTR_0_PGRAPH;
|
||||
}
|
||||
|
||||
/* PVIDEO */
|
||||
if (d->pvideo.pending_interrupts & d->pvideo.enabled_interrupts) {
|
||||
d->pmc.pending_interrupts |= NV_PMC_INTR_0_PVIDEO;
|
||||
}
|
||||
else {
|
||||
d->pmc.pending_interrupts &= ~NV_PMC_INTR_0_PVIDEO;
|
||||
}
|
||||
|
||||
/* TODO : PBUS * /
|
||||
if (d->pbus.pending_interrupts & d->pbus.enabled_interrupts) {
|
||||
d->pmc.pending_interrupts |= NV_PMC_INTR_0_PBUS;
|
||||
|
@ -377,7 +385,7 @@ void AvGetFormatSize(ULONG mode, int* width, int* height)
|
|||
}
|
||||
|
||||
extern void UpdateFPSCounter();
|
||||
void NV2ADevice::SwapBuffers(NV2AState *d)
|
||||
void NV2ADevice::UpdateHostDisplay(NV2AState *d)
|
||||
{
|
||||
if (!d->pgraph.opengl_enabled) {
|
||||
return;
|
||||
|
@ -388,7 +396,7 @@ void NV2ADevice::SwapBuffers(NV2AState *d)
|
|||
NV2A_GL_DGROUP_BEGIN("VGA Frame");
|
||||
|
||||
static ULONG PreviousAvDisplayModeFormat = 0;
|
||||
static GLenum internalFormat = GL_RGBA;
|
||||
static GLenum frame_internal_format = GL_RGBA;
|
||||
static GLenum frame_format = GL_RGBA;
|
||||
static GLenum frame_type = GL_UNSIGNED_INT_8_8_8_8;
|
||||
static int frame_width = 640;
|
||||
|
@ -398,7 +406,7 @@ void NV2ADevice::SwapBuffers(NV2AState *d)
|
|||
// Convert AV Format to OpenGl format details & destroy the texture if format changed..
|
||||
// This is required for titles that use a non ARGB framebuffer, such was Beats of Rage
|
||||
if (PreviousAvDisplayModeFormat != g_AvDisplayModeFormat) {
|
||||
AvDisplayModeFormatToGL(g_AvDisplayModeFormat, &internalFormat, &frame_format, &frame_type);
|
||||
AvDisplayModeFormatToGL(g_AvDisplayModeFormat, &frame_internal_format, &frame_format, &frame_type);
|
||||
AvGetFormatSize(AvpCurrentMode, &frame_width, &frame_height);
|
||||
if (frame_texture != -1) {
|
||||
glDeleteTextures(1, &frame_texture);
|
||||
|
@ -413,7 +421,7 @@ void NV2ADevice::SwapBuffers(NV2AState *d)
|
|||
if (frame_texture == -1) {
|
||||
glGenTextures(1, &frame_texture);
|
||||
glBindTexture(GL_TEXTURE_2D, frame_texture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, frame_width, frame_height, 0, frame_format, frame_type, (void*)frame_buffer);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, frame_internal_format, frame_width, frame_height, 0, frame_format, frame_type, (void*)frame_buffer);
|
||||
} else {
|
||||
glBindTexture(GL_TEXTURE_2D, frame_texture);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, frame_width, frame_height, frame_format, frame_type, (void*)frame_buffer);
|
||||
|
@ -449,17 +457,18 @@ void NV2ADevice::SwapBuffers(NV2AState *d)
|
|||
hwaddr overlay_limit = d->pvideo.regs[NV_PVIDEO_LIMIT(v)];
|
||||
hwaddr overlay_offset = d->pvideo.regs[NV_PVIDEO_OFFSET(v)];
|
||||
|
||||
int overlay_in_width = GET_MASK(d->pvideo.regs[NV_PVIDEO_SIZE_IN(v)], NV_PVIDEO_SIZE_IN_WIDTH);
|
||||
int overlay_in_height = GET_MASK(d->pvideo.regs[NV_PVIDEO_SIZE_IN(0)], NV_PVIDEO_SIZE_IN_HEIGHT);
|
||||
int overlay_in_s = GET_MASK(d->pvideo.regs[NV_PVIDEO_POINT_IN(v)], NV_PVIDEO_POINT_IN_S);
|
||||
int overlay_in_t = GET_MASK(d->pvideo.regs[NV_PVIDEO_POINT_IN(v)], NV_PVIDEO_POINT_IN_T);
|
||||
int overlay_format_pitch = GET_MASK(d->pvideo.regs[NV_PVIDEO_FORMAT(v)], NV_PVIDEO_FORMAT_PITCH);
|
||||
int overlay_format_color = GET_MASK(d->pvideo.regs[NV_PVIDEO_FORMAT(v)], NV_PVIDEO_FORMAT_COLOR);
|
||||
|
||||
int overlay_out_width = GET_MASK(d->pvideo.regs[NV_PVIDEO_SIZE_OUT(v)], NV_PVIDEO_SIZE_OUT_WIDTH);
|
||||
int overlay_out_height = GET_MASK(d->pvideo.regs[NV_PVIDEO_SIZE_OUT(v)], NV_PVIDEO_SIZE_OUT_HEIGHT);
|
||||
int overlay_in_s = GET_MASK(d->pvideo.regs[NV_PVIDEO_POINT_IN(v)], NV_PVIDEO_POINT_IN_S);
|
||||
int overlay_in_t = GET_MASK(d->pvideo.regs[NV_PVIDEO_POINT_IN(v)], NV_PVIDEO_POINT_IN_T);
|
||||
int overlay_in_width = GET_MASK(d->pvideo.regs[NV_PVIDEO_SIZE_IN(v)], NV_PVIDEO_SIZE_IN_WIDTH);
|
||||
int overlay_in_height = GET_MASK(d->pvideo.regs[NV_PVIDEO_SIZE_IN(0)], NV_PVIDEO_SIZE_IN_HEIGHT);
|
||||
|
||||
int overlay_out_x = GET_MASK(d->pvideo.regs[NV_PVIDEO_POINT_OUT(v)], NV_PVIDEO_POINT_OUT_X);
|
||||
int overlay_out_y = GET_MASK(d->pvideo.regs[NV_PVIDEO_POINT_OUT(v)], NV_PVIDEO_POINT_OUT_Y);
|
||||
int overlay_out_width = GET_MASK(d->pvideo.regs[NV_PVIDEO_SIZE_OUT(v)], NV_PVIDEO_SIZE_OUT_WIDTH);
|
||||
int overlay_out_height = GET_MASK(d->pvideo.regs[NV_PVIDEO_SIZE_OUT(v)], NV_PVIDEO_SIZE_OUT_HEIGHT);
|
||||
|
||||
// Use a shader to convert YUV to RGB :
|
||||
// From https://stackoverflow.com/questions/44291939/portable-yuv-drawing-context
|
||||
|
@ -522,16 +531,20 @@ void NV2ADevice::SwapBuffers(NV2AState *d)
|
|||
|
||||
GLuint vertex_shader = create_gl_shader(GL_VERTEX_SHADER, OPENGL_SHADER_YUV[0], "YUV>RGB Vertex shader");
|
||||
GLuint fragment_shader = create_gl_shader(GL_FRAGMENT_SHADER, OPENGL_SHADER_YUV[1], "YUV>RGB Fragment shader");
|
||||
// TODO : Verified upto here - get the rest working too...
|
||||
glAttachShader(shader_program_yuv_to_rgb, vertex_shader); // glAttachObjectARB
|
||||
glAttachShader(shader_program_yuv_to_rgb, fragment_shader); // glAttachObjectARB
|
||||
|
||||
glLinkProgram(shader_program_yuv_to_rgb);
|
||||
#if 0
|
||||
|
||||
/* Check it linked */
|
||||
GLint linked = 0;
|
||||
glGetProgramiv(shader_program_yuv_to_rgb, GL_LINK_STATUS, &linked);
|
||||
#endif
|
||||
if (!linked) {
|
||||
GLchar log[2048];
|
||||
glGetProgramInfoLog(shader_program_yuv_to_rgb, 2048, NULL, log);
|
||||
fprintf(stderr, "nv2a: shader linking failed: %s\n", log);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
glUseProgram(shader_program_yuv_to_rgb);
|
||||
|
@ -540,14 +553,17 @@ void NV2ADevice::SwapBuffers(NV2AState *d)
|
|||
static GLuint overlay_texture = -1;
|
||||
|
||||
hwaddr overlay_buffer = /*CONTIGUOUS_MEMORY_BASE=*/0x80000000 | overlay_base + overlay_offset;
|
||||
GLenum overlay_internal_format = frame_internal_format; // TODO
|
||||
GLenum overlay_format = frame_format; // TODO
|
||||
GLenum overlay_type = frame_type; // TODO
|
||||
if (overlay_texture == -1) {
|
||||
glGenTextures(1, &overlay_texture);
|
||||
glBindTexture(GL_TEXTURE_2D, overlay_texture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, overlay_in_width, overlay_in_height, 0, frame_format, frame_type, (void*)overlay_buffer);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, overlay_internal_format, overlay_in_width, overlay_in_height, 0, overlay_format, overlay_type, (void*)overlay_buffer);
|
||||
}
|
||||
else {
|
||||
glBindTexture(GL_TEXTURE_2D, overlay_texture);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, overlay_in_width, overlay_in_height, frame_format, frame_type, (void*)overlay_buffer);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, overlay_in_width, overlay_in_height, overlay_format, overlay_type, (void*)overlay_buffer);
|
||||
}
|
||||
|
||||
// Bind overlay texture
|
||||
|
@ -581,7 +597,7 @@ void NV2ADevice::SwapBuffers(NV2AState *d)
|
|||
UpdateFPSCounter();
|
||||
}
|
||||
|
||||
// TODO: Fix this properl
|
||||
// TODO: Fix this properly
|
||||
static void nv2a_vblank_thread(NV2AState *d)
|
||||
{
|
||||
CxbxSetThreadName("Cxbx NV2A VBLANK");
|
||||
|
@ -596,7 +612,7 @@ static void nv2a_vblank_thread(NV2AState *d)
|
|||
|
||||
// TODO: We should swap here for the purposes of supporting overlays + direct framebuffer access
|
||||
// But it causes crashes on AMD hardware for reasons currently unknown...
|
||||
//NV2ADevice::SwapBuffers(d);
|
||||
//NV2ADevice::UpdateHostDisplay(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -674,6 +690,7 @@ void NV2ADevice::Init()
|
|||
|
||||
CxbxReserveNV2AMemory(d);
|
||||
|
||||
|
||||
d->pcrtc.start = 0;
|
||||
|
||||
d->vram_ptr = (uint8_t*)PHYSICAL_MAP_BASE;
|
||||
|
@ -687,6 +704,7 @@ void NV2ADevice::Init()
|
|||
// Setup the conditions/mutexes
|
||||
qemu_mutex_init(&d->pfifo.cache1.cache_lock);
|
||||
qemu_cond_init(&d->pfifo.cache1.cache_cond);
|
||||
qemu_cond_init(&d->pvideo.interrupt_cond);
|
||||
|
||||
pgraph_init(m_nv2a_state);
|
||||
|
||||
|
|
|
@ -507,6 +507,9 @@ typedef struct NV2AState {
|
|||
} pfifo;
|
||||
|
||||
struct {
|
||||
uint32_t pending_interrupts;
|
||||
uint32_t enabled_interrupts;
|
||||
QemuCond interrupt_cond;
|
||||
uint32_t regs[NV_PVIDEO_SIZE]; // TODO : union
|
||||
} pvideo;
|
||||
|
||||
|
@ -645,7 +648,7 @@ public:
|
|||
uint32_t MMIORead(int barIndex, uint32_t addr, unsigned size);
|
||||
void MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size);
|
||||
|
||||
static void SwapBuffers(NV2AState *d);
|
||||
static void UpdateHostDisplay(NV2AState *d);
|
||||
private:
|
||||
NV2AState *m_nv2a_state;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue