added frame marker to tile_context / texture_entry

made tile params scroll into view when selecting params with the keyboard
fixed fullscreen ui elements not resizing when the window resized
This commit is contained in:
Anthony Pesch 2016-12-26 14:28:24 -08:00
parent adc8a82a5a
commit 92c6baf455
11 changed files with 485 additions and 481 deletions

View File

@ -82,16 +82,15 @@ static void emu_paint(void *data) {
/* render latest ta context */
struct render_context *render_ctx = &emu->render_ctx;
struct tile_ctx *pending_ctx = NULL;
int pending_frame = 0;
if (ta_lock_pending_context(emu->dc->ta, &pending_ctx, &pending_frame)) {
if (ta_lock_pending_context(emu->dc->ta, &pending_ctx)) {
render_ctx->surfs = emu->surfs;
render_ctx->surfs_size = array_size(emu->surfs);
render_ctx->verts = emu->verts;
render_ctx->verts_size = array_size(emu->verts);
render_ctx->sorted_surfs = emu->sorted_surfs;
render_ctx->sorted_surfs_size = array_size(emu->sorted_surfs);
tr_parse_context(emu->tr, pending_ctx, pending_frame, render_ctx);
tr_parse_context(emu->tr, pending_ctx, render_ctx);
ta_unlock_pending_context(emu->dc->ta);
}
@ -284,5 +283,8 @@ struct emu *emu_create(struct window *window) {
{0}};
win_add_listener(emu->window, &emu->listener);
/* enable debug menu by default */
win_enable_debug_menu(emu->window, 1);
return emu;
}

View File

@ -6,41 +6,41 @@
#include "ui/nuklear.h"
#include "ui/window.h"
static const char *s_param_names[] = {
static const char *param_names[] = {
"TA_PARAM_END_OF_LIST", "TA_PARAM_USER_TILE_CLIP", "TA_PARAM_OBJ_LIST_SET",
"TA_PARAM_RESERVED0", "TA_PARAM_POLY_OR_VOL", "TA_PARAM_SPRITE",
"TA_PARAM_RESERVED1", "TA_PARAM_VERTEX",
};
static const char *s_list_names[] = {
static const char *list_names[] = {
"TA_LIST_OPAQUE", "TA_LIST_OPAQUE_MODVOL",
"TA_LIST_TRANSLUCENT", "TA_LIST_TRANSLUCENT_MODVOL",
"TA_LIST_PUNCH_THROUGH",
};
static const char *s_pixel_format_names[] = {
static const char *pxl_names[] = {
"PXL_INVALID", "PXL_RGBA", "PXL_RGBA5551",
"PXL_RGB565", "PXL_RGBA4444", "PXL_RGBA8888",
};
static const char *s_filter_mode_names[] = {
static const char *filter_names[] = {
"FILTER_NEAREST", "FILTER_BILINEAR",
};
static const char *s_wrap_mode_names[] = {
static const char *wrap_names[] = {
"WRAP_REPEAT", "WRAP_CLAMP_TO_EDGE", "WRAP_MIRRORED_REPEAT",
};
static const char *s_depthfunc_names[] = {
static const char *depthfunc_names[] = {
"NONE", "NEVER", "LESS", "EQUAL", "LEQUAL",
"GREATER", "NEQUAL", "GEQUAL", "ALWAYS",
};
static const char *s_cullface_names[] = {
static const char *cullface_names[] = {
"NONE", "FRONT", "BACK",
};
static const char *s_blendfunc_names[] = {
static const char *blendfunc_names[] = {
"NONE",
"ZERO",
"ONE",
@ -54,7 +54,7 @@ static const char *s_blendfunc_names[] = {
"ONE_MINUS_DST_COLOR",
};
static const char *s_shademode_names[] = {
static const char *shademode_names[] = {
"DECAL", "MODULATE", "DECAL_ALPHA", "MODULATE_ALPHA",
};
@ -78,18 +78,16 @@ struct tracer {
/* trace state */
struct trace *trace;
struct tile_ctx ctx;
uint8_t params[TA_MAX_PARAMS];
struct trace_cmd *current_cmd;
int current_param_offset;
int current_context;
int num_contexts;
int current_param;
int scroll_to_param;
/* render state */
struct render_context rctx;
struct render_context rc;
struct surface surfs[TA_MAX_SURFS];
struct vertex verts[TA_MAX_VERTS];
int sorted_surfs[TA_MAX_SURFS];
struct param_state states[TA_MAX_PARAMS];
struct render_param params[TA_MAX_PARAMS / 32];
struct tracer_texture_entry textures[1024];
struct rb_tree live_textures;
@ -131,7 +129,7 @@ static struct tracer_texture_entry *tracer_find_texture(struct tracer *tracer,
}
static void tracer_add_texture(struct tracer *tracer, union tsp tsp,
union tcw tcw, const uint8_t *palette,
union tcw tcw, int frame, const uint8_t *palette,
const uint8_t *texture) {
struct tracer_texture_entry *entry = tracer_find_texture(tracer, tsp, tcw);
int new_entry = 0;
@ -148,8 +146,9 @@ static void tracer_add_texture(struct tracer *tracer, union tsp tsp,
rb_insert(&tracer->live_textures, &entry->live_it, &tracer_texture_cb);
new_entry = 1;
};
}
entry->frame = frame;
entry->dirty = new_entry ? 0 : 1;
entry->palette = palette;
entry->texture = texture;
@ -170,6 +169,7 @@ static void tracer_copy_command(const struct trace_cmd *cmd,
/* copy TRACE_CMD_CONTEXT to the current context being rendered */
CHECK_EQ(cmd->type, TRACE_CMD_CONTEXT);
ctx->frame = cmd->context.frame;
ctx->autosort = cmd->context.autosort;
ctx->stride = cmd->context.stride;
ctx->pal_pxl_format = cmd->context.pal_pxl_format;
@ -185,58 +185,42 @@ static void tracer_copy_command(const struct trace_cmd *cmd,
ctx->size = cmd->context.params_size;
}
static inline bool param_state_empty(struct param_state *param_state) {
return !param_state->num_surfs && !param_state->num_verts;
}
static inline bool tracer_param_hidden(struct tracer *tracer, union pcw pcw) {
return !tracer->show_params[pcw.para_type];
}
static void tracer_prev_param(struct tracer *tracer) {
int offset = tracer->current_param_offset;
int i = tracer->current_param;
while (--offset >= 0) {
struct param_state *param_state = &tracer->rctx.states[offset];
if (param_state_empty(param_state)) {
continue;
}
union pcw pcw = *(union pcw *)(tracer->ctx.params + offset);
while (i--) {
struct render_param *rp = &tracer->rc.params[i];
union pcw pcw = *(const union pcw *)(tracer->params + rp->offset);
/* found the next visible param */
if (!tracer_param_hidden(tracer, pcw)) {
tracer->current_param_offset = offset;
tracer->current_param = i;
tracer->scroll_to_param = 1;
break;
}
}
}
static void tracer_next_param(struct tracer *tracer) {
int offset = tracer->current_param_offset;
int i = tracer->current_param;
while (++offset < tracer->rctx.num_states) {
struct param_state *param_state = &tracer->rctx.states[offset];
if (param_state_empty(param_state)) {
continue;
}
union pcw pcw = *(union pcw *)(tracer->ctx.params + offset);
while (++i < tracer->rc.num_params) {
struct render_param *rp = &tracer->rc.params[i];
union pcw pcw = *(const union pcw *)(tracer->params + rp->offset);
/* found the next visible param */
if (!tracer_param_hidden(tracer, pcw)) {
tracer->current_param_offset = offset;
tracer->current_param = i;
tracer->scroll_to_param = 1;
break;
}
}
}
static void tracer_reset_param(struct tracer *tracer) {
tracer->current_param_offset = -1;
}
static void tracer_prev_context(struct tracer *tracer) {
struct trace_cmd *begin = tracer->current_cmd->prev;
@ -266,7 +250,7 @@ static void tracer_prev_context(struct tracer *tracer) {
CHECK_EQ(override->type, TRACE_CMD_TEXTURE);
tracer_add_texture(tracer, override->texture.tsp, override->texture.tcw,
override->texture.palette,
override->texture.frame, override->texture.palette,
override->texture.texture);
}
}
@ -274,10 +258,11 @@ static void tracer_prev_context(struct tracer *tracer) {
curr = curr->prev;
}
tracer->current_cmd = curr;
tracer->current_context--;
tracer->current_cmd = prev;
tracer->current_param = -1;
tracer->scroll_to_param = 0;
tracer_copy_command(tracer->current_cmd, &tracer->ctx);
tracer_reset_param(tracer);
tr_parse_context(tracer->tr, &tracer->ctx, &tracer->rc);
}
static void tracer_next_context(struct tracer *tracer) {
@ -305,35 +290,22 @@ static void tracer_next_context(struct tracer *tracer) {
while (curr != next) {
if (curr->type == TRACE_CMD_TEXTURE) {
tracer_add_texture(tracer, curr->texture.tsp, curr->texture.tcw,
curr->texture.palette, curr->texture.texture);
curr->texture.frame, curr->texture.palette,
curr->texture.texture);
}
curr = curr->next;
}
tracer->current_cmd = curr;
tracer->current_context++;
tracer->current_cmd = next;
tracer->current_param = -1;
tracer->scroll_to_param = 0;
tracer_copy_command(tracer->current_cmd, &tracer->ctx);
tracer_reset_param(tracer);
tr_parse_context(tracer->tr, &tracer->ctx, &tracer->rc);
}
static void tracer_reset_context(struct tracer *tracer) {
/* calculate the total number of frames for the trace */
struct trace_cmd *cmd = tracer->trace->cmds;
tracer->num_contexts = 0;
while (cmd) {
if (cmd->type == TRACE_CMD_CONTEXT) {
tracer->num_contexts++;
}
cmd = cmd->next;
}
/* start rendering the first context */
tracer->current_cmd = NULL;
tracer->current_context = -1;
tracer_next_context(tracer);
}
@ -354,12 +326,16 @@ static void tracer_render_scrubber_menu(struct tracer *tracer) {
nk_flags flags = NK_WINDOW_NO_SCROLLBAR;
if (nk_begin(ctx, "context scrubber", bounds, flags)) {
nk_window_set_bounds(ctx, bounds);
nk_layout_row_dynamic(ctx, SCRUBBER_WINDOW_HEIGHT, 1);
nk_size frame = tracer->current_context;
nk_size frame = tracer->ctx.frame - tracer->trace->first_frame;
nk_size max_frames = tracer->trace->last_frame - tracer->trace->first_frame;
if (nk_progress(ctx, &frame, max_frames - 1, true)) {
int delta = tracer->trace->first_frame + (int)frame - tracer->ctx.frame;
if (nk_progress(ctx, &frame, tracer->num_contexts - 1, true)) {
int delta = (int)frame - tracer->current_context;
for (int i = 0; i < ABS(delta); i++) {
if (delta > 0) {
tracer_next_context(tracer);
@ -372,24 +348,23 @@ static void tracer_render_scrubber_menu(struct tracer *tracer) {
nk_end(ctx);
}
static void tracer_param_tooltip(struct tracer *tracer, int list_type,
int vertex_type, int offset) {
static void tracer_param_tooltip(struct tracer *tracer,
struct render_param *rp) {
struct nk_context *ctx = &tracer->window->nk->ctx;
struct param_state *param_state = &tracer->rctx.states[offset];
int surf_id = param_state->num_surfs - 1;
int vert_id = param_state->num_verts - 1;
if (nk_tooltip_begin(ctx, 300.0f)) {
nk_layout_row_dynamic(ctx, ctx->style.font->height, 1);
nk_labelf(ctx, NK_TEXT_LEFT, "list type: %s", s_list_names[list_type]);
nk_labelf(ctx, NK_TEXT_LEFT, "surf: %d", surf_id);
nk_labelf(ctx, NK_TEXT_LEFT, "list type: %s", list_names[rp->list_type]);
nk_labelf(ctx, NK_TEXT_LEFT, "surf: %d", rp->surf - tracer->rc.surfs);
/* find sorted position */
int sort = 0;
for (int i = 0, n = tracer->rctx.num_surfs; i < n; i++) {
int idx = tracer->rctx.sorted_surfs[i];
if (idx == surf_id) {
for (int i = 0; i < tracer->rc.num_surfs; i++) {
int idx = tracer->rc.sorted_surfs[i];
struct surface *surf = &tracer->rc.surfs[idx];
if (surf == rp->surf) {
sort = i;
break;
}
@ -397,9 +372,12 @@ static void tracer_param_tooltip(struct tracer *tracer, int list_type,
nk_labelf(ctx, NK_TEXT_LEFT, "sort: %d", sort);
/* render source TA information */
if (vertex_type == -1) {
union pcw pcw = *(const union pcw *)(tracer->params + rp->offset);
if (pcw.para_type == TA_PARAM_POLY_OR_VOL ||
pcw.para_type == TA_PARAM_SPRITE) {
const union poly_param *param =
(const union poly_param *)(tracer->ctx.params + offset);
(const union poly_param *)(tracer->params + rp->offset);
nk_labelf(ctx, NK_TEXT_LEFT, "pcw: 0x%x", param->type0.pcw.full);
nk_labelf(ctx, NK_TEXT_LEFT, "isp_tsp: 0x%x", param->type0.isp_tsp.full);
@ -448,13 +426,13 @@ static void tracer_param_tooltip(struct tracer *tracer, int list_type,
param->sprite.offset_color);
break;
}
} else {
} else if (pcw.para_type == TA_PARAM_VERTEX) {
const union vert_param *param =
(const union vert_param *)(tracer->ctx.params + offset);
(const union vert_param *)(tracer->params + rp->offset);
nk_labelf(ctx, NK_TEXT_LEFT, "vert type: %d", vertex_type);
nk_labelf(ctx, NK_TEXT_LEFT, "vert type: %d", rp->vertex_type);
switch (vertex_type) {
switch (rp->vertex_type) {
case 0:
nk_labelf(ctx, NK_TEXT_LEFT, "xyz: {%.2f, %.2f, %.2f}",
param->type0.xyz[0], param->type0.xyz[1],
@ -585,31 +563,33 @@ static void tracer_param_tooltip(struct tracer *tracer, int list_type,
/* always render translated surface information. new surfaces can be created
without receiving a new TA_PARAM_POLY_OR_VOL / TA_PARAM_SPRITE */
struct surface *surf = &tracer->rctx.surfs[surf_id];
if (rp->surf) {
struct surface *surf = rp->surf;
/* TODO separator */
/* TODO separator */
nk_layout_row_static(ctx, 40.0f, 40, 1);
nk_image(ctx, nk_image_id((int)surf->texture));
nk_layout_row_static(ctx, 40.0f, 40, 1);
nk_image(ctx, nk_image_id((int)surf->texture));
nk_layout_row_dynamic(ctx, ctx->style.font->height, 1);
nk_labelf(ctx, NK_TEXT_LEFT, "depth_write: %d", surf->depth_write);
nk_labelf(ctx, NK_TEXT_LEFT, "depth_func: %s",
s_depthfunc_names[surf->depth_func]);
nk_labelf(ctx, NK_TEXT_LEFT, "cull: %s", s_cullface_names[surf->cull]);
nk_labelf(ctx, NK_TEXT_LEFT, "src_blend: %s",
s_blendfunc_names[surf->src_blend]);
nk_labelf(ctx, NK_TEXT_LEFT, "dst_blend: %s",
s_blendfunc_names[surf->dst_blend]);
nk_labelf(ctx, NK_TEXT_LEFT, "shade: %s", s_shademode_names[surf->shade]);
nk_labelf(ctx, NK_TEXT_LEFT, "ignore_tex_alpha: %d",
surf->ignore_tex_alpha);
nk_labelf(ctx, NK_TEXT_LEFT, "first_vert: %d", surf->first_vert);
nk_labelf(ctx, NK_TEXT_LEFT, "num_verts: %d", surf->num_verts);
nk_layout_row_dynamic(ctx, ctx->style.font->height, 1);
nk_labelf(ctx, NK_TEXT_LEFT, "depth_write: %d", surf->depth_write);
nk_labelf(ctx, NK_TEXT_LEFT, "depth_func: %s",
depthfunc_names[surf->depth_func]);
nk_labelf(ctx, NK_TEXT_LEFT, "cull: %s", cullface_names[surf->cull]);
nk_labelf(ctx, NK_TEXT_LEFT, "src_blend: %s",
blendfunc_names[surf->src_blend]);
nk_labelf(ctx, NK_TEXT_LEFT, "dst_blend: %s",
blendfunc_names[surf->dst_blend]);
nk_labelf(ctx, NK_TEXT_LEFT, "shade: %s", shademode_names[surf->shade]);
nk_labelf(ctx, NK_TEXT_LEFT, "ignore_tex_alpha: %d",
surf->ignore_tex_alpha);
nk_labelf(ctx, NK_TEXT_LEFT, "first_vert: %d", surf->first_vert);
nk_labelf(ctx, NK_TEXT_LEFT, "num_verts: %d", surf->num_verts);
}
/* render translated vert only when rendering a vertex tooltip */
if (vertex_type != -1) {
struct vertex *vert = &tracer->rctx.verts[vert_id];
if (rp->vert) {
struct vertex *vert = rp->vert;
/* TODO separator */
@ -641,10 +621,15 @@ static void tracer_render_side_menu(struct tracer *tracer) {
char label[128];
if (nk_begin(ctx, "side menu", bounds, 0)) {
/* parem filters */
nk_window_set_bounds(ctx, bounds);
struct nk_window *win = ctx->current;
struct nk_panel *layout = win->layout;
/* param filters */
if (nk_tree_push(ctx, NK_TREE_TAB, "filters", NK_MINIMIZED)) {
for (int i = 0; i < TA_NUM_PARAMS; i++) {
snprintf(label, sizeof(label), "Show %s", s_param_names[i]);
snprintf(label, sizeof(label), "Show %s", param_names[i]);
nk_checkbox_text(ctx, label, (int)strlen(label),
&tracer->show_params[i]);
}
@ -654,64 +639,49 @@ static void tracer_render_side_menu(struct tracer *tracer) {
/* context parameters */
if (nk_tree_push(ctx, NK_TREE_TAB, "params", 0)) {
/* param list */
int list_type = TA_NUM_LISTS;
int vertex_type = TA_NUM_VERTS;
for (int i = 0; i < tracer->rc.num_params; i++) {
struct render_param *rp = &tracer->rc.params[i];
union pcw pcw = *(const union pcw *)(tracer->params + rp->offset);
for (int offset = 0; offset < tracer->rctx.num_states; offset++) {
struct param_state *param_state = &tracer->rctx.states[offset];
if (param_state_empty(param_state)) {
continue;
}
union pcw pcw = *(union pcw *)(tracer->ctx.params + offset);
int param_selected = (offset == tracer->current_param_offset);
int selected = (i == tracer->current_param);
if (!tracer_param_hidden(tracer, pcw)) {
struct nk_rect bounds = nk_widget_bounds(ctx);
snprintf(label, sizeof(label), "0x%04x %s", offset,
s_param_names[pcw.para_type]);
nk_selectable_label(ctx, label, NK_TEXT_LEFT, &param_selected);
if (ta_pcw_list_type_valid(pcw, list_type)) {
list_type = pcw.list_type;
}
snprintf(label, sizeof(label), "0x%04x %s", rp->offset,
param_names[pcw.para_type]);
nk_selectable_label(ctx, label, NK_TEXT_LEFT, &selected);
switch (pcw.para_type) {
/* control params */
case TA_PARAM_END_OF_LIST:
list_type = TA_NUM_LISTS;
vertex_type = TA_NUM_VERTS;
break;
case TA_PARAM_USER_TILE_CLIP:
break;
case TA_PARAM_OBJ_LIST_SET:
LOG_FATAL("TA_PARAM_OBJ_LIST_SET unsupported");
break;
/* global params */
case TA_PARAM_POLY_OR_VOL:
case TA_PARAM_SPRITE:
vertex_type = ta_get_vert_type(pcw);
if (nk_input_is_mouse_hovering_rect(&ctx->input, bounds)) {
tracer_param_tooltip(tracer, list_type, -1, offset);
tracer_param_tooltip(tracer, rp);
}
break;
/* vertex params */
case TA_PARAM_VERTEX:
if (nk_input_is_mouse_hovering_rect(&ctx->input, bounds)) {
tracer_param_tooltip(tracer, list_type, vertex_type, offset);
tracer_param_tooltip(tracer, rp);
}
break;
}
if (param_selected) {
tracer->current_param_offset = offset;
if (selected) {
tracer->current_param = i;
/* scroll to parameter if not visible */
if (tracer->scroll_to_param) {
float at_y = layout->at_y;
float min_visible_y = layout->offset->y;
float max_visible_y = layout->offset->y + layout->bounds.h;
if (at_y < min_visible_y || at_y >= max_visible_y) {
layout->offset->y = at_y;
}
tracer->scroll_to_param = 0;
}
}
}
}
@ -749,13 +719,13 @@ static void tracer_render_side_menu(struct tracer *tracer) {
nk_labelf(ctx, NK_TEXT_LEFT, "addr: 0x%08x",
entry->tcw.texture_addr << 3);
nk_labelf(ctx, NK_TEXT_LEFT, "format: %s",
s_pixel_format_names[entry->format]);
pxl_names[entry->format]);
nk_labelf(ctx, NK_TEXT_LEFT, "filter: %s",
s_filter_mode_names[entry->filter]);
filter_names[entry->filter]);
nk_labelf(ctx, NK_TEXT_LEFT, "wrap_u: %s",
s_wrap_mode_names[entry->wrap_u]);
wrap_names[entry->wrap_u]);
nk_labelf(ctx, NK_TEXT_LEFT, "wrap_v: %s",
s_wrap_mode_names[entry->wrap_v]);
wrap_names[entry->wrap_v]);
nk_labelf(ctx, NK_TEXT_LEFT, "mipmaps: %d", entry->mipmaps);
nk_labelf(ctx, NK_TEXT_LEFT, "width: %d", entry->width);
nk_labelf(ctx, NK_TEXT_LEFT, "height: %d", entry->height);
@ -781,35 +751,31 @@ static void tracer_render_side_menu(struct tracer *tracer) {
static void tracer_paint(void *data) {
struct tracer *tracer = data;
tr_parse_context(tracer->tr, &tracer->ctx, 0, &tracer->rctx);
/* render ui */
tracer_render_side_menu(tracer);
tracer_render_scrubber_menu(tracer);
/* clamp surfaces the last surface belonging to the current param */
int n = tracer->rctx.num_surfs;
int last_idx = n;
/* only render up to the surface of the currently selected param */
int num_surfs = tracer->rc.num_surfs;
int last_surf = num_surfs - 1;
if (tracer->current_param_offset >= 0) {
const struct param_state *offset =
&tracer->rctx.states[tracer->current_param_offset];
last_idx = offset->num_surfs;
if (tracer->current_param >= 0) {
const struct render_param *rp = &tracer->rc.params[tracer->current_param];
last_surf = rp->surf - tracer->rc.surfs;
}
/* render the context */
rb_begin_surfaces(tracer->rb, tracer->rctx.projection, tracer->rctx.verts,
tracer->rctx.num_verts);
rb_begin_surfaces(tracer->rb, tracer->rc.projection, tracer->rc.verts,
tracer->rc.num_verts);
for (int i = 0; i < n; i++) {
int idx = tracer->rctx.sorted_surfs[i];
for (int i = 0; i < num_surfs; i++) {
int idx = tracer->rc.sorted_surfs[i];
/* if this surface comes after the current parameter, ignore it */
if (idx >= last_idx) {
if (idx > last_surf) {
continue;
}
rb_draw_surface(tracer->rb, &tracer->rctx.surfs[idx]);
rb_draw_surface(tracer->rb, &tracer->rc.surfs[idx]);
}
rb_end_surfaces(tracer->rb);
@ -870,6 +836,15 @@ void tracer_run(struct tracer *tracer, const char *path) {
}
}
void tracer_destroy(struct tracer *tracer) {
if (tracer->trace) {
trace_destroy(tracer->trace);
}
win_remove_listener(tracer->window, &tracer->listener);
tr_destroy(tracer->tr);
free(tracer);
}
struct tracer *tracer_create(struct window *window) {
/* ensure param / poly / vertex size LUTs are generated */
ta_build_tables();
@ -888,14 +863,14 @@ struct tracer *tracer_create(struct window *window) {
win_add_listener(tracer->window, &tracer->listener);
/* setup render context buffers */
tracer->rctx.surfs = tracer->surfs;
tracer->rctx.surfs_size = array_size(tracer->surfs);
tracer->rctx.verts = tracer->verts;
tracer->rctx.verts_size = array_size(tracer->verts);
tracer->rctx.sorted_surfs = tracer->sorted_surfs;
tracer->rctx.sorted_surfs_size = array_size(tracer->sorted_surfs);
tracer->rctx.states = tracer->states;
tracer->rctx.states_size = array_size(tracer->states);
tracer->rc.surfs = tracer->surfs;
tracer->rc.surfs_size = array_size(tracer->surfs);
tracer->rc.verts = tracer->verts;
tracer->rc.verts_size = array_size(tracer->verts);
tracer->rc.sorted_surfs = tracer->sorted_surfs;
tracer->rc.sorted_surfs_size = array_size(tracer->sorted_surfs);
tracer->rc.params = tracer->params;
tracer->rc.params_size = array_size(tracer->params);
/* add all textures to free list */
for (int i = 0, n = array_size(tracer->textures); i < n; i++) {
@ -915,12 +890,3 @@ struct tracer *tracer_create(struct window *window) {
return tracer;
}
void tracer_destroy(struct tracer *tracer) {
if (tracer->trace) {
trace_destroy(tracer->trace);
}
win_remove_listener(tracer->window, &tracer->listener);
tr_destroy(tracer->tr);
free(tracer);
}

View File

@ -4,9 +4,9 @@
struct tracer;
struct window;
void tracer_run(struct tracer *tracer, const char *path);
struct tracer *tracer_create(struct window *window);
void tracer_destroy(struct tracer *tracer);
void tracer_run(struct tracer *tracer, const char *path);
#endif

View File

@ -263,12 +263,20 @@ static struct ta_texture_entry *ta_find_texture(struct ta *ta, union tsp tsp,
static struct texture_entry *ta_texture_provider_find_texture(void *data,
union tsp tsp,
union tcw tcw) {
struct ta_texture_entry *entry = ta_find_texture(data, tsp, tcw);
struct ta *ta = (struct ta *)data;
struct ta_texture_entry *entry = ta_find_texture(ta, tsp, tcw);
if (!entry) {
return NULL;
}
if (entry->dirty) {
/* sanity check that the texture source is valid for the current context.
video ram will be modified between frames, if these values don't match
something is broken in the thread synchronization */
CHECK_EQ(entry->frame, ta->frame);
}
return (struct texture_entry *)entry;
}
@ -428,11 +436,10 @@ static void ta_write_context(struct ta *ta, struct tile_ctx *ctx, void *ptr,
static void ta_register_texture(struct ta *ta, union tsp tsp, union tcw tcw) {
struct ta_texture_entry *entry = ta_find_texture(ta, tsp, tcw);
int new_entry = 0;
if (!entry) {
entry = ta_alloc_texture(ta, tsp, tcw);
new_entry = 1;
entry->dirty = 1;
}
/* mark texture source valid for the current frame */
@ -494,10 +501,10 @@ static void ta_register_texture(struct ta *ta, union tsp tsp, union tcw tcw) {
#endif
/* add modified entries to the trace */
if (ta->trace_writer && (new_entry || entry->dirty)) {
trace_writer_insert_texture(ta->trace_writer, tsp, tcw, entry->palette,
entry->palette_size, entry->texture,
entry->texture_size);
if (ta->trace_writer && entry->dirty) {
trace_writer_insert_texture(ta->trace_writer, tsp, tcw, entry->frame,
entry->palette, entry->palette_size,
entry->texture, entry->texture_size);
}
}
@ -534,10 +541,13 @@ static void ta_register_textures(struct ta *ta, struct tile_ctx *ctx,
}
}
static void ta_save_register_state(struct ta *ta, struct tile_ctx *ctx) {
static void ta_save_state(struct ta *ta, struct tile_ctx *ctx) {
struct pvr *pvr = ta->pvr;
struct address_space *space = ta->sh4->memory_if->space;
/* mark context valid for the current frame */
ctx->frame = ta->frame;
/* autosort */
if (!pvr->FPU_PARAM_CFG->region_header_type) {
ctx->autosort = !pvr->ISP_FEED_CFG->presort;
@ -630,10 +640,6 @@ static void ta_render_timer(void *data) {
}
static void ta_start_render(struct ta *ta, struct tile_ctx *ctx) {
/* save off required register state that may be modified by the time the
context is rendered */
ta_save_register_state(ta, ctx);
/* if the graphics thread is still parsing the previous context, skip this
one */
if (!mutex_trylock(ta->pending_mutex)) {
@ -654,10 +660,15 @@ static void ta_start_render(struct ta *ta, struct tile_ctx *ctx) {
ta_unlink_context(ta, ctx);
ta->pending_context = ctx;
/* increment internal frame number. this frame number is assigned to each
texture source registered by this context */
/* increment internal frame number. this frame number is assigned to the
context and each texture source it registers to assert synchronization
between the emulator and graphics thread is working as expected */
ta->frame++;
/* save off required state that may be modified by the time the context is
rendered */
ta_save_state(ta, ctx);
/* register the source of each texture referenced by the context with the
tile renderer. note, the process of actually uploading the texture to the
render backend happens lazily while rendering the context (keeping all
@ -944,8 +955,7 @@ void ta_unlock_pending_context(struct ta *ta) {
mutex_unlock(ta->pending_mutex);
}
int ta_lock_pending_context(struct ta *ta, struct tile_ctx **pending_ctx,
int *pending_frame) {
int ta_lock_pending_context(struct ta *ta, struct tile_ctx **pending_ctx) {
mutex_lock(ta->pending_mutex);
if (!ta->pending_context) {
@ -953,8 +963,11 @@ int ta_lock_pending_context(struct ta *ta, struct tile_ctx **pending_ctx,
return 0;
}
/* ensure that the pending context is still valid */
CHECK_EQ(ta->pending_context->frame, ta->frame);
*pending_ctx = ta->pending_context;
*pending_frame = ta->frame;
return 1;
}
@ -1009,7 +1022,8 @@ REG_W32(pvr_cb, TA_LIST_INIT) {
return;
}
struct tile_ctx *ctx = ta_demand_context(ta, ta->pvr->TA_ISP_BASE->base_address);
struct tile_ctx *ctx =
ta_demand_context(ta, ta->pvr->TA_ISP_BASE->base_address);
ta_init_context(ta, ctx);
ta->next_context = ctx;
}

View File

@ -45,8 +45,7 @@ struct ta *ta_create(struct dreamcast *dc);
void ta_destroy(struct ta *ta);
struct texture_provider *ta_texture_provider(struct ta *ta);
int ta_lock_pending_context(struct ta *ta, struct tile_ctx **pending_ctx,
int *pending_frame);
int ta_lock_pending_context(struct ta *ta, struct tile_ctx **pending_ctx);
void ta_unlock_pending_context(struct ta *ta);
#endif

View File

@ -442,6 +442,7 @@ struct tile_ctx {
uint32_t addr;
/* pvr / ta state */
int frame;
bool autosort;
int stride;
int pal_pxl_format;

View File

@ -117,7 +117,7 @@ static inline uint32_t float_to_rgba(float r, float g, float b, float a) {
}
static texture_handle_t tr_demand_texture(struct tr *tr,
const struct tile_ctx *ctx, int frame,
const struct tile_ctx *ctx,
union tsp tsp, union tcw tcw) {
/* TODO it's bad that textures are only cached based off tsp / tcw yet the
TEXT_CONTROL registers and PAL_RAM_CTRL registers are used here to control
@ -138,11 +138,6 @@ static texture_handle_t tr_demand_texture(struct tr *tr,
entry->handle = 0;
}
/* sanity check that the texture source is valid for the current frame. video
ram will be modified between frames, if these values don't match something
is broken in the ta's thread synchronization */
CHECK_EQ(frame, entry->frame);
static uint8_t converted[1024 * 1024 * 4];
const uint8_t *palette = entry->palette;
const uint8_t *texture = entry->texture;
@ -313,47 +308,46 @@ static texture_handle_t tr_demand_texture(struct tr *tr,
return entry->handle;
}
static struct surface *tr_alloc_surf(struct tr *tr, struct render_context *rctx,
static struct surface *tr_alloc_surf(struct tr *tr, struct render_context *rc,
bool copy_from_prev) {
CHECK_LT(rctx->num_surfs, rctx->surfs_size);
int id = rctx->num_surfs++;
struct surface *surf = &rctx->surfs[id];
CHECK_LT(rc->num_surfs, rc->surfs_size);
int id = rc->num_surfs++;
struct surface *surf = &rc->surfs[id];
if (copy_from_prev) {
*surf = rctx->surfs[id - 1];
*surf = rc->surfs[id - 1];
} else {
memset(surf, 0, sizeof(*surf));
}
/* start verts at the end */
surf->first_vert = rctx->num_verts;
surf->first_vert = rc->num_verts;
surf->num_verts = 0;
/* default sort the surface */
rctx->sorted_surfs[id] = id;
rc->sorted_surfs[id] = id;
return surf;
}
static struct vertex *tr_alloc_vert(struct tr *tr,
struct render_context *rctx) {
CHECK_LT(rctx->num_verts, rctx->verts_size);
int id = rctx->num_verts++;
struct vertex *v = &rctx->verts[id];
static struct vertex *tr_alloc_vert(struct tr *tr, struct render_context *rc) {
CHECK_LT(rc->num_verts, rc->verts_size);
int id = rc->num_verts++;
struct vertex *v = &rc->verts[id];
memset(v, 0, sizeof(*v));
/* update vertex count on the current surface */
struct surface *surf = &rctx->surfs[rctx->num_surfs - 1];
struct surface *surf = &rc->surfs[rc->num_surfs - 1];
surf->num_verts++;
return v;
}
static void tr_discard_incomplete_surf(struct tr *tr,
struct render_context *rctx) {
struct render_context *rc) {
/* free up the last surface if it wasn't finished */
if (tr->last_vertex && !tr->last_vertex->type0.pcw.end_of_strip) {
rctx->num_surfs--;
rc->num_surfs--;
}
}
@ -453,9 +447,9 @@ static int tr_parse_bg_vert(const struct tile_ctx *ctx, int offset,
}
static void tr_parse_bg(struct tr *tr, const struct tile_ctx *ctx,
struct render_context *rctx) {
struct render_context *rc) {
/* translate the surface */
struct surface *surf = tr_alloc_surf(tr, rctx, false);
struct surface *surf = tr_alloc_surf(tr, rc, false);
surf->texture = 0;
surf->depth_write = !ctx->bg_isp.z_write_disable;
@ -465,10 +459,10 @@ static void tr_parse_bg(struct tr *tr, const struct tile_ctx *ctx,
surf->dst_blend = BLEND_NONE;
/* translate the first 3 vertices */
struct vertex *v0 = tr_alloc_vert(tr, rctx);
struct vertex *v1 = tr_alloc_vert(tr, rctx);
struct vertex *v2 = tr_alloc_vert(tr, rctx);
struct vertex *v3 = tr_alloc_vert(tr, rctx);
struct vertex *v0 = tr_alloc_vert(tr, rc);
struct vertex *v1 = tr_alloc_vert(tr, rc);
struct vertex *v2 = tr_alloc_vert(tr, rc);
struct vertex *v3 = tr_alloc_vert(tr, rc);
int offset = 0;
offset = tr_parse_bg_vert(ctx, offset, v0);
@ -500,9 +494,9 @@ static void tr_parse_bg(struct tr *tr, const struct tile_ctx *ctx,
/* this offset color implementation is not correct at all, see the
Texture/Shading Instruction in the union tsp instruction word */
static void tr_parse_poly_param(struct tr *tr, const struct tile_ctx *ctx,
int frame, struct render_context *rctx,
struct render_context *rc,
const uint8_t *data) {
tr_discard_incomplete_surf(tr, rctx);
tr_discard_incomplete_surf(tr, rc);
const union poly_param *param = (const union poly_param *)data;
@ -559,7 +553,7 @@ static void tr_parse_poly_param(struct tr *tr, const struct tile_ctx *ctx,
}
/* setup the new surface */
struct surface *surf = tr_alloc_surf(tr, rctx, false);
struct surface *surf = tr_alloc_surf(tr, rc, false);
surf->depth_write = !param->type0.isp_tsp.z_write_disable;
surf->depth_func =
translate_depth_func(param->type0.isp_tsp.depth_compare_mode);
@ -584,7 +578,7 @@ static void tr_parse_poly_param(struct tr *tr, const struct tile_ctx *ctx,
if (param->type0.pcw.texture) {
surf->texture =
tr_demand_texture(tr, ctx, frame, param->type0.tsp, param->type0.tcw);
tr_demand_texture(tr, ctx, param->type0.tsp, param->type0.tcw);
} else {
surf->texture = 0;
}
@ -630,20 +624,20 @@ static void tr_parse_spriteb_vert(struct tr *tr, const union vert_param *param,
}
static void tr_parse_vert_param(struct tr *tr, const struct tile_ctx *ctx,
struct render_context *rctx,
struct render_context *rc,
const uint8_t *data) {
const union vert_param *param = (const union vert_param *)data;
/* if there is no need to change the Global Parameters, a Vertex Parameter
for the next polygon may be input immediately after inputting a Vertex
Parameter for which "End of Strip" was specified */
if (tr->last_vertex && tr->last_vertex->type0.pcw.end_of_strip) {
tr_alloc_surf(tr, rctx, true);
tr_alloc_surf(tr, rc, true);
}
tr->last_vertex = param;
switch (tr->vertex_type) {
case 0: {
struct vertex *vert = tr_alloc_vert(tr, rctx);
struct vertex *vert = tr_alloc_vert(tr, rc);
vert->xyz[0] = param->type0.xyz[0];
vert->xyz[1] = param->type0.xyz[1];
vert->xyz[2] = param->type0.xyz[2];
@ -654,7 +648,7 @@ static void tr_parse_vert_param(struct tr *tr, const struct tile_ctx *ctx,
} break;
case 1: {
struct vertex *vert = tr_alloc_vert(tr, rctx);
struct vertex *vert = tr_alloc_vert(tr, rc);
vert->xyz[0] = param->type1.xyz[0];
vert->xyz[1] = param->type1.xyz[1];
vert->xyz[2] = param->type1.xyz[2];
@ -667,7 +661,7 @@ static void tr_parse_vert_param(struct tr *tr, const struct tile_ctx *ctx,
} break;
case 2: {
struct vertex *vert = tr_alloc_vert(tr, rctx);
struct vertex *vert = tr_alloc_vert(tr, rc);
vert->xyz[0] = param->type2.xyz[0];
vert->xyz[1] = param->type2.xyz[1];
vert->xyz[2] = param->type2.xyz[2];
@ -678,7 +672,7 @@ static void tr_parse_vert_param(struct tr *tr, const struct tile_ctx *ctx,
} break;
case 3: {
struct vertex *vert = tr_alloc_vert(tr, rctx);
struct vertex *vert = tr_alloc_vert(tr, rc);
vert->xyz[0] = param->type3.xyz[0];
vert->xyz[1] = param->type3.xyz[1];
vert->xyz[2] = param->type3.xyz[2];
@ -689,7 +683,7 @@ static void tr_parse_vert_param(struct tr *tr, const struct tile_ctx *ctx,
} break;
case 4: {
struct vertex *vert = tr_alloc_vert(tr, rctx);
struct vertex *vert = tr_alloc_vert(tr, rc);
vert->xyz[0] = param->type4.xyz[0];
vert->xyz[1] = param->type4.xyz[1];
vert->xyz[2] = param->type4.xyz[2];
@ -702,7 +696,7 @@ static void tr_parse_vert_param(struct tr *tr, const struct tile_ctx *ctx,
} break;
case 5: {
struct vertex *vert = tr_alloc_vert(tr, rctx);
struct vertex *vert = tr_alloc_vert(tr, rc);
vert->xyz[0] = param->type5.xyz[0];
vert->xyz[1] = param->type5.xyz[1];
vert->xyz[2] = param->type5.xyz[2];
@ -718,7 +712,7 @@ static void tr_parse_vert_param(struct tr *tr, const struct tile_ctx *ctx,
} break;
case 6: {
struct vertex *vert = tr_alloc_vert(tr, rctx);
struct vertex *vert = tr_alloc_vert(tr, rc);
vert->xyz[0] = param->type6.xyz[0];
vert->xyz[1] = param->type6.xyz[1];
vert->xyz[2] = param->type6.xyz[2];
@ -736,7 +730,7 @@ static void tr_parse_vert_param(struct tr *tr, const struct tile_ctx *ctx,
} break;
case 7: {
struct vertex *vert = tr_alloc_vert(tr, rctx);
struct vertex *vert = tr_alloc_vert(tr, rc);
vert->xyz[0] = param->type7.xyz[0];
vert->xyz[1] = param->type7.xyz[1];
vert->xyz[2] = param->type7.xyz[2];
@ -748,7 +742,7 @@ static void tr_parse_vert_param(struct tr *tr, const struct tile_ctx *ctx,
} break;
case 8: {
struct vertex *vert = tr_alloc_vert(tr, rctx);
struct vertex *vert = tr_alloc_vert(tr, rc);
vert->xyz[0] = param->type8.xyz[0];
vert->xyz[1] = param->type8.xyz[1];
vert->xyz[2] = param->type8.xyz[2];
@ -762,17 +756,17 @@ static void tr_parse_vert_param(struct tr *tr, const struct tile_ctx *ctx,
} break;
case 15: {
tr_parse_spritea_vert(tr, param, 0, tr_alloc_vert(tr, rctx));
tr_parse_spritea_vert(tr, param, 1, tr_alloc_vert(tr, rctx));
tr_parse_spritea_vert(tr, param, 3, tr_alloc_vert(tr, rctx));
tr_parse_spritea_vert(tr, param, 2, tr_alloc_vert(tr, rctx));
tr_parse_spritea_vert(tr, param, 0, tr_alloc_vert(tr, rc));
tr_parse_spritea_vert(tr, param, 1, tr_alloc_vert(tr, rc));
tr_parse_spritea_vert(tr, param, 3, tr_alloc_vert(tr, rc));
tr_parse_spritea_vert(tr, param, 2, tr_alloc_vert(tr, rc));
} break;
case 16: {
tr_parse_spriteb_vert(tr, param, 0, tr_alloc_vert(tr, rctx));
tr_parse_spriteb_vert(tr, param, 1, tr_alloc_vert(tr, rctx));
tr_parse_spriteb_vert(tr, param, 3, tr_alloc_vert(tr, rctx));
tr_parse_spriteb_vert(tr, param, 2, tr_alloc_vert(tr, rctx));
tr_parse_spriteb_vert(tr, param, 0, tr_alloc_vert(tr, rc));
tr_parse_spriteb_vert(tr, param, 1, tr_alloc_vert(tr, rc));
tr_parse_spriteb_vert(tr, param, 3, tr_alloc_vert(tr, rc));
tr_parse_spriteb_vert(tr, param, 2, tr_alloc_vert(tr, rc));
} break;
case 17: {
@ -793,11 +787,11 @@ static void tr_parse_vert_param(struct tr *tr, const struct tile_ctx *ctx,
/* FIXME is this true for sprites which come through this path as well? */
}
static float tr_cmp_surf(struct render_context *rctx, const struct surface *a,
static float tr_cmp_surf(struct render_context *rc, const struct surface *a,
const struct surface *b) {
float minza = FLT_MAX;
for (int i = 0, n = a->num_verts; i < n; i++) {
struct vertex *v = &rctx->verts[a->first_vert + i];
struct vertex *v = &rc->verts[a->first_vert + i];
if (v->xyz[2] < minza) {
minza = v->xyz[2];
@ -806,7 +800,7 @@ static float tr_cmp_surf(struct render_context *rctx, const struct surface *a,
float minzb = FLT_MAX;
for (int i = 0, n = b->num_verts; i < n; i++) {
struct vertex *v = &rctx->verts[b->first_vert + i];
struct vertex *v = &rc->verts[b->first_vert + i];
if (v->xyz[2] < minzb) {
minzb = v->xyz[2];
@ -816,7 +810,7 @@ static float tr_cmp_surf(struct render_context *rctx, const struct surface *a,
return minza - minzb;
}
static void tr_merge_surfs(struct render_context *rctx, int *low, int *mid,
static void tr_merge_surfs(struct render_context *rc, int *low, int *mid,
int *high) {
static int tmp[16384];
@ -827,7 +821,7 @@ static void tr_merge_surfs(struct render_context *rctx, int *low, int *mid,
while (i <= mid && j <= high) {
DCHECK_LT(k, end);
if (tr_cmp_surf(rctx, &rctx->surfs[*i], &rctx->surfs[*j]) <= 0.0f) {
if (tr_cmp_surf(rc, &rc->surfs[*i], &rc->surfs[*j]) <= 0.0f) {
*(k++) = *(i++);
} else {
*(k++) = *(j++);
@ -847,48 +841,48 @@ static void tr_merge_surfs(struct render_context *rctx, int *low, int *mid,
memcpy(low, tmp, (k - tmp) * sizeof(tmp[0]));
}
static void tr_sort_surfs(struct render_context *rctx, int low, int high) {
static void tr_sort_surfs(struct render_context *rc, int low, int high) {
if (low >= high) {
return;
}
int mid = (low + high) / 2;
tr_sort_surfs(rctx, low, mid);
tr_sort_surfs(rctx, mid + 1, high);
tr_merge_surfs(rctx, &rctx->sorted_surfs[low], &rctx->sorted_surfs[mid],
&rctx->sorted_surfs[high]);
tr_sort_surfs(rc, low, mid);
tr_sort_surfs(rc, mid + 1, high);
tr_merge_surfs(rc, &rc->sorted_surfs[low], &rc->sorted_surfs[mid],
&rc->sorted_surfs[high]);
}
static void tr_parse_eol(struct tr *tr, const struct tile_ctx *ctx,
struct render_context *rctx, const uint8_t *data) {
tr_discard_incomplete_surf(tr, rctx);
struct render_context *rc, const uint8_t *data) {
tr_discard_incomplete_surf(tr, rc);
/* sort transparent polys by their z value, from back to front. remember, in
dreamcast coordinates smaller z values are further away from the camera */
if ((tr->list_type == TA_LIST_TRANSLUCENT ||
tr->list_type == TA_LIST_TRANSLUCENT_MODVOL) &&
ctx->autosort) {
tr_sort_surfs(rctx, tr->last_sorted_surf, rctx->num_surfs - 1);
tr_sort_surfs(rc, tr->last_sorted_surf, rc->num_surfs - 1);
}
tr->last_poly = NULL;
tr->last_vertex = NULL;
tr->list_type = TA_NUM_LISTS;
tr->vertex_type = TA_NUM_VERTS;
tr->last_sorted_surf = rctx->num_surfs;
tr->last_sorted_surf = rc->num_surfs;
}
static void tr_proj_mat(struct tr *tr, const struct tile_ctx *ctx,
struct render_context *rctx) {
struct render_context *rc) {
/* this isn't a traditional projection matrix. xy components coming into the
TA are in window space, while the z component is 1/w with +z headed into
the screen. these coordinates need to be scaled back into ndc space, and
z needs to be flipped so that -z is headed into the screen */
float znear = FLT_MIN;
float znear = -FLT_MAX;
float zfar = FLT_MAX;
for (int i = 0; i < rctx->num_verts; i++) {
struct vertex *v = &rctx->verts[i];
for (int i = 0; i < rc->num_verts; i++) {
struct vertex *v = &rc->verts[i];
if (v->xyz[2] > znear) {
znear = v->xyz[2];
}
@ -900,32 +894,32 @@ static void tr_proj_mat(struct tr *tr, const struct tile_ctx *ctx,
/* fudge so z isn't mapped to exactly 0.0 and 1.0 */
float zdepth = (znear - zfar) * 1.1f;
rctx->projection[0] = 2.0f / (float)ctx->video_width;
rctx->projection[4] = 0.0f;
rctx->projection[8] = 0.0f;
rctx->projection[12] = -1.0f;
rc->projection[0] = 2.0f / (float)ctx->video_width;
rc->projection[4] = 0.0f;
rc->projection[8] = 0.0f;
rc->projection[12] = -1.0f;
rctx->projection[1] = 0.0f;
rctx->projection[5] = -2.0f / (float)ctx->video_height;
rctx->projection[9] = 0.0f;
rctx->projection[13] = 1.0f;
rc->projection[1] = 0.0f;
rc->projection[5] = -2.0f / (float)ctx->video_height;
rc->projection[9] = 0.0f;
rc->projection[13] = 1.0f;
rctx->projection[2] = 0.0f;
rctx->projection[6] = 0.0f;
rctx->projection[10] = 2.0f / -zdepth;
rctx->projection[14] = -2.0f * znear / -zdepth - 1.0f;
rc->projection[2] = 0.0f;
rc->projection[6] = 0.0f;
rc->projection[10] = 2.0f / -zdepth;
rc->projection[14] = -2.0f * znear / -zdepth - 1.0f;
rctx->projection[3] = 0.0f;
rctx->projection[7] = 0.0f;
rctx->projection[11] = 0.0f;
rctx->projection[15] = 1.0f;
rc->projection[3] = 0.0f;
rc->projection[7] = 0.0f;
rc->projection[11] = 0.0f;
rc->projection[15] = 1.0f;
}
static void tr_reset(struct tr *tr, struct render_context *rctx) {
static void tr_reset(struct tr *tr, struct render_context *rc) {
/* reset render state */
rctx->num_surfs = 0;
rctx->num_verts = 0;
rctx->num_states = 0;
rc->num_surfs = 0;
rc->num_verts = 0;
rc->num_params = 0;
/* reset global state */
tr->last_poly = NULL;
@ -935,16 +929,16 @@ static void tr_reset(struct tr *tr, struct render_context *rctx) {
tr->last_sorted_surf = 0;
}
void tr_parse_context(struct tr *tr, const struct tile_ctx *ctx, int frame,
struct render_context *rctx) {
void tr_parse_context(struct tr *tr, const struct tile_ctx *ctx,
struct render_context *rc) {
PROF_ENTER("gpu", "tr_parse_context");
const uint8_t *data = ctx->params;
const uint8_t *end = ctx->params + ctx->size;
tr_reset(tr, rctx);
tr_reset(tr, rc);
tr_parse_bg(tr, ctx, rctx);
tr_parse_bg(tr, ctx, rc);
while (data < end) {
union pcw pcw = *(union pcw *)data;
@ -961,7 +955,7 @@ void tr_parse_context(struct tr *tr, const struct tile_ctx *ctx, int frame,
switch (pcw.para_type) {
/* control params */
case TA_PARAM_END_OF_LIST:
tr_parse_eol(tr, ctx, rctx, data);
tr_parse_eol(tr, ctx, rc, data);
break;
case TA_PARAM_USER_TILE_CLIP:
@ -973,47 +967,46 @@ void tr_parse_context(struct tr *tr, const struct tile_ctx *ctx, int frame,
/* global params */
case TA_PARAM_POLY_OR_VOL:
tr_parse_poly_param(tr, ctx, frame, rctx, data);
tr_parse_poly_param(tr, ctx, rc, data);
break;
case TA_PARAM_SPRITE:
tr_parse_poly_param(tr, ctx, frame, rctx, data);
tr_parse_poly_param(tr, ctx, rc, data);
break;
/* vertex params */
case TA_PARAM_VERTEX:
tr_parse_vert_param(tr, ctx, rctx, data);
tr_parse_vert_param(tr, ctx, rc, data);
break;
}
/* keep track of the surf / vert counts at each parameter offset */
if (rctx->states) {
int offset = (int)(data - ctx->params);
CHECK_LT(offset, rctx->states_size);
rctx->num_states = MAX(rctx->num_states, offset);
struct param_state *param_state = &rctx->states[offset];
param_state->num_surfs = rctx->num_surfs;
param_state->num_verts = rctx->num_verts;
if (rc->params) {
struct render_param *rp = &rc->params[rc->num_params++];
rp->offset = data - ctx->params;
rp->list_type = tr->list_type;
rp->vertex_type = tr->vertex_type;
rp->surf = rc->num_surfs ? &rc->surfs[rc->num_surfs - 1] : NULL;
rp->vert = rc->num_verts ? &rc->verts[rc->num_verts - 1] : NULL;
}
data += ta_get_param_size(pcw, tr->vertex_type);
}
tr_proj_mat(tr, ctx, rctx);
tr_proj_mat(tr, ctx, rc);
PROF_LEAVE();
}
void tr_render_context(struct tr *tr, const struct render_context *rctx) {
void tr_render_context(struct tr *tr, const struct render_context *rc) {
PROF_ENTER("gpu", "tr_render_context");
rb_begin_surfaces(tr->rb, rctx->projection, rctx->verts, rctx->num_verts);
rb_begin_surfaces(tr->rb, rc->projection, rc->verts, rc->num_verts);
const int *sorted_surf = rctx->sorted_surfs;
const int *sorted_surf_end = rctx->sorted_surfs + rctx->num_surfs;
const int *sorted_surf = rc->sorted_surfs;
const int *sorted_surf_end = rc->sorted_surfs + rc->num_surfs;
while (sorted_surf < sorted_surf_end) {
rb_draw_surface(tr->rb, &rctx->surfs[*sorted_surf]);
rb_draw_surface(tr->rb, &rc->surfs[*sorted_surf]);
sorted_surf++;
}

View File

@ -32,28 +32,32 @@ struct texture_entry {
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
*/
/* 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 texture_provider {
void *data;
struct texture_entry *(*find_texture)(void *, union tsp, union tcw);
};
/*
* represents the parse state after each ta parameter. used to visually scrub
* through the scene parameter by parameter in the tracer
*/
struct param_state {
int num_surfs;
int num_verts;
/* debug structure which represents an individual tile parameter from a
tile_context. used to scrub through a frame param by param in the
tracer */
struct render_param {
/* offset of parameter in input tile_context params */
int offset;
/* global list and vertex types at time of parsing */
int list_type;
int vertex_type;
/* surf and vert in output render_context */
struct surface *surf;
struct vertex *vert;
};
/* tile context parsed into appropriate structures for the video backend */
/* represents a tile_context parsed into appropriate structures for the render
backend */
struct render_context {
/* supplied by caller */
/* input / output buffers supplied by caller */
struct surface *surfs;
int surfs_size;
@ -63,14 +67,14 @@ struct render_context {
int *sorted_surfs;
int sorted_surfs_size;
struct param_state *states;
int states_size;
struct render_param *params;
int params_size;
/* */
/* output */
float projection[16];
int num_surfs;
int num_verts;
int num_states;
int num_params;
};
static inline texture_key_t tr_texture_key(union tsp tsp, union tcw tcw) {
@ -81,8 +85,8 @@ struct tr *tr_create(struct render_backend *rb,
struct texture_provider *provider);
void tr_destroy(struct tr *tr);
void tr_parse_context(struct tr *tr, const struct tile_ctx *ctx, int frame,
struct render_context *rctx);
void tr_render_context(struct tr *tr, const struct render_context *rctx);
void tr_parse_context(struct tr *tr, const struct tile_ctx *ctx,
struct render_context *rc);
void tr_render_context(struct tr *tr, const struct render_context *rc);
#endif

View File

@ -1,6 +1,7 @@
#include <limits.h>
#include "hw/pvr/tr.h"
#include "core/assert.h"
#include "core/math.h"
#include "hw/pvr/trace.h"
#include "sys/filesystem.h"
@ -18,63 +19,89 @@ void get_next_trace_filename(char *filename, size_t size) {
LOG_FATAL("Unable to find available trace filename");
}
// Commands are written out with null list pointers, and pointers to data
// are written out relative to the command itself. Set the list pointers,
// and make the data pointers absolute.
static bool trace_patch_pointers(void *begin, int size) {
struct trace_cmd *prev_cmd = NULL;
struct trace_cmd *curr_cmd = NULL;
uint8_t *ptr = begin;
uint8_t *end = ptr + size;
while (ptr < end) {
prev_cmd = curr_cmd;
curr_cmd = (struct trace_cmd *)ptr;
// set prev / next pointers
if (prev_cmd) {
prev_cmd->next = curr_cmd;
}
curr_cmd->prev = prev_cmd;
curr_cmd->next = NULL;
curr_cmd->override = NULL;
// patch relative data pointers
switch (curr_cmd->type) {
case TRACE_CMD_TEXTURE: {
curr_cmd->texture.palette += (intptr_t)ptr;
curr_cmd->texture.texture += (intptr_t)ptr;
ptr += sizeof(*curr_cmd) + curr_cmd->texture.palette_size +
curr_cmd->texture.texture_size;
} break;
case TRACE_CMD_CONTEXT: {
curr_cmd->context.bg_vertices += (intptr_t)ptr;
curr_cmd->context.params += (intptr_t)ptr;
ptr += sizeof(*curr_cmd) + curr_cmd->context.bg_vertices_size +
curr_cmd->context.params_size;
} break;
default:
LOG_INFO("Unexpected trace command type %d", curr_cmd->type);
return false;
}
void trace_writer_close(struct trace_writer *writer) {
if (writer->file) {
fclose(writer->file);
}
return true;
free(writer);
}
// For commands which mutate global state, the previous state needs to be
// tracked in order to support unwinding. To do so, each command is iterated
// and tagged with the previous command that it overrides.
static bool trace_patch_overrides(struct trace_cmd *cmd) {
void trace_writer_render_context(struct trace_writer *writer,
struct tile_ctx *ctx) {
struct trace_cmd cmd = {0};
cmd.type = TRACE_CMD_CONTEXT;
cmd.context.frame = ctx->frame;
cmd.context.autosort = ctx->autosort;
cmd.context.stride = ctx->stride;
cmd.context.pal_pxl_format = ctx->pal_pxl_format;
cmd.context.video_width = ctx->video_width;
cmd.context.video_height = ctx->video_height;
cmd.context.bg_isp = ctx->bg_isp;
cmd.context.bg_tsp = ctx->bg_tsp;
cmd.context.bg_tcw = ctx->bg_tcw;
cmd.context.bg_depth = ctx->bg_depth;
cmd.context.bg_vertices_size = sizeof(ctx->bg_vertices);
cmd.context.bg_vertices = (const uint8_t *)(intptr_t)sizeof(cmd);
cmd.context.params_size = ctx->size;
cmd.context.params =
(const uint8_t *)(intptr_t)(sizeof(cmd) + sizeof(ctx->bg_vertices));
CHECK_EQ(fwrite(&cmd, sizeof(cmd), 1, writer->file), 1);
CHECK_EQ(fwrite(ctx->bg_vertices, sizeof(ctx->bg_vertices), 1, writer->file),
1);
if (ctx->size) {
CHECK_EQ(fwrite(ctx->params, ctx->size, 1, writer->file), 1);
}
}
void trace_writer_insert_texture(struct trace_writer *writer, union tsp tsp,
union tcw tcw, int frame,
const uint8_t *palette, int palette_size,
const uint8_t *texture, int texture_size) {
struct trace_cmd cmd = {0};
cmd.type = TRACE_CMD_TEXTURE;
cmd.texture.tsp = tsp;
cmd.texture.tcw = tcw;
cmd.texture.frame = frame;
cmd.texture.palette_size = palette_size;
cmd.texture.palette = (const uint8_t *)(intptr_t)sizeof(cmd);
cmd.texture.texture_size = texture_size;
cmd.texture.texture = (const uint8_t *)(intptr_t)(sizeof(cmd) + palette_size);
CHECK_EQ(fwrite(&cmd, sizeof(cmd), 1, writer->file), 1);
if (palette_size) {
CHECK_EQ(fwrite(palette, palette_size, 1, writer->file), 1);
}
if (texture_size) {
CHECK_EQ(fwrite(texture, texture_size, 1, writer->file), 1);
}
}
struct trace_writer *trace_writer_open(const char *filename) {
struct trace_writer *writer = calloc(1, sizeof(struct trace_writer));
writer->file = fopen(filename, "wb");
if (!writer->file) {
trace_writer_close(writer);
return NULL;
}
return writer;
}
/* for commands which mutate global state, the previous state needs to be
tracked in order to support unwinding. To do so, each command is iterated
and tagged with the previous command that it overrides */
static int trace_patch_overrides(struct trace_cmd *cmd) {
while (cmd) {
if (cmd->type == TRACE_CMD_TEXTURE) {
texture_key_t texture_key =
tr_texture_key(cmd->texture.tsp, cmd->texture.tcw);
// walk backwards and see if this texture overrode a previous command
// TODO could cache this information in a map
/* walk backwards and see if this texture overrode a previous command
TODO could cache this information in a map */
struct trace_cmd *prev = cmd->prev;
while (prev) {
@ -95,7 +122,58 @@ static bool trace_patch_overrides(struct trace_cmd *cmd) {
cmd = cmd->next;
}
return true;
return 1;
}
/* commands are written out with null list pointers, and pointers to data
are written out relative to the command itself. Set the list pointers,
and make the data pointers absolute */
static int trace_patch_pointers(void *begin, int size) {
struct trace_cmd *prev_cmd = NULL;
struct trace_cmd *curr_cmd = NULL;
uint8_t *ptr = begin;
uint8_t *end = ptr + size;
while (ptr < end) {
prev_cmd = curr_cmd;
curr_cmd = (struct trace_cmd *)ptr;
/* set prev / next pointers */
if (prev_cmd) {
prev_cmd->next = curr_cmd;
}
curr_cmd->prev = prev_cmd;
curr_cmd->next = NULL;
curr_cmd->override = NULL;
/* patch relative data pointers */
switch (curr_cmd->type) {
case TRACE_CMD_TEXTURE: {
curr_cmd->texture.palette += (intptr_t)ptr;
curr_cmd->texture.texture += (intptr_t)ptr;
ptr += sizeof(*curr_cmd) + curr_cmd->texture.palette_size +
curr_cmd->texture.texture_size;
} break;
case TRACE_CMD_CONTEXT: {
curr_cmd->context.bg_vertices += (intptr_t)ptr;
curr_cmd->context.params += (intptr_t)ptr;
ptr += sizeof(*curr_cmd) + curr_cmd->context.bg_vertices_size +
curr_cmd->context.params_size;
} break;
default:
LOG_INFO("Unexpected trace command type %d", curr_cmd->type);
return 0;
}
}
return 1;
}
void trace_destroy(struct trace *trace) {
free(trace->cmds);
free(trace);
}
struct trace *trace_parse(const char *filename) {
@ -125,80 +203,22 @@ struct trace *trace_parse(const char *filename) {
return NULL;
}
/* count frame span */
{
struct trace_cmd *cmd = trace->cmds;
trace->first_frame = INT_MAX;
trace->last_frame = INT_MIN;
while (cmd) {
if (cmd->type == TRACE_CMD_CONTEXT) {
trace->first_frame = MIN(trace->first_frame, cmd->context.frame);
trace->last_frame = MAX(trace->last_frame, cmd->context.frame);
}
cmd = cmd->next;
}
}
return trace;
}
void trace_destroy(struct trace *trace) {
free(trace->cmds);
free(trace);
}
struct trace_writer *trace_writer_open(const char *filename) {
struct trace_writer *writer = calloc(1, sizeof(struct trace_writer));
writer->file = fopen(filename, "wb");
if (!writer->file) {
trace_writer_close(writer);
return NULL;
}
return writer;
}
void trace_writer_insert_texture(struct trace_writer *writer, union tsp tsp,
union tcw tcw, const uint8_t *palette,
int palette_size, const uint8_t *texture,
int texture_size) {
struct trace_cmd cmd = {0};
cmd.type = TRACE_CMD_TEXTURE;
cmd.texture.tsp = tsp;
cmd.texture.tcw = tcw;
cmd.texture.palette_size = palette_size;
cmd.texture.palette = (const uint8_t *)(intptr_t)sizeof(cmd);
cmd.texture.texture_size = texture_size;
cmd.texture.texture = (const uint8_t *)(intptr_t)(sizeof(cmd) + palette_size);
CHECK_EQ(fwrite(&cmd, sizeof(cmd), 1, writer->file), 1);
if (palette_size) {
CHECK_EQ(fwrite(palette, palette_size, 1, writer->file), 1);
}
if (texture_size) {
CHECK_EQ(fwrite(texture, texture_size, 1, writer->file), 1);
}
}
void trace_writer_render_context(struct trace_writer *writer,
struct tile_ctx *ctx) {
struct trace_cmd cmd = {0};
cmd.type = TRACE_CMD_CONTEXT;
cmd.context.autosort = ctx->autosort;
cmd.context.stride = ctx->stride;
cmd.context.pal_pxl_format = ctx->pal_pxl_format;
cmd.context.video_width = ctx->video_width;
cmd.context.video_height = ctx->video_height;
cmd.context.bg_isp = ctx->bg_isp;
cmd.context.bg_tsp = ctx->bg_tsp;
cmd.context.bg_tcw = ctx->bg_tcw;
cmd.context.bg_depth = ctx->bg_depth;
cmd.context.bg_vertices_size = sizeof(ctx->bg_vertices);
cmd.context.bg_vertices = (const uint8_t *)(intptr_t)sizeof(cmd);
cmd.context.params_size = ctx->size;
cmd.context.params =
(const uint8_t *)(intptr_t)(sizeof(cmd) + sizeof(ctx->bg_vertices));
CHECK_EQ(fwrite(&cmd, sizeof(cmd), 1, writer->file), 1);
CHECK_EQ(fwrite(ctx->bg_vertices, sizeof(ctx->bg_vertices), 1, writer->file),
1);
if (ctx->size) {
CHECK_EQ(fwrite(ctx->params, ctx->size, 1, writer->file), 1);
}
}
void trace_writer_close(struct trace_writer *writer) {
if (writer->file) {
fclose(writer->file);
}
free(writer);
}

View File

@ -13,26 +13,28 @@ enum trace_cmd_type {
struct trace_cmd {
enum trace_cmd_type type;
// set on read
/* set on read */
struct trace_cmd *prev;
struct trace_cmd *next;
struct trace_cmd * override;
// the data pointers in these structs are written out relative to the cmd,
// and patched to absolute pointers on read
/* the data pointers in these structs are written out relative to the cmd,
and patched to absolute pointers on read */
union {
struct {
union tsp tsp;
union tcw tcw;
int32_t frame;
uint32_t palette_size;
const uint8_t *palette;
uint32_t texture_size;
const uint8_t *texture;
} texture;
// slimmed down version of the tile_ctx structure, will need to be in
// sync
/* slimmed down version of the tile_ctx structure, will need to be in
sync */
struct {
int32_t frame;
int8_t autosort;
uint32_t stride;
uint32_t pal_pxl_format;
@ -52,24 +54,26 @@ struct trace_cmd {
struct trace {
struct trace_cmd *cmds;
int first_frame;
int last_frame;
};
struct trace_writer {
FILE *file;
};
extern void get_next_trace_filename(char *filename, size_t size);
void get_next_trace_filename(char *filename, size_t size);
struct trace *trace_parse(const char *filename);
void trace_destroy(struct trace *trace);
struct trace_writer *trace_writer_open(const char *filename);
void trace_writer_insert_texture(struct trace_writer *writer, union tsp tsp,
union tcw tcw, const uint8_t *palette,
int palette_size, const uint8_t *texture,
int texture_size);
void trace_writer_close(struct trace_writer *writer);
void trace_writer_render_context(struct trace_writer *writer,
struct tile_ctx *ctx);
void trace_writer_close(struct trace_writer *writer);
void trace_writer_insert_texture(struct trace_writer *writer, union tsp tsp,
union tcw tcw, int frame,
const uint8_t *palette, int palette_size,
const uint8_t *texture, int texture_size);
struct trace_writer *trace_writer_open(const char *filename);
void trace_destroy(struct trace *trace);
struct trace *trace_parse(const char *filename);
#endif

View File

@ -96,6 +96,8 @@ static void win_debug_menu(struct window *win) {
ctx->style.window.padding = nk_vec2(0.0f, 0.0f);
if (nk_begin(ctx, "debug menu", bounds, NK_WINDOW_NO_SCROLLBAR)) {
nk_window_set_bounds(ctx, bounds);
nk_menubar_begin(ctx);
nk_layout_row_begin(ctx, NK_STATIC, DEBUG_MENU_HEIGHT,
MAX_WINDOW_LISTENERS + 2);
@ -959,7 +961,6 @@ struct window *win_create() {
win->width = DEFAULT_WIDTH;
win->height = DEFAULT_HEIGHT;
win->debug_menu = 1;
/* initialize window */
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) {