mirror of https://github.com/inolen/redream.git
added retrace tool
This commit is contained in:
parent
d3118a9ae8
commit
e914e0df48
|
@ -167,6 +167,7 @@ set(REDREAM_SOURCES
|
|||
src/core/profiler.cc
|
||||
src/core/ringbuf.cc
|
||||
src/core/rb_tree.c
|
||||
src/core/sort.c
|
||||
src/core/string.c
|
||||
src/hw/aica/aica.c
|
||||
src/hw/arm7/arm7.c
|
||||
|
@ -335,6 +336,16 @@ target_link_libraries(recc ${REDREAM_LIBS})
|
|||
target_compile_definitions(recc PRIVATE ${REDREAM_DEFS} MICROPROFILE_ENABLED=0)
|
||||
target_compile_options(recc PRIVATE ${REDREAM_FLAGS})
|
||||
|
||||
add_executable(retrace $<TARGET_OBJECTS:relib>
|
||||
src/null_host.c
|
||||
tools/retrace/depth.c
|
||||
tools/retrace/main.c)
|
||||
target_include_directories(retrace SYSTEM PUBLIC ${REDREAM_INCLUDE_DIRS})
|
||||
target_include_directories(retrace PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||
target_link_libraries(retrace ${REDREAM_LIBS})
|
||||
target_compile_definitions(retrace PRIVATE ${REDREAM_DEFS} MICROPROFILE_ENABLED=0)
|
||||
target_compile_options(retrace PRIVATE ${REDREAM_FLAGS})
|
||||
|
||||
endif()
|
||||
|
||||
#--------------------------------------------------
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "core/sort.h"
|
||||
|
||||
static void merge(void *in, void *out, size_t size, int l, int m, int r,
|
||||
sort_cmp cmp) {
|
||||
int i = l;
|
||||
int j = m;
|
||||
int k = l;
|
||||
|
||||
while (k < r) {
|
||||
if ((i < m && cmp(in + i * size, in + j * size)) || j >= r) {
|
||||
memcpy(out + k * size, in + i * size, size);
|
||||
k++;
|
||||
i++;
|
||||
} else {
|
||||
memcpy(out + k * size, in + j * size, size);
|
||||
k++;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void mergesort_r(void *in, void *out, size_t size, int l, int r,
|
||||
sort_cmp cmp) {
|
||||
if ((r - l) < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
int m = (l + r) / 2;
|
||||
mergesort_r(out, in, size, l, m, cmp);
|
||||
mergesort_r(out, in, size, m, r, cmp);
|
||||
merge(in, out, size, l, m, r, cmp);
|
||||
}
|
||||
|
||||
void mergesort_fixed(void *data, void *tmp, int num, size_t size,
|
||||
sort_cmp cmp) {
|
||||
memcpy(tmp, data, num * size);
|
||||
mergesort_r(tmp, data, size, 0, num, cmp);
|
||||
}
|
||||
|
||||
void mergesort(void *data, int num, size_t size, sort_cmp cmp) {
|
||||
void *tmp = malloc(num * size);
|
||||
mergesort_fixed(data, tmp, num, size, cmp);
|
||||
free(tmp);
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef SORT_H
|
||||
#define SORT_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* returns if a is <= b */
|
||||
typedef int (*sort_cmp)(const void *, const void *);
|
||||
|
||||
void mergesort_fixed(void *data, void *tmp, int num, size_t size, sort_cmp cmp);
|
||||
void mergesort(void *data, int num, size_t size, sort_cmp cmp);
|
||||
|
||||
#endif
|
|
@ -175,6 +175,24 @@ void trace_destroy(struct trace *trace) {
|
|||
free(trace);
|
||||
}
|
||||
|
||||
void trace_copy_context(const struct trace_cmd *cmd, struct tile_context *ctx) {
|
||||
CHECK_EQ(cmd->type, TRACE_CMD_CONTEXT);
|
||||
|
||||
ctx->autosort = cmd->context.autosort;
|
||||
ctx->stride = cmd->context.stride;
|
||||
ctx->pal_pxl_format = cmd->context.pal_pxl_format;
|
||||
ctx->bg_isp = cmd->context.bg_isp;
|
||||
ctx->bg_tsp = cmd->context.bg_tsp;
|
||||
ctx->bg_tcw = cmd->context.bg_tcw;
|
||||
ctx->bg_depth = cmd->context.bg_depth;
|
||||
ctx->video_width = cmd->context.video_width;
|
||||
ctx->video_height = cmd->context.video_height;
|
||||
memcpy(ctx->bg_vertices, cmd->context.bg_vertices,
|
||||
cmd->context.bg_vertices_size);
|
||||
memcpy(ctx->params, cmd->context.params, cmd->context.params_size);
|
||||
ctx->size = cmd->context.params_size;
|
||||
}
|
||||
|
||||
struct trace *trace_parse(const char *filename) {
|
||||
struct trace *trace = calloc(1, sizeof(struct trace));
|
||||
|
||||
|
|
|
@ -63,16 +63,17 @@ struct trace_writer {
|
|||
|
||||
void get_next_trace_filename(char *filename, size_t size);
|
||||
|
||||
void trace_writer_close(struct trace_writer *writer);
|
||||
void trace_writer_render_context(struct trace_writer *writer,
|
||||
struct tile_context *ctx);
|
||||
struct trace *trace_parse(const char *filename);
|
||||
void trace_copy_context(const struct trace_cmd *cmd, struct tile_context *ctx);
|
||||
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, unsigned 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);
|
||||
void trace_writer_render_context(struct trace_writer *writer,
|
||||
struct tile_context *ctx);
|
||||
void trace_writer_close(struct trace_writer *writer);
|
||||
|
||||
#endif
|
||||
|
|
23
src/tracer.c
23
src/tracer.c
|
@ -149,25 +149,6 @@ static void tracer_add_texture(struct tracer *tracer,
|
|||
tex->palette_size = cmd->texture.palette_size;
|
||||
}
|
||||
|
||||
static void tracer_copy_context(const struct trace_cmd *cmd,
|
||||
struct tile_context *ctx) {
|
||||
CHECK_EQ(cmd->type, TRACE_CMD_CONTEXT);
|
||||
|
||||
ctx->autosort = cmd->context.autosort;
|
||||
ctx->stride = cmd->context.stride;
|
||||
ctx->pal_pxl_format = cmd->context.pal_pxl_format;
|
||||
ctx->bg_isp = cmd->context.bg_isp;
|
||||
ctx->bg_tsp = cmd->context.bg_tsp;
|
||||
ctx->bg_tcw = cmd->context.bg_tcw;
|
||||
ctx->bg_depth = cmd->context.bg_depth;
|
||||
ctx->video_width = cmd->context.video_width;
|
||||
ctx->video_height = cmd->context.video_height;
|
||||
memcpy(ctx->bg_vertices, cmd->context.bg_vertices,
|
||||
cmd->context.bg_vertices_size);
|
||||
memcpy(ctx->params, cmd->context.params, cmd->context.params_size);
|
||||
ctx->size = cmd->context.params_size;
|
||||
}
|
||||
|
||||
static void tracer_prev_param(struct tracer *tracer) {
|
||||
int i = tracer->current_param;
|
||||
|
||||
|
@ -225,7 +206,7 @@ static void tracer_prev_context(struct tracer *tracer) {
|
|||
tracer->current_cmd = prev;
|
||||
tracer->current_param = -1;
|
||||
tracer->scroll_to_param = 0;
|
||||
tracer_copy_context(tracer->current_cmd, &tracer->ctx);
|
||||
trace_copy_context(tracer->current_cmd, &tracer->ctx);
|
||||
tr_convert_context(tracer->r, tracer, &tracer_find_texture, &tracer->ctx,
|
||||
&tracer->rc);
|
||||
}
|
||||
|
@ -264,7 +245,7 @@ static void tracer_next_context(struct tracer *tracer) {
|
|||
tracer->current_cmd = next;
|
||||
tracer->current_param = -1;
|
||||
tracer->scroll_to_param = 0;
|
||||
tracer_copy_context(tracer->current_cmd, &tracer->ctx);
|
||||
trace_copy_context(tracer->current_cmd, &tracer->ctx);
|
||||
tr_convert_context(tracer->r, tracer, &tracer_find_texture, &tracer->ctx,
|
||||
&tracer->rc);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include "core/assert.h"
|
||||
#include "core/sort.h"
|
||||
#include "hw/pvr/tr.h"
|
||||
#include "hw/pvr/trace.h"
|
||||
|
||||
struct depth_entry {
|
||||
/* vertex index */
|
||||
int n;
|
||||
|
||||
/* depth buffer value */
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} d;
|
||||
};
|
||||
|
||||
typedef void (*depth_cb)(float, float, float, struct depth_entry *);
|
||||
|
||||
struct test {
|
||||
const char *name;
|
||||
depth_cb depth;
|
||||
sort_cmp cmp;
|
||||
int match;
|
||||
int total;
|
||||
};
|
||||
|
||||
static struct tr_texture *find_texture(void *userdata, union tsp tsp,
|
||||
union tcw tcw) {
|
||||
/* return a non-zero handle so it doesn't try to create a texture with
|
||||
the render backend (which is NULL) */
|
||||
static struct tr_texture tex;
|
||||
tex.handle = 1;
|
||||
return &tex;
|
||||
}
|
||||
|
||||
static int depth_cmp(const void *a, const void *b) {
|
||||
const struct depth_entry *ea = (const struct depth_entry *)a;
|
||||
const struct depth_entry *eb = (const struct depth_entry *)b;
|
||||
return ea->d.i <= eb->d.i;
|
||||
}
|
||||
|
||||
static int depth_cmpf(const void *a, const void *b) {
|
||||
const struct depth_entry *ea = (const struct depth_entry *)a;
|
||||
const struct depth_entry *eb = (const struct depth_entry *)b;
|
||||
return ea->d.f <= eb->d.f;
|
||||
}
|
||||
|
||||
static void test_context(struct trace_cmd *cmd, struct test *tests,
|
||||
int num_tests) {
|
||||
CHECK_EQ(cmd->type, TRACE_CMD_CONTEXT);
|
||||
|
||||
struct tile_context *ctx = calloc(1, sizeof(struct tile_context));
|
||||
struct tr_context *rc = calloc(1, sizeof(struct tr_context));
|
||||
|
||||
/* parse the context */
|
||||
trace_copy_context(cmd, ctx);
|
||||
tr_convert_context(NULL, NULL, &find_texture, ctx, rc);
|
||||
|
||||
/* sort each vertex by the original w */
|
||||
struct depth_entry *original =
|
||||
calloc(rc->num_verts, sizeof(struct depth_entry));
|
||||
float minw = FLT_MAX;
|
||||
float maxw = -FLT_MAX;
|
||||
|
||||
for (int i = 0; i < rc->num_verts; i++) {
|
||||
struct ta_vertex *vert = &rc->verts[i];
|
||||
struct depth_entry *entry = &original[i];
|
||||
entry->n = i;
|
||||
entry->d.f = 1.0f / vert->xyz[2];
|
||||
|
||||
minw = MIN(minw, entry->d.f);
|
||||
maxw = MAX(maxw, entry->d.f);
|
||||
}
|
||||
|
||||
mergesort(original, rc->num_verts, sizeof(struct depth_entry), &depth_cmpf);
|
||||
|
||||
for (int i = 0; i < num_tests; i++) {
|
||||
struct test *test = &tests[i];
|
||||
|
||||
/* calculate the depth for each vertex using the test's depth function */
|
||||
struct depth_entry *tmp = calloc(rc->num_verts, sizeof(struct depth_entry));
|
||||
|
||||
for (int j = 0; j < rc->num_verts; j++) {
|
||||
struct ta_vertex *vert = &rc->verts[j];
|
||||
struct depth_entry *entry = &tmp[j];
|
||||
entry->n = j;
|
||||
test->depth(1.0f / vert->xyz[2], minw, maxw, entry);
|
||||
}
|
||||
|
||||
/* sort the vertices based on the depth value */
|
||||
mergesort(tmp, rc->num_verts, sizeof(struct depth_entry), test->cmp);
|
||||
|
||||
/* compare sorted results with original results */
|
||||
for (int j = 0; j < rc->num_verts; j++) {
|
||||
if (original[j].n == tmp[j].n) {
|
||||
test->match++;
|
||||
}
|
||||
}
|
||||
|
||||
test->total += rc->num_verts;
|
||||
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
free(original);
|
||||
free(rc);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
static void test_flt(float w, float minw, float maxw,
|
||||
struct depth_entry *entry) {
|
||||
entry->d.f = (w - minw) / (maxw - minw);
|
||||
}
|
||||
|
||||
static void test_int(float w, float minw, float maxw,
|
||||
struct depth_entry *entry) {
|
||||
entry->d.i = ((w - minw) / (maxw - minw)) * ((1 << 24) - 1);
|
||||
}
|
||||
|
||||
static void test_log2(float w, float minw, float maxw,
|
||||
struct depth_entry *entry) {
|
||||
entry->d.i = (log2(1.0f + w - minw) / log2(maxw - minw)) * ((1 << 24) - 1);
|
||||
}
|
||||
|
||||
static void test_log2_fixed(float w, float minw, float maxw,
|
||||
struct depth_entry *entry) {
|
||||
entry->d.i = (log2(1.0f + w) / 17.0f) * ((1 << 24) - 1);
|
||||
}
|
||||
|
||||
int cmd_depth(int argc, const char **argv) {
|
||||
if (argc < 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *filename = argv[0];
|
||||
struct trace *trace = trace_parse(filename);
|
||||
|
||||
struct test tests[] = {
|
||||
{"32-bit float", &test_flt, &depth_cmpf, 0, 0},
|
||||
{"24-bit int", &test_int, &depth_cmp, 0, 0},
|
||||
{"24-bit int using log2", &test_log2, &depth_cmp, 0, 0},
|
||||
{"24-bit int using log2 w/ fixed max", &test_log2_fixed, &depth_cmp, 0,
|
||||
0},
|
||||
};
|
||||
int num_tests = array_size(tests);
|
||||
|
||||
/* check each context in the trace */
|
||||
struct trace_cmd *next = trace->cmds;
|
||||
while (next) {
|
||||
if (next->type == TRACE_CMD_CONTEXT) {
|
||||
test_context(next, tests, num_tests);
|
||||
break;
|
||||
}
|
||||
next = next->next;
|
||||
}
|
||||
|
||||
trace_destroy(trace);
|
||||
|
||||
/* print results */
|
||||
LOG_INFO("===-----------------------------------------------------===");
|
||||
LOG_INFO("depth test results");
|
||||
LOG_INFO("===-----------------------------------------------------===");
|
||||
LOG_INFO("");
|
||||
|
||||
int max_name_length = 0;
|
||||
for (int i = 0; i < num_tests; i++) {
|
||||
struct test *test = &tests[i];
|
||||
int l = (int)strlen(test->name);
|
||||
max_name_length = MAX(max_name_length, l);
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_tests; i++) {
|
||||
struct test *test = &tests[i];
|
||||
LOG_INFO("%-*s %f%%", max_name_length, test->name,
|
||||
((float)test->match / test->total) * 100.0f);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#include "core/log.h"
|
||||
|
||||
extern int cmd_depth(int argc, const char **argv);
|
||||
|
||||
static void print_help() {
|
||||
LOG_INFO("usage: retrace <command> [<args> ...]");
|
||||
LOG_INFO("the available commands are:");
|
||||
LOG_INFO(" depth compare depth function accuracies");
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
int res = 0;
|
||||
|
||||
if (argc >= 2) {
|
||||
const char *cmd = argv[1];
|
||||
|
||||
if (!strcmp(cmd, "depth")) {
|
||||
res = cmd_depth(argc - 2, argv + 2);
|
||||
}
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
print_help();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
Loading…
Reference in New Issue