nv2a: Add VMStateDescription

This commit is contained in:
Matt Borgerson 2020-06-17 16:32:34 -07:00 committed by mborgerson
parent c9cf9a9972
commit 60d3dc8ae1
1 changed files with 187 additions and 6 deletions

View File

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