static int thread_rendering;
static BOOL hold_cmds;
static BOOL needs_display;
+static BOOL flushed;
extern const unsigned char cmd_lengths[];
#endif /* _3DS */
while(1) {
- int result, last_cmd, start, end;
+ int result, cpu_cycles = 0, last_cmd, start, end;
video_thread_queue *queue;
pthread_mutex_lock(&thread->queue_lock);
for (i = start; i < end; i++) {
cmd = &queue->queue[i];
- result = real_do_cmd_list(cmd->cmd_list, cmd->count, &last_cmd);
-
+ result = real_do_cmd_list(cmd->cmd_list, cmd->count,
+ &cpu_cycles, &last_cmd);
if (result != cmd->count) {
fprintf(stderr, "Processed wrong cmd count: expected %d, got %d\n", cmd->count, result);
}
tmp = thread.queue;
thread.queue = thread.bg_queue;
thread.bg_queue = tmp;
- needs_display = TRUE;
pthread_cond_signal(&thread.cond_msg_avail);
}
pthread_mutex_unlock(&thread.queue_lock);
return;
}
+ if (thread.bg_queue->used) {
+ /* When we flush the background queue, the vblank handler can't
+ * know that we had a frame pending, and we delay rendering too
+ * long. Force it. */
+ flushed = TRUE;
+ }
+
/* Flush both queues. This is necessary because gpulib could be
* trying to process a DMA write that a command in the queue should
* run beforehand. For example, Xenogears sprites write a black
return pos;
}
-int do_cmd_list(uint32_t *list, int count, int *last_cmd) {
+int do_cmd_list(uint32_t *list, int count, int *cycles, int *last_cmd) {
int pos = 0;
if (thread.running) {
pos = scan_cmd_list(list, count, last_cmd);
video_thread_queue_cmd(list, pos, *last_cmd);
} else {
- pos = real_do_cmd_list(list, count, last_cmd);
+ pos = real_do_cmd_list(list, count, cycles, last_cmd);
memcpy(gpu.ex_regs, gpu.scratch_ex_regs, sizeof(gpu.ex_regs));
}
return pos;
void renderer_sync_ecmds(uint32_t * ecmds) {
if (thread.running) {
- int dummy;
- do_cmd_list(&ecmds[1], 6, &dummy);
+ int dummy = 0;
+ do_cmd_list(&ecmds[1], 6, &dummy, &dummy);
} else {
real_renderer_sync_ecmds(ecmds);
}
}
-void renderer_update_caches(int x, int y, int w, int h) {
+void renderer_update_caches(int x, int y, int w, int h, int state_changed) {
renderer_sync();
- real_renderer_update_caches(x, y, w, h);
+ real_renderer_update_caches(x, y, w, h, state_changed);
}
void renderer_flush_queues(void) {
}
pthread_mutex_lock(&thread.queue_lock);
- if (thread.bg_queue->used) {
+ if (thread.bg_queue->used || flushed) {
/* We have commands for a future frame to run. Force a wait until
* the current frame is finished, and start processing the next
* frame after it's drawn (see the `updated` clause above). */
/* We are no longer holding commands back, so the next frame may
* get mixed into the following frame. This is usually fine, but can
* result in frameskip-like effects for 60fps games. */
+ flushed = FALSE;
hold_cmds = FALSE;
needs_display = TRUE;
gpu.state.fb_dirty = TRUE;