diff --git a/src/devices/video/EmuNV2A.cpp b/src/devices/video/EmuNV2A.cpp index 512cf8788..5249a10e6 100644 --- a/src/devices/video/EmuNV2A.cpp +++ b/src/devices/video/EmuNV2A.cpp @@ -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; diff --git a/src/devices/video/EmuNV2A_PGRAPH.cpp b/src/devices/video/EmuNV2A_PGRAPH.cpp index a0642553b..f0b993352 100644 --- a/src/devices/video/EmuNV2A_PGRAPH.cpp +++ b/src/devices/video/EmuNV2A_PGRAPH.cpp @@ -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 */ diff --git a/src/devices/video/EmuNV2A_PVIDEO.cpp b/src/devices/video/EmuNV2A_PVIDEO.cpp index dfe9f4938..74fa53ca7 100644 --- a/src/devices/video/EmuNV2A_PVIDEO.cpp +++ b/src/devices/video/EmuNV2A_PVIDEO.cpp @@ -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: diff --git a/src/devices/video/nv2a.cpp b/src/devices/video/nv2a.cpp index 892ae5162..8b46d7b6d 100644 --- a/src/devices/video/nv2a.cpp +++ b/src/devices/video/nv2a.cpp @@ -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); diff --git a/src/devices/video/nv2a.h b/src/devices/video/nv2a.h index c0ed4650b..52c3009c5 100644 --- a/src/devices/video/nv2a.h +++ b/src/devices/video/nv2a.h @@ -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; };