diff --git a/hw/xbox/nv2a/nv2a.h b/hw/xbox/nv2a/nv2a.h index a5c4468deb..2a9b7312d4 100644 --- a/hw/xbox/nv2a/nv2a.h +++ b/hw/xbox/nv2a/nv2a.h @@ -24,6 +24,7 @@ void nv2a_init(PCIBus *bus, int devfn, MemoryRegion *ram); void nv2a_context_init(void); int nv2a_get_framebuffer_surface(void); +void nv2a_release_framebuffer_surface(void); void nv2a_set_surface_scale_factor(unsigned int scale); unsigned int nv2a_get_surface_scale_factor(void); const uint8_t *nv2a_get_dac_palette(void); diff --git a/hw/xbox/nv2a/pgraph/gl/surface.c b/hw/xbox/nv2a/pgraph/gl/surface.c index c0aa4a4f26..802a3febc0 100644 --- a/hw/xbox/nv2a/pgraph/gl/surface.c +++ b/hw/xbox/nv2a/pgraph/gl/surface.c @@ -39,8 +39,6 @@ void pgraph_gl_set_surface_scale_factor(NV2AState *d, unsigned int scale) g_config.display.quality.surface_scale = scale < 1 ? 1 : scale; - qemu_mutex_unlock_iothread(); - qemu_mutex_lock(&d->pfifo.lock); qatomic_set(&d->pfifo.halt, true); qemu_mutex_unlock(&d->pfifo.lock); @@ -67,8 +65,6 @@ void pgraph_gl_set_surface_scale_factor(NV2AState *d, unsigned int scale) qatomic_set(&d->pfifo.halt, false); pfifo_kick(d); qemu_mutex_unlock(&d->pfifo.lock); - - qemu_mutex_lock_iothread(); } unsigned int pgraph_gl_get_surface_scale_factor(NV2AState *d) diff --git a/hw/xbox/nv2a/pgraph/pgraph.c b/hw/xbox/nv2a/pgraph/pgraph.c index 7ffc1ae5de..534daa3c0f 100644 --- a/hw/xbox/nv2a/pgraph/pgraph.c +++ b/hw/xbox/nv2a/pgraph/pgraph.c @@ -222,6 +222,7 @@ void pgraph_init(NV2AState *d) qemu_mutex_init(&pg->renderer_lock); qemu_event_init(&pg->sync_complete, false); qemu_event_init(&pg->flush_complete, false); + qemu_cond_init(&pg->framebuffer_released); pg->frame_time = 0; pg->draw_time = 0; @@ -352,26 +353,41 @@ void pgraph_destroy(PGRAPHState *pg) int nv2a_get_framebuffer_surface(void) { NV2AState *d = g_nv2a; + PGRAPHState *pg = &d->pgraph; int s = 0; - qemu_mutex_lock(&d->pgraph.renderer_lock); - if (d->pgraph.renderer->ops.get_framebuffer_surface) { - s = d->pgraph.renderer->ops.get_framebuffer_surface(d); + qemu_mutex_lock(&pg->renderer_lock); + assert(!pg->framebuffer_in_use); + pg->framebuffer_in_use = true; + if (pg->renderer->ops.get_framebuffer_surface) { + s = pg->renderer->ops.get_framebuffer_surface(d); } - qemu_mutex_unlock(&d->pgraph.renderer_lock); + qemu_mutex_unlock(&pg->renderer_lock); return s; } +void nv2a_release_framebuffer_surface(void) +{ + NV2AState *d = g_nv2a; + PGRAPHState *pg = &d->pgraph; + qemu_mutex_lock(&pg->renderer_lock); + pg->framebuffer_in_use = false; + qemu_cond_broadcast(&pg->framebuffer_released); + qemu_mutex_unlock(&pg->renderer_lock); +} + void nv2a_set_surface_scale_factor(unsigned int scale) { NV2AState *d = g_nv2a; + qemu_mutex_unlock_iothread(); qemu_mutex_lock(&d->pgraph.renderer_lock); if (d->pgraph.renderer->ops.set_surface_scale_factor) { d->pgraph.renderer->ops.set_surface_scale_factor(d, scale); } qemu_mutex_unlock(&d->pgraph.renderer_lock); + qemu_mutex_lock_iothread(); } unsigned int nv2a_get_surface_scale_factor(void) @@ -379,11 +395,13 @@ unsigned int nv2a_get_surface_scale_factor(void) NV2AState *d = g_nv2a; int s = 1; + qemu_mutex_unlock_iothread(); qemu_mutex_lock(&d->pgraph.renderer_lock); if (d->pgraph.renderer->ops.get_surface_scale_factor) { s = d->pgraph.renderer->ops.get_surface_scale_factor(d); } qemu_mutex_unlock(&d->pgraph.renderer_lock); + qemu_mutex_lock_iothread(); return s; } @@ -2958,6 +2976,9 @@ void pgraph_process_pending(NV2AState *d) qemu_mutex_unlock(&d->pfifo.lock); qemu_mutex_lock(&d->pgraph.lock); + while (pg->framebuffer_in_use) { + qemu_cond_wait(&d->pgraph.framebuffer_released, &d->pgraph.renderer_lock); + } if (pg->renderer->ops.finalize) { pg->renderer->ops.finalize(d); diff --git a/hw/xbox/nv2a/pgraph/pgraph.h b/hw/xbox/nv2a/pgraph/pgraph.h index bbff5f2c58..4ecc1c0d25 100644 --- a/hw/xbox/nv2a/pgraph/pgraph.h +++ b/hw/xbox/nv2a/pgraph/pgraph.h @@ -235,6 +235,9 @@ typedef struct PGRAPHState { bool sync_pending; QemuEvent sync_complete; + bool framebuffer_in_use; + QemuCond framebuffer_released; + unsigned int surface_scale_factor; uint8_t *scale_buf; diff --git a/hw/xbox/nv2a/pgraph/vk/surface.c b/hw/xbox/nv2a/pgraph/vk/surface.c index 43b0e743d7..a348de1e71 100644 --- a/hw/xbox/nv2a/pgraph/vk/surface.c +++ b/hw/xbox/nv2a/pgraph/vk/surface.c @@ -36,8 +36,6 @@ void pgraph_vk_set_surface_scale_factor(NV2AState *d, unsigned int scale) { g_config.display.quality.surface_scale = scale < 1 ? 1 : scale; - qemu_mutex_unlock_iothread(); - qemu_mutex_lock(&d->pfifo.lock); qatomic_set(&d->pfifo.halt, true); qemu_mutex_unlock(&d->pfifo.lock); @@ -65,8 +63,6 @@ void pgraph_vk_set_surface_scale_factor(NV2AState *d, unsigned int scale) qatomic_set(&d->pfifo.halt, false); pfifo_kick(d); qemu_mutex_unlock(&d->pfifo.lock); - - qemu_mutex_lock_iothread(); } unsigned int pgraph_vk_get_surface_scale_factor(NV2AState *d) diff --git a/ui/xemu.c b/ui/xemu.c index 0d01f22460..c8030fc8d0 100644 --- a/ui/xemu.c +++ b/ui/xemu.c @@ -1209,6 +1209,7 @@ void sdl2_gl_refresh(DisplayChangeListener *dcl) qemu_mutex_unlock_main_loop(); glFinish(); + nv2a_release_framebuffer_surface(); SDL_GL_SwapWindow(scon->real_window); /* VGA update (see note above) + vblank */