From 60d3dc8ae1db197592b7aa7a2cf852313cdfcf45 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Wed, 17 Jun 2020 16:32:34 -0700 Subject: [PATCH] nv2a: Add VMStateDescription --- hw/xbox/nv2a/nv2a.c | 193 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 187 insertions(+), 6 deletions(-) diff --git a/hw/xbox/nv2a/nv2a.c b/hw/xbox/nv2a/nv2a.c index 2a7192ee02..785e9c2d04 100644 --- a/hw/xbox/nv2a/nv2a.c +++ b/hw/xbox/nv2a/nv2a.c @@ -26,6 +26,8 @@ #include "qemu/main-loop.h" #include "qapi/error.h" #include "qemu/error-report.h" +#include "migration/vmstate.h" +#include "sysemu/runstate.h" #include "hw/hw.h" #include "hw/display/vga.h" @@ -424,16 +426,26 @@ static void nv2a_init_memory(NV2AState *d, MemoryRegion *ram) pfifo_thread, d, QEMU_THREAD_JOINABLE); } -static void nv2a_reset(NV2AState *d) +static void nv2a_lock_fifo(NV2AState *d) { qemu_mutex_lock(&d->pfifo.lock); - - // Wait for pfifo to become idle qemu_cond_broadcast(&d->pfifo.fifo_cond); qemu_mutex_unlock_iothread(); qemu_cond_wait(&d->pfifo.fifo_idle_cond, &d->pfifo.lock); qemu_mutex_lock_iothread(); qemu_mutex_lock(&d->pgraph.lock); +} + +static void nv2a_unlock_fifo(NV2AState *d) +{ + pfifo_kick(d); + qemu_mutex_unlock(&d->pgraph.lock); + qemu_mutex_unlock(&d->pfifo.lock); +} + +static void nv2a_reset(NV2AState *d) +{ + nv2a_lock_fifo(d); memset(d->pfifo.regs, 0, sizeof(d->pfifo.regs)); memset(d->pgraph.regs, 0, sizeof(d->pgraph.regs)); @@ -452,11 +464,14 @@ static void nv2a_reset(NV2AState *d) d->pgraph.waiting_for_flip = false; d->pgraph.waiting_for_fifo_access = false; d->pgraph.waiting_for_context_switch = false; + d->pgraph.flush_pending = false; - pfifo_kick(d); + d->pmc.pending_interrupts = 0; + d->pfifo.pending_interrupts = 0; + d->ptimer.pending_interrupts = 0; + d->pcrtc.pending_interrupts = 0; - qemu_mutex_unlock(&d->pgraph.lock); - qemu_mutex_unlock(&d->pfifo.lock); + nv2a_unlock_fifo(d); } static void nv2a_realize(PCIDevice *dev, Error **errp) @@ -520,6 +535,170 @@ static void qdev_nv2a_reset(DeviceState *dev) nv2a_reset(d); } +// Note: This is handled as a VM state change and not as a `pre_save` callback +// because we want to halt the FIFO before any VM state is saved/restored to +// avoid corruption. +static void nv2a_vm_state_change(void *opaque, int running, RunState state) +{ + NV2AState *d = opaque; + if (state == RUN_STATE_SAVE_VM) { + nv2a_lock_fifo(d); + } else if (state == RUN_STATE_RESTORE_VM) { + nv2a_reset(d); // Early reset to avoid changing any state during load + } +} + +static int nv2a_post_save(void *opaque) +{ + NV2AState *d = opaque; + nv2a_unlock_fifo(d); + return 0; +} + +static int nv2a_pre_load(void *opaque) +{ + NV2AState *d = opaque; + nv2a_lock_fifo(d); + return 0; +} + +static int nv2a_post_load(void *opaque, int version_id) +{ + NV2AState *d = opaque; + d->pgraph.flush_pending = true; + nv2a_unlock_fifo(d); + return 0; +} + +const VMStateDescription vmstate_nv2a_pgraph_vertex_attributes = { + .name = "nv2a/pgraph/vertex-attr", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + // FIXME + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_nv2a = { + .name = "nv2a", + .version_id = 1, + .minimum_version_id = 1, + .post_save = nv2a_post_save, + .post_load = nv2a_post_load, + .pre_load = nv2a_pre_load, + .fields = (VMStateField[]) { + // FIXME: Split this up into subsections + VMSTATE_PCI_DEVICE(parent_obj, NV2AState), + VMSTATE_STRUCT(vga, NV2AState, 0, vmstate_vga_common, VGACommonState), + VMSTATE_UINT32(pgraph.pending_interrupts, NV2AState), + VMSTATE_UINT32(pgraph.enabled_interrupts, NV2AState), + VMSTATE_UINT64(pgraph.context_surfaces_2d.object_instance, NV2AState), + VMSTATE_UINT64(pgraph.context_surfaces_2d.dma_image_source, NV2AState), + VMSTATE_UINT64(pgraph.context_surfaces_2d.dma_image_dest, NV2AState), + VMSTATE_UINT32(pgraph.context_surfaces_2d.color_format, NV2AState), + VMSTATE_UINT32(pgraph.context_surfaces_2d.source_pitch, NV2AState), + VMSTATE_UINT32(pgraph.context_surfaces_2d.dest_pitch, NV2AState), + VMSTATE_UINT64(pgraph.context_surfaces_2d.source_offset, NV2AState), + VMSTATE_UINT64(pgraph.context_surfaces_2d.dest_offset, NV2AState), + VMSTATE_UINT64(pgraph.image_blit.object_instance, NV2AState), + VMSTATE_UINT64(pgraph.image_blit.context_surfaces, NV2AState), + VMSTATE_UINT32(pgraph.image_blit.operation, NV2AState), + VMSTATE_UINT32(pgraph.image_blit.in_x, NV2AState), + VMSTATE_UINT32(pgraph.image_blit.in_y, NV2AState), + VMSTATE_UINT32(pgraph.image_blit.out_x, NV2AState), + VMSTATE_UINT32(pgraph.image_blit.out_y, NV2AState), + VMSTATE_UINT32(pgraph.image_blit.width, NV2AState), + VMSTATE_UINT32(pgraph.image_blit.height, NV2AState), + VMSTATE_UINT64(pgraph.kelvin.object_instance, NV2AState), + VMSTATE_UINT64(pgraph.dma_color, NV2AState), + VMSTATE_UINT64(pgraph.dma_zeta, NV2AState), + VMSTATE_BOOL(pgraph.surface_color.draw_dirty, NV2AState), + VMSTATE_BOOL(pgraph.surface_zeta.draw_dirty, NV2AState), + VMSTATE_BOOL(pgraph.surface_color.buffer_dirty, NV2AState), + VMSTATE_BOOL(pgraph.surface_zeta.buffer_dirty, NV2AState), + VMSTATE_BOOL(pgraph.surface_color.write_enabled_cache, NV2AState), + VMSTATE_BOOL(pgraph.surface_zeta.write_enabled_cache, NV2AState), + VMSTATE_UINT32(pgraph.surface_color.pitch, NV2AState), + VMSTATE_UINT32(pgraph.surface_zeta.pitch, NV2AState), + VMSTATE_UINT64(pgraph.surface_color.offset, NV2AState), + VMSTATE_UINT64(pgraph.surface_zeta.offset, NV2AState), + VMSTATE_UINT32(pgraph.surface_type, NV2AState), + VMSTATE_UINT32(pgraph.surface_shape.z_format, NV2AState), + VMSTATE_UINT32(pgraph.surface_shape.color_format, NV2AState), + VMSTATE_UINT32(pgraph.surface_shape.zeta_format, NV2AState), + VMSTATE_UINT32(pgraph.surface_shape.log_width, NV2AState), + VMSTATE_UINT32(pgraph.surface_shape.log_height, NV2AState), + VMSTATE_UINT32(pgraph.surface_shape.clip_x, NV2AState), + VMSTATE_UINT32(pgraph.surface_shape.clip_width, NV2AState), + VMSTATE_UINT32(pgraph.surface_shape.clip_height, NV2AState), + VMSTATE_UINT32(pgraph.surface_shape.anti_aliasing, NV2AState), + VMSTATE_UINT32(pgraph.last_surface_shape.z_format, NV2AState), + VMSTATE_UINT32(pgraph.last_surface_shape.color_format, NV2AState), + VMSTATE_UINT32(pgraph.last_surface_shape.zeta_format, NV2AState), + VMSTATE_UINT32(pgraph.last_surface_shape.log_width, NV2AState), + VMSTATE_UINT32(pgraph.last_surface_shape.log_height, NV2AState), + VMSTATE_UINT32(pgraph.last_surface_shape.clip_x, NV2AState), + VMSTATE_UINT32(pgraph.last_surface_shape.clip_width, NV2AState), + VMSTATE_UINT32(pgraph.last_surface_shape.clip_height, NV2AState), + VMSTATE_UINT32(pgraph.last_surface_shape.anti_aliasing, NV2AState), + VMSTATE_UINT64(pgraph.dma_a, NV2AState), + VMSTATE_UINT64(pgraph.dma_b, NV2AState), + VMSTATE_UINT64(pgraph.dma_state, NV2AState), + VMSTATE_UINT64(pgraph.dma_notifies, NV2AState), + VMSTATE_UINT64(pgraph.dma_semaphore, NV2AState), + VMSTATE_UINT64(pgraph.dma_report, NV2AState), + VMSTATE_UINT64(pgraph.report_offset, NV2AState), + VMSTATE_UINT64(pgraph.dma_vertex_a, NV2AState), + VMSTATE_UINT64(pgraph.dma_vertex_b, NV2AState), + VMSTATE_UINT32_2DARRAY(pgraph.program_data, NV2AState, NV2A_MAX_TRANSFORM_PROGRAM_LENGTH, VSH_TOKEN_SIZE), + VMSTATE_UINT32_2DARRAY(pgraph.vsh_constants, NV2AState, NV2A_VERTEXSHADER_CONSTANTS, 4), + VMSTATE_BOOL_ARRAY(pgraph.vsh_constants_dirty, NV2AState, NV2A_VERTEXSHADER_CONSTANTS), + VMSTATE_UINT32_2DARRAY(pgraph.ltctxa, NV2AState, NV2A_LTCTXA_COUNT, 4), + VMSTATE_BOOL_ARRAY(pgraph.ltctxa_dirty, NV2AState, NV2A_LTCTXA_COUNT), + VMSTATE_UINT32_2DARRAY(pgraph.ltctxb, NV2AState, NV2A_LTCTXB_COUNT, 4), + VMSTATE_BOOL_ARRAY(pgraph.ltctxb_dirty, NV2AState, NV2A_LTCTXB_COUNT), + VMSTATE_UINT32_2DARRAY(pgraph.ltc1, NV2AState, NV2A_LTC1_COUNT, 4), + VMSTATE_BOOL_ARRAY(pgraph.ltc1_dirty, NV2AState, NV2A_LTC1_COUNT), + VMSTATE_STRUCT_ARRAY(pgraph.vertex_attributes, NV2AState, NV2A_VERTEXSHADER_ATTRIBUTES, 1, vmstate_nv2a_pgraph_vertex_attributes, VertexAttribute), + VMSTATE_UINT32(pgraph.inline_array_length, NV2AState), + VMSTATE_UINT32_ARRAY(pgraph.inline_array, NV2AState, NV2A_MAX_BATCH_LENGTH), + VMSTATE_UINT32(pgraph.inline_elements_length, NV2AState), // fixme + VMSTATE_UINT32_ARRAY(pgraph.inline_elements, NV2AState, NV2A_MAX_BATCH_LENGTH), + VMSTATE_UINT32(pgraph.inline_buffer_length, NV2AState), // fixme + VMSTATE_UINT32(pgraph.draw_arrays_length, NV2AState), // fixme + VMSTATE_UINT32(pgraph.draw_arrays_max_count, NV2AState), // fixme + // GLint gl_draw_arrays_start[1000]; // fixme + // GLsizei gl_draw_arrays_count[1000]; // fixme + VMSTATE_UINT32_ARRAY(pgraph.regs, NV2AState, 0x2000), + VMSTATE_UINT32(pmc.pending_interrupts, NV2AState), + VMSTATE_UINT32(pmc.enabled_interrupts, NV2AState), + VMSTATE_UINT32(pfifo.pending_interrupts, NV2AState), + VMSTATE_UINT32(pfifo.enabled_interrupts, NV2AState), + VMSTATE_UINT32_ARRAY(pfifo.regs, NV2AState, 0x2000), + VMSTATE_UINT32_ARRAY(pvideo.regs, NV2AState, 0x1000), + VMSTATE_UINT32(ptimer.pending_interrupts, NV2AState), + VMSTATE_UINT32(ptimer.enabled_interrupts, NV2AState), + VMSTATE_UINT32(ptimer.numerator, NV2AState), + VMSTATE_UINT32(ptimer.denominator, NV2AState), + VMSTATE_UINT32(ptimer.alarm_time, NV2AState), + VMSTATE_UINT32_ARRAY(pfb.regs, NV2AState, 0x1000), + VMSTATE_UINT32(pcrtc.pending_interrupts, NV2AState), + VMSTATE_UINT32(pcrtc.enabled_interrupts, NV2AState), + VMSTATE_UINT64(pcrtc.start, NV2AState), + VMSTATE_UINT32(pramdac.core_clock_coeff, NV2AState), + VMSTATE_UINT64(pramdac.core_clock_freq, NV2AState), + VMSTATE_UINT32(pramdac.memory_clock_coeff, NV2AState), + VMSTATE_UINT32(pramdac.video_clock_coeff, NV2AState), + VMSTATE_BOOL(pgraph.waiting_for_flip, NV2AState), + VMSTATE_BOOL(pgraph.waiting_for_nop, NV2AState), + VMSTATE_BOOL(pgraph.waiting_for_fifo_access, NV2AState), + VMSTATE_BOOL(pgraph.waiting_for_context_switch, NV2AState), + VMSTATE_END_OF_LIST() + }, +}; + static void nv2a_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -538,6 +717,7 @@ static void nv2a_class_init(ObjectClass *klass, void *data) k->exit = nv2a_exitfn; dc->desc = "GeForce NV2A Integrated Graphics"; + dc->vmsd = &vmstate_nv2a; dc->reset = qdev_nv2a_reset; } @@ -563,4 +743,5 @@ void nv2a_init(PCIBus *bus, int devfn, MemoryRegion *ram) PCIDevice *dev = pci_create_simple(bus, devfn, "nv2a"); NV2AState *d = NV2A_DEVICE(dev); nv2a_init_memory(d, ram); + qemu_add_vm_change_state_handler(nv2a_vm_state_change, d); }