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:
PatrickvL 2018-06-18 15:05:43 +02:00
parent 5a6a37f5fb
commit 2734bcf212
5 changed files with 140 additions and 87 deletions

View File

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

View File

@ -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 */

View File

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

View File

@ -123,20 +123,28 @@ static void update_irq(NV2AState *d)
d->pmc.pending_interrupts &= ~NV_PMC_INTR_0_PGRAPH;
}
/* TODO : PBUS * /
if (d->pbus.pending_interrupts & d->pbus.enabled_interrupts) {
d->pmc.pending_interrupts |= NV_PMC_INTR_0_PBUS;
/* 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_PBUS;
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;
}
else {
d->pmc.pending_interrupts &= ~NV_PMC_INTR_0_PBUS;
} */
/* TODO : SOFTWARE * /
if (d->user.pending_interrupts & d->.enabled_interrupts) {
d->pmc.pending_interrupts |= NV_PMC_INTR_0_SOFTWARE;
d->pmc.pending_interrupts |= NV_PMC_INTR_0_SOFTWARE;
}
else {
d->pmc.pending_interrupts &= ~NV_PMC_INTR_0_SOFTWARE;
d->pmc.pending_interrupts &= ~NV_PMC_INTR_0_SOFTWARE;
} */
if (d->pmc.pending_interrupts && d->pmc.enabled_interrupts) {
@ -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);

View File

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