mirror of https://github.com/inolen/redream.git
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:
parent
adc8a82a5a
commit
92c6baf455
|
@ -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;
|
||||
}
|
||||
|
|
336
src/emu/tracer.c
336
src/emu/tracer.c
|
@ -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, ¶m_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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -442,6 +442,7 @@ struct tile_ctx {
|
|||
uint32_t addr;
|
||||
|
||||
/* pvr / ta state */
|
||||
int frame;
|
||||
bool autosort;
|
||||
int stride;
|
||||
int pal_pxl_format;
|
||||
|
|
213
src/hw/pvr/tr.c
213
src/hw/pvr/tr.c
|
@ -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++;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue