added comments explaining the purpose of emulator.c

This commit is contained in:
Anthony Pesch 2017-05-24 16:59:49 -04:00
parent a4704f4c50
commit 69ed32c442
3 changed files with 87 additions and 67 deletions

View File

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

View File

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

View File

@ -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