From 69ed32c4428f16e691f2155294fc97da3599be39 Mon Sep 17 00:00:00 2001 From: Anthony Pesch Date: Wed, 24 May 2017 16:59:49 -0400 Subject: [PATCH] added comments explaining the purpose of emulator.c --- src/emulator.c | 100 +++++++++++++++++++++++++++++------------------- src/hw/pvr/tr.c | 33 ++++++++-------- src/hw/pvr/tr.h | 21 +++++----- 3 files changed, 87 insertions(+), 67 deletions(-) diff --git a/src/emulator.c b/src/emulator.c index 363b5ee8..53e7fd99 100644 --- a/src/emulator.c +++ b/src/emulator.c @@ -1,3 +1,16 @@ +/* + * client code for the dreamcast machine + * + * acts as a middle man between the dreamcast guest and local host. the host + * interface provides callbacks for user input events, window resize events, + * etc. that need to be passed to the dreamcast, while the dreamcast interface + * provides callbacks that push frames of video and audio data to be presented + * on the host + * + * this code encapsulates the logic that would otherwise need to be duplicated + * for each of the multiple host implementations (sdl, libretro, etc.) + */ + #include "emulator.h" #include "core/option.h" #include "core/profiler.h" @@ -28,31 +41,36 @@ enum { }; struct emu { - int multi_threaded; struct host *host; struct dreamcast *dc; - volatile int running; int debug_menu; + volatile int running; + volatile int video_width; + volatile int video_height; + volatile int video_resized; struct render_backend *r, *r2; struct microprofile *mp; struct nuklear *nk; struct tr *tr; - /* video state */ + /* hosts which support creating multiple gl contexts will render video on + a second thread. the original hardware rendered asynchronously as well, + so many games use this time to perform additional cpu work. on many + games this upwards of doubles the performance */ + int multi_threaded; thread_t video_thread; + /* latest context from the dreamcast, ready to be converted and presented */ mutex_t pending_mutex; cond_t pending_cond; struct tile_context *pending_ctx; + /* latest context converted into render commands to be presented locally */ volatile int video_state; - volatile int video_width; - volatile int video_height; - struct tr_context video_rc; - int video_fb_width; - int video_fb_height; + + /* offscreen framebuffer the video output is rendered to */ framebuffer_handle_t video_fb; texture_handle_t video_tex; sync_handle_t video_sync; @@ -72,20 +90,18 @@ static void emu_render_frame(struct emu *emu) { emu->video_state = FRAME_RENDERING; /* resize the framebuffer at this time if the output size has changed */ - if (emu->video_fb_width != emu->video_width || - emu->video_fb_height != emu->video_height) { + if (emu->video_resized) { r_destroy_framebuffer(r2, emu->video_fb); - emu->video_fb_width = emu->video_width; - emu->video_fb_height = emu->video_height; - emu->video_fb = r_create_framebuffer(r2, emu->video_fb_width, - emu->video_fb_height, &emu->video_tex); + emu->video_fb = r_create_framebuffer(r2, emu->video_width, + emu->video_height, &emu->video_tex); + emu->video_resized = 0; } /* render the current render context to the video framebuffer */ framebuffer_handle_t original = r_get_framebuffer(r2); r_bind_framebuffer(r2, emu->video_fb); - r_viewport(emu->r, emu->video_fb_width, emu->video_fb_height); + r_viewport(emu->r, emu->video_width, emu->video_height); tr_render_context(emu->tr, &emu->video_rc); r_bind_framebuffer(r2, original); @@ -237,13 +253,16 @@ static void emu_paint(struct emu *emu) { nk_render(emu->nk); } -static void emu_poll_input(void *userdata) { +/* + * dreamcast guest interface + */ +static void emu_guest_poll_input(void *userdata) { struct emu *emu = userdata; input_poll(emu->host); } -static void emu_finish_render(void *userdata) { +static void emu_guest_finish_render(void *userdata) { struct emu *emu = userdata; if (emu->multi_threaded) { @@ -259,7 +278,7 @@ static void emu_finish_render(void *userdata) { } } -static void emu_start_render(void *userdata, struct tile_context *ctx) { +static void emu_guest_start_render(void *userdata, struct tile_context *ctx) { struct emu *emu = userdata; if (emu->video_state != FRAME_WAITING) { @@ -283,20 +302,24 @@ static void emu_start_render(void *userdata, struct tile_context *ctx) { } } -static void emu_push_audio(void *userdata, const int16_t *data, int frames) { +static void emu_guest_push_audio(void *userdata, const int16_t *data, + int frames) { struct emu *emu = userdata; audio_push(emu->host, data, frames); } -static void emu_input_mousemove(void *userdata, int port, int x, int y) { +/* + * local host interface + */ +static void emu_host_mousemove(void *userdata, int port, int x, int y) { struct emu *emu = userdata; mp_mousemove(emu->mp, x, y); nk_mousemove(emu->nk, x, y); } -static void emu_input_keydown(void *userdata, int port, enum keycode key, - int16_t value) { +static void emu_host_keydown(void *userdata, int port, enum keycode key, + int16_t value) { struct emu *emu = userdata; if (key == K_F1 && value > 0) { @@ -311,7 +334,7 @@ static void emu_input_keydown(void *userdata, int port, enum keycode key, } } -static void emu_video_context_destroyed(void *userdata) { +static void emu_host_context_destroyed(void *userdata) { struct emu *emu = userdata; struct tr_provider *provider = ta_texture_provider(emu->dc->ta); @@ -361,11 +384,11 @@ static void emu_video_context_destroyed(void *userdata) { r_destroy(emu->r); } -static void emu_video_context_reset(void *userdata) { +static void emu_host_context_reset(void *userdata) { struct emu *emu = userdata; struct tr_provider *provider = ta_texture_provider(emu->dc->ta); - emu_video_context_destroyed(userdata); + emu_host_context_destroyed(userdata); emu->running = 1; @@ -387,10 +410,8 @@ static void emu_video_context_reset(void *userdata) { emu->tr = tr_create(r2, provider); - emu->video_fb_width = emu->video_width; - emu->video_fb_height = emu->video_height; - emu->video_fb = r_create_framebuffer(r2, emu->video_fb_width, - emu->video_fb_height, &emu->video_tex); + emu->video_fb = r_create_framebuffer(r2, emu->video_width, emu->video_height, + &emu->video_tex); /* startup video thread */ if (emu->multi_threaded) { @@ -402,11 +423,12 @@ static void emu_video_context_reset(void *userdata) { r_make_current(emu->r); } -static void emu_video_resized(void *userdata) { +static void emu_host_resized(void *userdata) { struct emu *emu = userdata; emu->video_width = video_width(emu->host); emu->video_height = video_height(emu->host); + emu->video_resized = 1; } void emu_run_frame(struct emu *emu) { @@ -449,19 +471,19 @@ struct emu *emu_create(struct host *host) { /* setup host, bind event callbacks */ emu->host = host; emu->host->userdata = emu; - emu->host->video_resized = &emu_video_resized; - emu->host->video_context_reset = &emu_video_context_reset; - emu->host->video_context_destroyed = &emu_video_context_destroyed; - emu->host->input_keydown = &emu_input_keydown; - emu->host->input_mousemove = &emu_input_mousemove; + emu->host->video_resized = &emu_host_resized; + emu->host->video_context_reset = &emu_host_context_reset; + emu->host->video_context_destroyed = &emu_host_context_destroyed; + emu->host->input_keydown = &emu_host_keydown; + emu->host->input_mousemove = &emu_host_mousemove; /* create dreamcast, bind client callbacks */ emu->dc = dc_create(); emu->dc->userdata = emu; - emu->dc->push_audio = &emu_push_audio; - emu->dc->start_render = &emu_start_render; - emu->dc->finish_render = &emu_finish_render; - emu->dc->poll_input = &emu_poll_input; + emu->dc->push_audio = &emu_guest_push_audio; + emu->dc->start_render = &emu_guest_start_render; + emu->dc->finish_render = &emu_guest_finish_render; + emu->dc->poll_input = &emu_guest_poll_input; /* start up the video thread */ emu->multi_threaded = video_gl_supports_multiple_contexts(emu->host); diff --git a/src/hw/pvr/tr.c b/src/hw/pvr/tr.c index 0bb893cb..1a851481 100644 --- a/src/hw/pvr/tr.c +++ b/src/hw/pvr/tr.c @@ -18,10 +18,6 @@ struct tr { int vertex_type; float face_color[4]; float face_offset_color[4]; - - /* scratch buffers used when sorting surfaces */ - int merged[TA_MAX_SURFS]; - float minz[TA_MAX_SURFS]; }; static int compressed_mipmap_offsets[] = { @@ -119,10 +115,10 @@ static inline uint32_t float_to_rgba(float r, float g, float b, float a) { (float_to_u8(g) << 8) | float_to_u8(r); } -static texture_handle_t tr_demand_texture(struct tr *tr, - const struct tile_context *ctx, - union tsp tsp, union tcw tcw) { - PROF_ENTER("gpu", "tr_demand_texture"); +static texture_handle_t tr_convert_texture(struct tr *tr, + const struct tile_context *ctx, + union tsp tsp, union tcw tcw) { + PROF_ENTER("gpu", "tr_convert_texture"); /* allow headless tile renderer */ if (!tr->provider) { @@ -607,7 +603,7 @@ static void tr_parse_poly_param(struct tr *tr, const struct tile_context *ctx, if (param->type0.pcw.texture) { surf->texture = - tr_demand_texture(tr, ctx, param->type0.tsp, param->type0.tcw); + tr_convert_texture(tr, ctx, param->type0.tsp, param->type0.tcw); } else { surf->texture = 0; } @@ -801,15 +797,19 @@ static void tr_parse_vert_param(struct tr *tr, const struct tile_context *ctx, /* FIXME is this true for sprites which come through this path as well? */ } +/* scratch buffers used by surface merge sort */ +static int sort_tmp[TA_MAX_SURFS]; +static float sort_minz[TA_MAX_SURFS]; + static void tr_merge_surfs(struct tr *tr, int *low, int *mid, int *high) { int *i = low; int *j = mid + 1; - int *k = tr->merged; - int *end = tr->merged + array_size(tr->merged); + int *k = sort_tmp; + int *end = sort_tmp + array_size(sort_tmp); while (i <= mid && j <= high) { DCHECK_LT(k, end); - if (tr->minz[*i] <= tr->minz[*j]) { + if (sort_minz[*i] <= sort_minz[*j]) { *(k++) = *(i++); } else { *(k++) = *(j++); @@ -826,7 +826,7 @@ static void tr_merge_surfs(struct tr *tr, int *low, int *mid, int *high) { *(k++) = *(j++); } - memcpy(low, tr->merged, (k - tr->merged) * sizeof(tr->merged[0])); + memcpy(low, sort_tmp, (k - sort_tmp) * sizeof(sort_tmp[0])); } static void tr_sort_surfs(struct tr *tr, struct tr_list *list, int low, @@ -850,7 +850,7 @@ static void tr_sort_render_list(struct tr *tr, struct tr_context *rc, for (int i = 0; i < list->num_surfs; i++) { int idx = list->surfs[i]; struct ta_surface *surf = &rc->surfs[idx]; - float *minz = &tr->minz[idx]; + float *minz = &sort_minz[idx]; /* the surf coordinates have 1/w for z, so smaller values are further away from the camera */ @@ -955,7 +955,7 @@ void tr_render_context(struct tr *tr, const struct tr_context *rc) { } void tr_convert_context(struct tr *tr, const struct tile_context *ctx, - struct tr_context *rc) { + struct tr_context *rc) { PROF_ENTER("gpu", "tr_convert_context"); const uint8_t *data = ctx->params; @@ -987,9 +987,6 @@ void tr_convert_context(struct tr *tr, const struct tile_context *ctx, /* global params */ case TA_PARAM_POLY_OR_VOL: - tr_parse_poly_param(tr, ctx, rc, data); - break; - case TA_PARAM_SPRITE: tr_parse_poly_param(tr, ctx, rc, data); break; diff --git a/src/hw/pvr/tr.h b/src/hw/pvr/tr.h index ac9e340a..6f9b1fe9 100644 --- a/src/hw/pvr/tr.h +++ b/src/hw/pvr/tr.h @@ -9,9 +9,19 @@ #include "render/render_backend.h" struct tr; +struct tr_texture; typedef uint64_t tr_texture_key_t; +/* provides abstraction around providing texture data to the renderer. when + emulating the actual ta, textures will be provided from guest memory, but + when playing back traces the textures will come from the trace itself */ +struct tr_provider { + void *userdata; + void (*clear_textures)(void *); + struct tr_texture *(*find_texture)(void *, union tsp, union tcw); +}; + struct tr_texture { union tsp tsp; union tcw tcw; @@ -34,15 +44,6 @@ struct tr_texture { texture_handle_t handle; }; -/* provides abstraction around providing texture data to the renderer. when - emulating the actual ta, textures will be provided from guest memory, but - when playing back traces the textures will come from the trace itself */ -struct tr_provider { - void *userdata; - void (*clear_textures)(void *); - struct tr_texture *(*find_texture)(void *, union tsp, union tcw); -}; - struct tr_param { /* offset of parameter in tile_context param stream */ int offset; @@ -87,7 +88,7 @@ struct tr *tr_create(struct render_backend *rb, struct tr_provider *provider); void tr_destroy(struct tr *tr); void tr_convert_context(struct tr *tr, const struct tile_context *ctx, - struct tr_context *rc); + struct tr_context *rc); void tr_render_context(struct tr *tr, const struct tr_context *rc); #endif