diff --git a/hw/xbox/nv2a/nv2a_int.h b/hw/xbox/nv2a/nv2a_int.h index ef00ad2846..bf7818197c 100644 --- a/hw/xbox/nv2a/nv2a_int.h +++ b/hw/xbox/nv2a/nv2a_int.h @@ -357,6 +357,7 @@ typedef struct PGRAPHState { bool waiting_for_context_switch; bool flush_pending; bool gl_sync_pending; + QemuEvent gl_sync_complete; } PGRAPHState; typedef struct NV2AState { diff --git a/hw/xbox/nv2a/pgraph.c b/hw/xbox/nv2a/pgraph.c index 44279f3e05..73f4afaf4a 100644 --- a/hw/xbox/nv2a/pgraph.c +++ b/hw/xbox/nv2a/pgraph.c @@ -2988,6 +2988,7 @@ void pgraph_init(NV2AState *d) pg->downloads_pending = false; qemu_mutex_init(&pg->lock); + qemu_event_init(&pg->gl_sync_complete, false); /* fire up opengl */ glo_set_current(g_nv2a_context_render); @@ -3866,21 +3867,21 @@ void pgraph_gl_sync(NV2AState *d) // Switch back to original context glo_set_current(g_nv2a_context_render); + + qemu_event_set(&d->pgraph.gl_sync_complete); } int nv2a_get_framebuffer_surface(void) { NV2AState *d = g_nv2a; PGRAPHState *pg = &d->pgraph; - GLuint buffer = 0; qemu_mutex_lock(&d->pfifo.lock); - - // Lookup surface in surface cache // FIXME: Possible race condition with pgraph, consider lock SurfaceBinding *surface = pgraph_surface_get(d, d->pcrtc.start); if (surface == NULL || !surface->color) { - goto done; + qemu_mutex_unlock(&d->pfifo.lock); + return 0; } assert(surface->color); @@ -3892,18 +3893,13 @@ int nv2a_get_framebuffer_surface(void) ); surface->frame_time = pg->frame_time; - pg->gl_sync_pending = true; - do { - d->pfifo.fifo_kick = true; - qemu_cond_broadcast(&d->pfifo.fifo_cond); - qemu_cond_wait(&d->pfifo.fifo_idle_cond, &d->pfifo.lock); - } while (pg->gl_sync_pending); - - buffer = pg->gl_display_buffer; - -done: + qemu_event_reset(&d->pgraph.gl_sync_complete); + atomic_set(&pg->gl_sync_pending, true); + pfifo_kick(d); qemu_mutex_unlock(&d->pfifo.lock); - return buffer; + qemu_event_wait(&d->pgraph.gl_sync_complete); + + return pg->gl_display_buffer; } static bool pgraph_check_surface_to_texture_compatibility(