X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=plugins%2Fgpulib%2Fgpulib_thread_if.c;h=d456f03c9cad7132ec6a49674ad60d1cc8fc9278;hb=ff3890db8ef473ee5eae6a7120ee39d761a86620;hp=f0f607d621cbfb12411b39eb839c04f7341ac99d;hpb=accedc82b01fe5834a805a9872405d51de1d5c06;p=pcsx_rearmed.git diff --git a/plugins/gpulib/gpulib_thread_if.c b/plugins/gpulib/gpulib_thread_if.c index f0f607d6..d456f03c 100644 --- a/plugins/gpulib/gpulib_thread_if.c +++ b/plugins/gpulib/gpulib_thread_if.c @@ -18,12 +18,17 @@ ***************************************************************************/ #include +#include #include #include #include "../gpulib/gpu.h" #include "../../frontend/plugin_lib.h" #include "gpulib_thread_if.h" +#define FALSE 0 +#define TRUE 1 +#define BOOL unsigned short + typedef struct { uint32_t *cmd_list; int count; @@ -47,14 +52,15 @@ typedef struct { pthread_cond_t cond_queue_empty; video_thread_queue *queue; video_thread_queue *bg_queue; - bool running; + BOOL running; } video_thread_state; static video_thread_state thread; static video_thread_queue queues[2]; static int thread_rendering; -static bool hold_cmds; -static bool needs_display; +static BOOL hold_cmds; +static BOOL needs_display; +static BOOL flushed; extern const unsigned char cmd_lengths[]; @@ -62,10 +68,13 @@ static void *video_thread_main(void *arg) { video_thread_state *thread = (video_thread_state *)arg; video_thread_cmd *cmd; int i; + +#ifdef _3DS static int processed = 0; +#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); @@ -86,8 +95,8 @@ static void *video_thread_main(void *arg) { 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); } @@ -99,7 +108,7 @@ static void *video_thread_main(void *arg) { svcSleepThread(1); processed %= 512; } -#endif +#endif /* _3DS */ } pthread_mutex_lock(&thread->queue_lock); @@ -124,7 +133,6 @@ static void cmd_queue_swap() { 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); @@ -160,6 +168,13 @@ void renderer_sync(void) { 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 @@ -169,7 +184,7 @@ void renderer_sync(void) { * drop a frame. */ renderer_wait(); cmd_queue_swap(); - hold_cmds = false; + hold_cmds = FALSE; renderer_wait(); } @@ -178,7 +193,7 @@ static void video_thread_stop() { renderer_sync(); if (thread.running) { - thread.running = false; + thread.running = FALSE; pthread_cond_signal(&thread.cond_msg_avail); pthread_join(thread.thread, NULL); } @@ -215,7 +230,7 @@ static void video_thread_start() { thread.queue = &queues[0]; thread.bg_queue = &queues[1]; - thread.running = true; + thread.running = TRUE; return; error: @@ -227,7 +242,7 @@ static void video_thread_queue_cmd(uint32_t *list, int count, int last_cmd) { video_thread_cmd *cmd; uint32_t *cmd_list; video_thread_queue *queue; - bool lock; + BOOL lock; cmd_list = (uint32_t *)calloc(count, sizeof(uint32_t)); @@ -248,10 +263,10 @@ static void video_thread_queue_cmd(uint32_t *list, int count, int last_cmd) { if (hold_cmds) { queue = thread.bg_queue; - lock = false; + lock = FALSE; } else { queue = thread.queue; - lock = true; + lock = TRUE; } if (lock) { @@ -333,14 +348,14 @@ static int scan_cmd_list(uint32_t *data, int count, int *last_cmd) 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; @@ -363,16 +378,16 @@ void renderer_finish(void) { 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) { @@ -425,7 +440,7 @@ void renderer_notify_update_lace(int updated) { } 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). */ @@ -436,23 +451,24 @@ void renderer_notify_update_lace(int updated) { /* 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. */ - hold_cmds = false; - needs_display = true; - gpu.state.fb_dirty = true; + flushed = FALSE; + hold_cmds = FALSE; + needs_display = TRUE; + gpu.state.fb_dirty = TRUE; } else if (thread.queue->used) { /* We are still drawing during a vblank. Cut off the current frame * by sending new commands to the background queue and skip * drawing our partly rendered frame to the display. */ - hold_cmds = true; - needs_display = true; - gpu.state.fb_dirty = false; + hold_cmds = TRUE; + needs_display = TRUE; + gpu.state.fb_dirty = FALSE; } else if (needs_display && !thread.queue->used) { /* We have processed all commands in the queue, render the * buffer. We know we have something to render, because - * needs_display is true. */ - hold_cmds = false; - needs_display = false; - gpu.state.fb_dirty = true; + * needs_display is TRUE. */ + hold_cmds = FALSE; + needs_display = FALSE; + gpu.state.fb_dirty = TRUE; } else { /* Everything went normally, so do the normal thing. */ }