NV2A : Updated locks

This commit is contained in:
PatrickvL 2018-02-01 18:14:22 +01:00
parent 11b0e080be
commit 0ac96332a7
3 changed files with 130 additions and 53 deletions

View File

@ -7,7 +7,8 @@ typedef struct RAMHTEntry {
} RAMHTEntry;
static void pfifo_run_pusher(NV2AState *d); // forward declaration
int pfifo_puller_thread(void *opaque);
int pfifo_puller_thread(NV2AState *d);
static uint32_t ramht_hash(NV2AState *d, uint32_t handle);
static RAMHTEntry ramht_lookup(NV2AState *d, uint32_t handle); // forward declaration
DEVICE_READ32(PFIFO)
@ -36,12 +37,11 @@ DEVICE_READ32(PFIFO)
SET_MASK(result, NV_PFIFO_CACHE1_PUSH1_MODE, d->pfifo.cache1.mode);
break;
case NV_PFIFO_CACHE1_STATUS: {
std::lock_guard<std::mutex> lk(d->pfifo.cache1.mutex);
d->pfifo.cache1.cache_lock.lock();
if (d->pfifo.cache1.cache.empty()) {
result |= NV_PFIFO_CACHE1_STATUS_LOW_MARK; /* low mark empty */
}
d->pfifo.cache1.cache_lock.unlock();
} break;
case NV_PFIFO_CACHE1_DMA_PUSH:
SET_MASK(result, NV_PFIFO_CACHE1_DMA_PUSH_ACCESS,
@ -77,15 +77,16 @@ DEVICE_READ32(PFIFO)
| d->pfifo.cache1.subroutine_active;
break;
case NV_PFIFO_CACHE1_PULL0: {
std::lock_guard<std::mutex> lk(d->pfifo.cache1.mutex);
d->pfifo.cache1.cache_lock.lock();
result = d->pfifo.cache1.pull_enabled;
d->pfifo.cache1.cache_lock.unlock();
} break;
case NV_PFIFO_CACHE1_ENGINE: {
std::lock_guard<std::mutex> lk(d->pfifo.cache1.mutex);
d->pfifo.cache1.cache_lock.lock();
for (int i = 0; i < NV2A_NUM_SUBCHANNELS; i++) {
result |= d->pfifo.cache1.bound_engines[i] << (i * 2);
}
d->pfifo.cache1.cache_lock.unlock();
} break;
case NV_PFIFO_CACHE1_DMA_DCOUNT:
result = d->pfifo.cache1.dcount;
@ -155,7 +156,7 @@ DEVICE_WRITE32(PFIFO)
d->pfifo.cache1.subroutine_active = (value & NV_PFIFO_CACHE1_DMA_SUBROUTINE_STATE);
break;
case NV_PFIFO_CACHE1_PULL0: {
std::lock_guard<std::mutex> lk(d->pfifo.cache1.mutex);
d->pfifo.cache1.cache_lock.lock();
if ((value & NV_PFIFO_CACHE1_PULL0_ACCESS)
&& !d->pfifo.cache1.pull_enabled) {
@ -167,14 +168,14 @@ DEVICE_WRITE32(PFIFO)
&& d->pfifo.cache1.pull_enabled) {
d->pfifo.cache1.pull_enabled = false;
}
d->pfifo.cache1.cache_lock.unlock();
} break;
case NV_PFIFO_CACHE1_ENGINE: {
std::lock_guard<std::mutex> lk(d->pfifo.cache1.mutex);
d->pfifo.cache1.cache_lock.lock();
for (int i = 0; i < NV2A_NUM_SUBCHANNELS; i++) {
d->pfifo.cache1.bound_engines[i] = (FIFOEngine)((value >> (i * 2)) & 3);
}
d->pfifo.cache1.cache_lock.unlock();
} break;
case NV_PFIFO_CACHE1_DMA_DCOUNT:
d->pfifo.cache1.dcount = (value & NV_PFIFO_CACHE1_DMA_DCOUNT_VALUE);
@ -251,10 +252,10 @@ static void pfifo_run_pusher(NV2AState *d) {
command->subchannel = state->subchannel;
command->nonincreasing = state->method_nonincreasing;
command->parameter = word;
std::lock_guard<std::mutex> lk(state->mutex);
state->cache_lock.lock();
state->cache.push(command);
state->cache_cond.notify_all();
state->cache_lock.unlock();
if (!state->method_nonincreasing) {
state->method += 4;
@ -338,29 +339,27 @@ static void pfifo_run_pusher(NV2AState *d) {
}
}
int pfifo_puller_thread(void *opaque)
int pfifo_puller_thread(NV2AState *d)
{
CxbxSetThreadName("Cxbx NV2A FIFO");
NV2AState *d = (NV2AState *)opaque;
Cache1State *state = &d->pfifo.cache1;
while (true) {
// Scope the lock so that it automatically unlocks at tne end of this block
{
std::unique_lock<std::mutex> lk(state->mutex);
while (state->cache.empty() || !state->pull_enabled) {
state->cache_cond.wait(lk);
}
// Copy cache to working_cache
while (!state->cache.empty()) {
state->working_cache.push(state->cache.front());
state->cache.pop();
}
state->cache_lock.lock();
while (state->cache.empty() || !state->pull_enabled) {
state->cache_cond.wait(state->cache_lock);
}
// Copy cache to working_cache
while (!state->cache.empty()) {
state->working_cache.push(state->cache.front());
state->cache.pop();
}
state->cache_lock.unlock();
d->pgraph.lock.lock();
while (!state->working_cache.empty()) {
CacheEntry* command = state->working_cache.front();
state->working_cache.pop();
@ -385,9 +384,10 @@ int pfifo_puller_thread(void *opaque)
}
/* the engine is bound to the subchannel */
std::lock_guard<std::mutex> lk(state->mutex);
state->cache_lock.lock();
state->bound_engines[command->subchannel] = entry.engine;
state->last_engine = entry.engine;
state->cache_lock.unlock();
} else if (command->method >= 0x100) {
/* method passed to engine */
@ -427,6 +427,9 @@ int pfifo_puller_thread(void *opaque)
}
}
d->pgraph.lock.unlock();
return 0;
}

View File

@ -1,3 +1,8 @@
// TODO : Replace these functions by something equivalent
#define qemu_mutex_lock_iothread()
#define qemu_mutex_unlock_iothread()
#define NV2A_DPRINTF printf
static const GLenum pgraph_texture_min_filter_map[] = {
0,
GL_NEAREST,
@ -176,7 +181,7 @@ static void pgraph_method_log(unsigned int subchannel, unsigned int graphics_cla
DEVICE_READ32(PGRAPH)
{
std::lock_guard<std::mutex> lk(d->pgraph.mutex);
d->pgraph.lock.lock();
DEVICE_READ32_SWITCH() {
case NV_PGRAPH_INTR:
@ -215,6 +220,8 @@ DEVICE_READ32(PGRAPH)
DEVICE_READ32_REG(pgraph); // Was : DEBUG_READ32_UNHANDLED(PGRAPH);
}
d->pgraph.lock.unlock();
DEVICE_READ32_END(PGRAPH);
}
@ -227,7 +234,7 @@ static void pgraph_set_context_user(NV2AState *d, uint32_t value)
DEVICE_WRITE32(PGRAPH)
{
std::lock_guard<std::mutex> lk(d->pgraph.mutex);
d->pgraph.lock.lock();
switch (addr) {
case NV_PGRAPH_INTR:
@ -289,13 +296,13 @@ DEVICE_WRITE32(PGRAPH)
break;
}
d->pgraph.lock.unlock();
DEVICE_WRITE32_END(PGRAPH);
}
static void pgraph_method(NV2AState *d, unsigned int subchannel, unsigned int method, uint32_t parameter)
{
std::lock_guard<std::mutex> lk(d->pgraph.mutex);
// int i;
GraphicsSubchannel *subchannel_data;
GraphicsObject *object;
@ -317,9 +324,9 @@ static void pgraph_method(NV2AState *d, unsigned int subchannel, unsigned int me
if (method == NV_SET_OBJECT) {
subchannel_data->object_instance = parameter;
//qemu_mutex_lock_iothread();
qemu_mutex_lock_iothread();
load_graphics_object(d, parameter, object);
//qemu_mutex_unlock_iothread();
qemu_mutex_unlock_iothread();
return;
}
@ -440,6 +447,73 @@ static void pgraph_method(NV2AState *d, unsigned int subchannel, unsigned int me
case NV_KELVIN_PRIMITIVE: {
switch (method) {
case NV097_NO_OPERATION:
/* The bios uses nop as a software method call -
* it seems to expect a notify interrupt if the parameter isn't 0.
* According to a nouveau guy it should still be a nop regardless
* of the parameter. It's possible a debug register enables this,
* but nothing obvious sticks out. Weird.
*/
if (parameter != 0) {
assert(!(pg->pending_interrupts & NV_PGRAPH_INTR_ERROR));
pg->trapped_channel_id = pg->channel_id;
pg->trapped_subchannel = subchannel;
pg->trapped_method = method;
pg->trapped_data[0] = parameter;
pg->notify_source = NV_PGRAPH_NSOURCE_NOTIFICATION; /* TODO: check this */
pg->pending_interrupts |= NV_PGRAPH_INTR_ERROR;
pg->lock.unlock();
qemu_mutex_lock_iothread();
update_irq(d);
pg->lock.lock();
qemu_mutex_unlock_iothread();
while (pg->pending_interrupts & NV_PGRAPH_INTR_ERROR) {
d->pgraph.interrupt_cond.wait(pg->lock);
}
}
break;
case NV097_WAIT_FOR_IDLE:
pgraph_update_surface(d, false, true, true);
break;
case NV097_SET_FLIP_READ:
SET_MASK(pg->regs[NV_PGRAPH_SURFACE], NV_PGRAPH_SURFACE_READ_3D,
parameter);
break;
case NV097_SET_FLIP_WRITE:
SET_MASK(pg->regs[NV_PGRAPH_SURFACE], NV_PGRAPH_SURFACE_WRITE_3D,
parameter);
break;
case NV097_SET_FLIP_MODULO:
SET_MASK(pg->regs[NV_PGRAPH_SURFACE], NV_PGRAPH_SURFACE_MODULO_3D,
parameter);
break;
case NV097_FLIP_INCREMENT_WRITE: {
NV2A_DPRINTF("flip increment write %d -> ",
GET_MASK(pg->regs[NV_PGRAPH_SURFACE],
NV_PGRAPH_SURFACE_WRITE_3D));
SET_MASK(pg->regs[NV_PGRAPH_SURFACE],
NV_PGRAPH_SURFACE_WRITE_3D,
(GET_MASK(pg->regs[NV_PGRAPH_SURFACE],
NV_PGRAPH_SURFACE_WRITE_3D)+1)
% GET_MASK(pg->regs[NV_PGRAPH_SURFACE],
NV_PGRAPH_SURFACE_MODULO_3D) );
NV2A_DPRINTF("%d\n",
GET_MASK(pg->regs[NV_PGRAPH_SURFACE],
NV_PGRAPH_SURFACE_WRITE_3D));
// if (glFrameTerminatorGREMEDY) {
// glFrameTerminatorGREMEDY();
// }
break;
}
case NV097_SET_CONTEXT_DMA_NOTIFIES:
kelvin->dma_notifies = parameter;
break;
@ -968,7 +1042,7 @@ static void pgraph_method(NV2AState *d, unsigned int subchannel, unsigned int me
pgraph_update_surface(d, false, true, true);
//qemu_mutex_unlock(&d->pg->lock);
//qemu_mutex_lock_iothread();
qemu_mutex_lock_iothread();
xbaddr semaphore_dma_len;
uint8_t *semaphore_data = (uint8_t*)nv_dma_map(d, kelvin->dma_semaphore,
@ -979,7 +1053,7 @@ static void pgraph_method(NV2AState *d, unsigned int subchannel, unsigned int me
stl_le_p((uint32_t*)semaphore_data, parameter);
//qemu_mutex_lock(&d->pg->lock);
//qemu_mutex_unlock_iothread();
qemu_mutex_unlock_iothread();
break;
}
@ -1131,43 +1205,42 @@ static void pgraph_method(NV2AState *d, unsigned int subchannel, unsigned int me
EmuWarning("EmuNV2A: Unknown Graphics Class/Method 0x%08X/0x%08X\n", object->graphics_class, method);
break;
}
}
static void pgraph_context_switch(NV2AState *d, unsigned int channel_id)
{
bool valid = false;
// Scope the lock so that it gets unlocked at end of this block
{
std::lock_guard<std::mutex> lk(d->pgraph.mutex);
d->pgraph.lock.lock(); // TODO : This isn't in xqemu / OpenXbox?
valid = d->pgraph.channel_valid && d->pgraph.channel_id == channel_id;
if (!valid) {
d->pgraph.trapped_channel_id = channel_id;
}
valid = d->pgraph.channel_valid && d->pgraph.channel_id == channel_id;
if (!valid) {
d->pgraph.trapped_channel_id = channel_id;
}
d->pgraph.lock.unlock(); // TODO : This isn't in xqemu / OpenXbox?
if (!valid) {
printf("puller needs to switch to ch %d\n", channel_id);
//qemu_mutex_lock_iothread();
d->pgraph.lock.unlock()
qemu_mutex_lock_iothread();
d->pgraph.pending_interrupts |= NV_PGRAPH_INTR_CONTEXT_SWITCH;
update_irq(d);
std::unique_lock<std::mutex> lk(d->pgraph.mutex);
//qemu_mutex_unlock_iothread();
d->pgraph.lock.lock();
qemu_mutex_unlock_iothread();
while (d->pgraph.pending_interrupts & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
d->pgraph.interrupt_cond.wait(lk);
d->pgraph.interrupt_cond.wait(d->pgraph.lock);
}
}
}
static void pgraph_wait_fifo_access(NV2AState *d) {
std::unique_lock<std::mutex> lk(d->pgraph.mutex);
while (!d->pgraph.fifo_access) {
d->pgraph.fifo_access_cond.wait(lk);
d->pgraph.fifo_access_cond.wait(d->pgraph.lock);
}
}

View File

@ -277,7 +277,7 @@ typedef struct GraphicsContext {
typedef struct PGRAPHState {
std::mutex mutex;
std::unique_lock<std::mutex> lock;
uint32_t pending_interrupts;
uint32_t enabled_interrupts;
@ -295,6 +295,7 @@ typedef struct PGRAPHState {
bool fifo_access;
std::condition_variable fifo_access_cond;
std::condition_variable flip_3d;
unsigned int channel_id;
@ -419,7 +420,7 @@ typedef struct Cache1State {
enum FIFOEngine last_engine;
/* The actual command queue */
std::mutex mutex;
std::unique_lock<std::mutex> cache_lock;
std::condition_variable cache_cond;
std::queue<CacheEntry*> cache;
std::queue<CacheEntry*> working_cache;