moved ta rendering into emulator

This commit is contained in:
Anthony Pesch 2016-11-26 12:20:22 -08:00
parent cd0f94c205
commit 646b108bb7
10 changed files with 291 additions and 257 deletions

View File

@ -5,6 +5,8 @@
#include "hw/gdrom/gdrom.h"
#include "hw/memory.h"
#include "hw/pvr/pvr.h"
#include "hw/pvr/ta.h"
#include "hw/pvr/tr.h"
#include "hw/scheduler.h"
#include "hw/sh4/sh4.h"
#include "sys/thread.h"
@ -19,6 +21,13 @@ struct emu {
int running;
int throttled;
/* render state */
struct tr *tr;
struct render_context render_ctx;
struct surface surfs[TA_MAX_SURFS];
struct vertex verts[TA_MAX_VERTS];
int sorted_surfs[TA_MAX_SURFS];
/* fps */
int fps;
int64_t last_frame_time;
@ -69,6 +78,25 @@ static bool emu_launch_gdi(struct emu *emu, const char *path) {
static void emu_paint(void *data) {
struct emu *emu = 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)) {
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);
ta_unlock_pending_context(emu->dc->ta);
}
tr_render_context(emu->tr, render_ctx);
/* track fps */
int64_t now = time_nanoseconds();
int64_t next_time = emu->last_frame_time + NS_PER_SEC;
@ -81,16 +109,20 @@ static void emu_paint(void *data) {
emu->num_frames = 0;
}
dc_paint(emu->dc);
PROF_FLIP();
}
static void emu_debug_menu(void *data, struct nk_context *ctx) {
struct emu *emu = data;
nk_layout_row_push(ctx, 70.0f);
/* set status string */
char status[128];
snprintf(status, sizeof(status), "%3d FPS %3d VBS %4d MIPS", emu->fps,
emu->dc->pvr->vbs, emu->dc->sh4->mips);
win_set_status(emu->window, status);
/* add drop down menus */
nk_layout_row_push(ctx, 70.0f);
if (nk_menu_begin_label(ctx, "EMULATOR", NK_TEXT_LEFT,
nk_vec2(140.0f, 200.0f))) {
nk_layout_row_dynamic(ctx, DEBUG_MENU_HEIGHT, 1);
@ -98,11 +130,6 @@ static void emu_debug_menu(void *data, struct nk_context *ctx) {
nk_menu_end(ctx);
}
char status[128];
snprintf(status, sizeof(status), "%3d FPS %3d VBS %4d MIPS", emu->fps,
emu->dc->pvr->vbs, emu->dc->sh4->mips);
win_set_status(emu->window, status);
dc_debug_menu(emu->dc, ctx);
}
@ -149,7 +176,7 @@ static void *emu_core_thread(void *data) {
}
void emu_run(struct emu *emu, const char *path) {
emu->dc = dc_create(emu->window->video);
emu->dc = dc_create();
if (!emu->dc) {
return;
@ -165,6 +192,9 @@ void emu_run(struct emu *emu, const char *path) {
}
}
/* create tile renderer */
emu->tr = tr_create(emu->window->video, ta_texture_provider(emu->dc->ta));
/* start core emulator thread */
thread_t core_thread;
emu->running = 1;
@ -196,6 +226,10 @@ struct emu *emu_create(struct window *window) {
void emu_destroy(struct emu *emu) {
win_remove_listener(emu->window, &emu->listener);
if (emu->tr) {
tr_destroy(emu->tr);
}
if (emu->dc) {
dc_destroy(emu->dc);
}

View File

@ -85,7 +85,7 @@ struct tracer {
int num_contexts;
// render state
struct render_ctx rctx;
struct render_context rctx;
struct surface surfs[TA_MAX_SURFS];
struct vertex verts[TA_MAX_VERTS];
int sorted_surfs[TA_MAX_SURFS];

View File

@ -76,14 +76,6 @@ void dc_tick(struct dreamcast *dc, int64_t ns) {
}
}
void dc_paint(struct dreamcast *dc) {
list_for_each_entry(dev, &dc->devices, struct device, it) {
if (dev->window_if && dev->window_if->paint) {
dev->window_if->paint(dev);
}
}
}
void dc_debug_menu(struct dreamcast *dc, struct nk_context *ctx) {
list_for_each_entry(dev, &dc->devices, struct device, it) {
if (dev->window_if && dev->window_if->debug_menu) {
@ -127,10 +119,8 @@ void dc_destroy_memory_interface(struct memory_interface *memory) {
}
struct window_interface *dc_create_window_interface(
device_paint_cb paint, device_debug_menu_cb debug_menu,
device_keydown_cb keydown) {
device_debug_menu_cb debug_menu, device_keydown_cb keydown) {
struct window_interface *window = calloc(1, sizeof(struct window_interface));
window->paint = paint;
window->debug_menu = debug_menu;
window->keydown = keydown;
return window;
@ -169,7 +159,7 @@ void dc_destroy_device(struct device *dev) {
free(dev);
}
struct dreamcast *dc_create(struct video_backend *video) {
struct dreamcast *dc_create() {
struct dreamcast *dc = calloc(1, sizeof(struct dreamcast));
dc->debugger = OPTION_gdb ? debugger_create(dc) : NULL;
@ -184,7 +174,7 @@ struct dreamcast *dc_create(struct video_backend *video) {
dc->holly = holly_create(dc);
dc->maple = maple_create(dc);
dc->pvr = pvr_create(dc);
dc->ta = ta_create(dc, video);
dc->ta = ta_create(dc);
if (!dc_init(dc)) {
dc_destroy(dc);

View File

@ -24,7 +24,6 @@ struct pvr;
struct scheduler;
struct sh4;
struct ta;
struct video_backend;
//
// register callbacks
@ -86,12 +85,10 @@ struct memory_interface {
};
// window interface
typedef void (*device_paint_cb)(struct device *);
typedef void (*device_debug_menu_cb)(struct device *, struct nk_context *);
typedef void (*device_keydown_cb)(struct device *, enum keycode, int16_t);
struct window_interface {
device_paint_cb paint;
device_debug_menu_cb debug_menu;
device_keydown_cb keydown;
};
@ -153,7 +150,6 @@ bool dc_init(struct dreamcast *dc);
void dc_suspend(struct dreamcast *dc);
void dc_resume(struct dreamcast *dc);
void dc_tick(struct dreamcast *dc, int64_t ns);
void dc_paint(struct dreamcast *dc);
void dc_debug_menu(struct dreamcast *dc, struct nk_context *ctx);
void dc_keydown(struct dreamcast *dc, enum keycode code, int16_t value);
@ -166,8 +162,7 @@ struct memory_interface *dc_create_memory_interface(struct dreamcast *dc,
void dc_destroy_memory_interface(struct memory_interface *memory);
struct window_interface *dc_create_window_interface(
device_paint_cb paint, device_debug_menu_cb debug_menu,
device_keydown_cb keydown);
device_debug_menu_cb debug_menu, device_keydown_cb keydown);
void dc_destroy_window_interface(struct window_interface *window);
void *dc_create_device(struct dreamcast *dc, size_t size, const char *name,
@ -175,7 +170,7 @@ void *dc_create_device(struct dreamcast *dc, size_t size, const char *name,
struct device *dc_get_device(struct dreamcast *dc, const char *name);
void dc_destroy_device(struct device *dev);
struct dreamcast *dc_create(struct video_backend *video);
struct dreamcast *dc_create();
void dc_destroy(struct dreamcast *dc);
#endif

View File

@ -36,7 +36,7 @@ int maple_handle_command(struct maple *mp, int port, struct maple_frame *frame,
struct maple *maple_create(struct dreamcast *dc) {
struct maple *mp =
dc_create_device(dc, sizeof(struct maple), "maple", &maple_init);
mp->window_if = dc_create_window_interface(NULL, NULL, &maple_keydown);
mp->window_if = dc_create_window_interface(NULL, &maple_keydown);
mp->devices[0] = controller_create();

View File

@ -13,7 +13,6 @@
#include "sys/filesystem.h"
#include "sys/thread.h"
#include "ui/nuklear.h"
#include "video/backend.h"
#define TA_MAX_CONTEXTS 8
#define TA_YUV420_MACROBLOCK_SIZE 384
@ -32,7 +31,6 @@ struct ta_texture_entry {
struct ta {
struct device;
struct texture_provider provider;
struct tr *tr;
uint8_t *video_ram;
uint8_t *palette_ram;
@ -65,19 +63,11 @@ struct ta {
mutex_t pending_mutex;
struct tile_ctx *pending_context;
// last parsed pending context
struct render_ctx render_context;
// buffers used by the tile contexts. allocating here instead of inside each
// tile_ctx to avoid blowing the stack when a tile_ctx is needed temporarily
// on the stack for searching
uint8_t params[TA_MAX_CONTEXTS * TA_MAX_PARAMS];
// buffers used by render context
struct surface surfs[TA_MAX_SURFS];
struct vertex verts[TA_MAX_VERTS];
int sorted_surfs[TA_MAX_SURFS];
// debug info
int frame;
int frames_skipped;
@ -862,31 +852,6 @@ static void ta_toggle_tracing(struct ta *ta) {
}
}
static void ta_paint(struct device *dev) {
struct ta *ta = (struct ta *)dev;
struct render_ctx *rctx = &ta->render_context;
mutex_lock(ta->pending_mutex);
if (ta->pending_context) {
rctx->surfs = ta->surfs;
rctx->surfs_size = array_size(ta->surfs);
rctx->verts = ta->verts;
rctx->verts_size = array_size(ta->verts);
rctx->sorted_surfs = ta->sorted_surfs;
rctx->sorted_surfs_size = array_size(ta->sorted_surfs);
tr_parse_context(ta->tr, ta->pending_context, ta->frame, rctx);
ta_free_context(ta, ta->pending_context);
ta->pending_context = NULL;
}
mutex_unlock(ta->pending_mutex);
tr_render_context(ta->tr, rctx);
}
static void ta_debug_menu(struct device *dev, struct nk_context *ctx) {
struct ta *ta = (struct ta *)dev;
@ -949,21 +914,44 @@ void ta_build_tables() {
}
}
void ta_unlock_pending_context(struct ta *ta) {
ta_free_context(ta, ta->pending_context);
ta->pending_context = NULL;
mutex_unlock(ta->pending_mutex);
}
int ta_lock_pending_context(struct ta *ta, struct tile_ctx **pending_ctx,
int *pending_frame) {
mutex_lock(ta->pending_mutex);
if (!ta->pending_context) {
mutex_unlock(ta->pending_mutex);
return 0;
}
*pending_ctx = ta->pending_context;
*pending_frame = ta->frame;
return 1;
}
struct texture_provider *ta_texture_provider(struct ta *ta) {
return &ta->provider;
}
void ta_destroy(struct ta *ta) {
mutex_destroy(ta->pending_mutex);
tr_destroy(ta->tr);
dc_destroy_window_interface(ta->window_if);
dc_destroy_device((struct device *)ta);
}
struct ta *ta_create(struct dreamcast *dc, struct video_backend *video) {
struct ta *ta_create(struct dreamcast *dc) {
ta_build_tables();
struct ta *ta = dc_create_device(dc, sizeof(struct ta), "ta", &ta_init);
ta->window_if = dc_create_window_interface(&ta_paint, &ta_debug_menu, NULL);
ta->window_if = dc_create_window_interface(&ta_debug_menu, NULL);
ta->provider =
(struct texture_provider){ta, &ta_texture_provider_find_texture};
ta->tr = tr_create(video, &ta->provider);
ta->pending_mutex = mutex_create();
return ta;

View File

@ -5,7 +5,7 @@
#include "hw/pvr/ta_types.h"
struct dreamcast;
struct video_backend;
struct texture_provider;
extern int g_param_sizes[0x100 * TA_NUM_PARAMS * TA_NUM_VERT_TYPES];
extern int g_poly_types[0x100 * TA_NUM_PARAMS * TA_NUM_LISTS];
@ -30,9 +30,14 @@ struct ta;
void ta_build_tables();
void ta_destroy(struct ta *ta);
struct ta *ta_create(struct dreamcast *dc, struct video_backend *video);
AM_DECLARE(ta_fifo_map);
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);
void ta_unlock_pending_context(struct ta *ta);
#endif

View File

@ -11,7 +11,7 @@ struct tr {
struct video_backend *video;
struct texture_provider *provider;
// current global state
/* current global state */
const union poly_param *last_poly;
const union vert_param *last_vertex;
int list_type;
@ -22,47 +22,47 @@ struct tr {
};
static int compressed_mipmap_offsets[] = {
0x00006, // 8 x 8
0x00016, // 16 x 16
0x00056, // 32 x 32
0x00156, // 64 x 64
0x00556, // 128 x 128
0x01556, // 256 x 256
0x05556, // 512 x 512
0x15556, // 1024 x 1024
0x00006, /* 8 x 8 */
0x00016, /* 16 x 16 */
0x00056, /* 32 x 32 */
0x00156, /* 64 x 64 */
0x00556, /* 128 x 128 */
0x01556, /* 256 x 256 */
0x05556, /* 512 x 512 */
0x15556, /* 1024 x 1024 */
};
static int paletted_4bpp_mipmap_offsets[] = {
0x0000c, // 8 x 8
0x0002c, // 16 x 16
0x000ac, // 32 x 32
0x002ac, // 64 x 64
0x00aac, // 128 x 128
0x02aac, // 256 x 256
0x0aaac, // 512 x 512
0x2aaac, // 1024 x 1024
0x0000c, /* 8 x 8 */
0x0002c, /* 16 x 16 */
0x000ac, /* 32 x 32 */
0x002ac, /* 64 x 64 */
0x00aac, /* 128 x 128 */
0x02aac, /* 256 x 256 */
0x0aaac, /* 512 x 512 */
0x2aaac, /* 1024 x 1024 */
};
static int paletted_8bpp_mipmap_offsets[] = {
0x00018, // 8 x 8
0x00058, // 16 x 16
0x00158, // 32 x 32
0x00558, // 64 x 64
0x01558, // 128 x 128
0x05558, // 256 x 256
0x15558, // 512 x 512
0x55558, // 1024 x 1024
0x00018, /* 8 x 8 */
0x00058, /* 16 x 16 */
0x00158, /* 32 x 32 */
0x00558, /* 64 x 64 */
0x01558, /* 128 x 128 */
0x05558, /* 256 x 256 */
0x15558, /* 512 x 512 */
0x55558, /* 1024 x 1024 */
};
static int nonpaletted_mipmap_offsets[] = {
0x00030, // 8 x 8
0x000b0, // 16 x 16
0x002b0, // 32 x 32
0x00ab0, // 64 x 64
0x02ab0, // 128 x 128
0x0aab0, // 256 x 256
0x2aab0, // 512 x 512
0xaaab0, // 1024 x 1024
0x00030, /* 8 x 8 */
0x000b0, /* 16 x 16 */
0x002b0, /* 32 x 32 */
0x00ab0, /* 64 x 64 */
0x02ab0, /* 128 x 128 */
0x0aab0, /* 256 x 256 */
0x2aab0, /* 512 x 512 */
0xaaab0, /* 1024 x 1024 */
};
static inline enum depth_func translate_depth_func(uint32_t depth_func) {
@ -119,28 +119,33 @@ 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,
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 texture generation
/*
* 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 texture generation
*/
struct texture_entry *entry =
tr->provider->find_texture(tr->provider->data, tsp, tcw);
CHECK_NOTNULL(entry);
// if there's a non-dirty handle, go ahead and return it
/* if there's a non-dirty handle, return it */
if (entry->handle && !entry->dirty) {
return entry->handle;
}
// if there's a dirty handle, destroy it before creating the new one
/* if there's a dirty handle, destroy it before creating the new one */
if (entry->handle && entry->dirty) {
video_destroy_texture(tr->video, entry->handle);
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
/*
* 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];
@ -149,13 +154,15 @@ static texture_handle_t tr_demand_texture(struct tr *tr,
const uint8_t *input = texture;
const uint8_t *output = texture;
// textures are either twiddled and vq compressed, twiddled and uncompressed
// or planar
/*
* textures are either twiddled and vq compressed, twiddled and uncompressed
* or planar
*/
bool twiddled = !tcw.scan_order;
bool compressed = tcw.vq_compressed;
bool mip_mapped = !tcw.scan_order && tcw.mip_mapped;
// get texture dimensions
/* get texture dimensions */
int width = 8 << tsp.texture_u_size;
int height = mip_mapped ? width : 8 << tsp.texture_v_size;
int stride = width;
@ -163,12 +170,16 @@ static texture_handle_t tr_demand_texture(struct tr *tr,
stride = ctx->stride;
}
// mipmap textures contain data for 1 x 1 up to width x height. skip to the
// highest res texture and let the renderer backend generate its own mipmaps
/*
* mipmap textures contain data for 1 x 1 up to width x height. skip to the
* highest res texture and let the renderer backend generate its own mipmaps
*/
if (mip_mapped) {
if (compressed) {
// for vq compressed textures the offset is only for the index data, the
// codebook is the same for all levels
/*
* for vq compressed textures the offset is only for the index data, the
* codebook is the same for all levels
*/
input += compressed_mipmap_offsets[tsp.texture_u_size];
} else if (tcw.pixel_format == TA_PIXEL_4BPP) {
input += paletted_4bpp_mipmap_offsets[tsp.texture_u_size];
@ -179,7 +190,7 @@ static texture_handle_t tr_demand_texture(struct tr *tr,
}
}
// used by vq compressed textures
/* used by vq compressed textures */
static const int codebook_size = 256 * 8;
const uint8_t *codebook = texture;
const uint8_t *index = input + codebook_size;
@ -289,7 +300,7 @@ static texture_handle_t tr_demand_texture(struct tr *tr,
break;
}
// ignore trilinear filtering for now
/* ignore trilinear filtering for now */
enum filter_mode filter =
tsp.filter_mode == 0 ? FILTER_NEAREST : FILTER_BILINEAR;
enum wrap_mode wrap_u =
@ -314,9 +325,8 @@ static texture_handle_t tr_demand_texture(struct tr *tr,
return entry->handle;
}
static struct surface *tr_alloc_surf(struct tr *tr, struct render_ctx *rctx,
static struct surface *tr_alloc_surf(struct tr *tr, struct render_context *rctx,
bool copy_from_prev) {
// either reset the surface state, or copy the state from the previous surface
CHECK_LT(rctx->num_surfs, rctx->surfs_size);
int id = rctx->num_surfs++;
struct surface *surf = &rctx->surfs[id];
@ -327,48 +337,52 @@ static struct surface *tr_alloc_surf(struct tr *tr, struct render_ctx *rctx,
memset(surf, 0, sizeof(*surf));
}
// star verts at the end
/* start verts at the end */
surf->first_vert = rctx->num_verts;
surf->num_verts = 0;
// default sort the surface
/* default sort the surface */
rctx->sorted_surfs[id] = id;
return surf;
}
static struct vertex *tr_alloc_vert(struct tr *tr, struct render_ctx *rctx) {
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];
memset(v, 0, sizeof(*v));
// update vertex count on the current surface
/* update vertex count on the current surface */
struct surface *surf = &rctx->surfs[rctx->num_surfs - 1];
surf->num_verts++;
return v;
}
static void tr_discard_incomplete_surf(struct tr *tr, struct render_ctx *rctx) {
// free up the last surface if it wasn't finished
static void tr_discard_incomplete_surf(struct tr *tr,
struct render_context *rctx) {
/* 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--;
}
}
// FIXME we could offload a lot of this to the GPU, generating shaders
// for different combinations of ISP/union tsp parameters once the logic is
// ironed out
// FIXME honor use alpha
// FIXME honor ignore tex alpha
/*
* TODO
* offload thiis to the GPU, generating shader for different combinations of
* ISP/TSP parameters once the logic is ironed out
*/
/* FIXME honor use alpha */
/* FIXME honor ignore tex alpha */
static void tr_parse_color(struct tr *tr, uint32_t base_color,
uint32_t *color) {
*color = abgr_to_rgba(base_color);
// if (!tr->last_poly->type0.tsp.use_alpha) {
// color[3] = 1.0f;
// }
/*if (!tr->last_poly->type0.tsp.use_alpha) {
color[3] = 1.0f;
}*/
}
static void tr_parse_color_intensity(struct tr *tr, float base_intensity,
@ -377,18 +391,18 @@ static void tr_parse_color_intensity(struct tr *tr, float base_intensity,
tr->face_color[1] * base_intensity,
tr->face_color[2] * base_intensity, tr->face_color[3]);
// if (!tr->last_poly->type0.tsp.use_alpha) {
// color[3] = 1.0f;
// }
/*if (!tr->last_poly->type0.tsp.use_alpha) {
color[3] = 1.0f;
}*/
}
static void tr_parse_color_rgba(struct tr *tr, float r, float g, float b,
float a, uint32_t *color) {
*color = float_to_rgba(r, g, b, a);
// if (!tr->last_poly->type0.tsp.use_alpha) {
// color[3] = 1.0f;
// }
/*if (!tr->last_poly->type0.tsp.use_alpha) {
color[3] = 1.0f;
}*/
}
static void tr_parse_offset_color(struct tr *tr, uint32_t offset_color,
@ -431,9 +445,9 @@ static int tr_parse_bg_vert(const struct tile_ctx *ctx, int offset,
if (ctx->bg_isp.texture) {
LOG_FATAL("Unsupported bg_isp.texture");
// v->uv[0] = *(float *)(&ctx->bg_vertices[offset]);
// v->uv[1] = *(float *)(&ctx->bg_vertices[offset + 4]);
// offset += 8;
/*v->uv[0] = *(float *)(&ctx->bg_vertices[offset]);
v->uv[1] = *(float *)(&ctx->bg_vertices[offset + 4]);
offset += 8;*/
}
uint32_t base_color = *(uint32_t *)&ctx->bg_vertices[offset];
@ -442,20 +456,20 @@ static int tr_parse_bg_vert(const struct tile_ctx *ctx, int offset,
if (ctx->bg_isp.offset) {
LOG_FATAL("Unsupported bg_isp.offset");
// uint32_t offset_color = *(uint32_t *)(&ctx->bg_vertices[offset]);
// v->offset_color[0] = ((offset_color >> 16) & 0xff) / 255.0f;
// v->offset_color[1] = ((offset_color >> 16) & 0xff) / 255.0f;
// v->offset_color[2] = ((offset_color >> 16) & 0xff) / 255.0f;
// v->offset_color[3] = 0.0f;
// offset += 4;
/*uint32_t offset_color = *(uint32_t *)(&ctx->bg_vertices[offset]);
v->offset_color[0] = ((offset_color >> 16) & 0xff) / 255.0f;
v->offset_color[1] = ((offset_color >> 16) & 0xff) / 255.0f;
v->offset_color[2] = ((offset_color >> 16) & 0xff) / 255.0f;
v->offset_color[3] = 0.0f;
offset += 4;*/
}
return offset;
}
static void tr_parse_bg(struct tr *tr, const struct tile_ctx *ctx,
struct render_ctx *rctx) {
// translate the surface
struct render_context *rctx) {
/* translate the surface */
struct surface *surf = tr_alloc_surf(tr, rctx, false);
surf->texture = 0;
@ -465,7 +479,7 @@ static void tr_parse_bg(struct tr *tr, const struct tile_ctx *ctx,
surf->src_blend = BLEND_NONE;
surf->dst_blend = BLEND_NONE;
// translate the first 3 vertices
/* 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);
@ -476,8 +490,10 @@ static void tr_parse_bg(struct tr *tr, const struct tile_ctx *ctx,
offset = tr_parse_bg_vert(ctx, offset, v1);
offset = tr_parse_bg_vert(ctx, offset, v2);
// override the xyz values supplied by ISP_BACKGND_T. while the hardware docs
// act like the should be correct, they're most definitely not in most cases
/*
* override the xyz values supplied by ISP_BACKGND_T. while the hardware docs
* act like the should be correct, they're most definitely not in most cases
*/
v0->xyz[0] = 0.0f;
v0->xyz[1] = (float)ctx->video_height;
v0->xyz[2] = ctx->bg_depth;
@ -488,7 +504,7 @@ static void tr_parse_bg(struct tr *tr, const struct tile_ctx *ctx,
v2->xyz[1] = (float)ctx->video_height;
v2->xyz[2] = ctx->bg_depth;
// 4th vertex isn't supplied, fill it out automatically
/* 4th vertex isn't supplied, fill it out automatically */
v3->xyz[0] = v2->xyz[0];
v3->xyz[1] = v1->xyz[1];
v3->xyz[2] = ctx->bg_depth;
@ -498,10 +514,12 @@ static void tr_parse_bg(struct tr *tr, const struct tile_ctx *ctx,
v3->uv[1] = v1->uv[1];
}
// NOTE this offset color implementation is not correct at all, see the
// Texture/Shading Instruction in the union tsp instruction word
/*
* 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_ctx *rctx,
int frame, struct render_context *rctx,
const uint8_t *data) {
tr_discard_incomplete_surf(tr, rctx);
@ -515,8 +533,8 @@ static void tr_parse_poly_param(struct tr *tr, const struct tile_ctx *ctx,
int poly_type = ta_get_poly_type(param->type0.pcw);
switch (poly_type) {
case 0: {
// uint32_t sdma_data_size;
// uint32_t sdma_next_addr;
/*uint32_t sdma_data_size;
uint32_t sdma_next_addr;*/
} break;
case 1: {
@ -552,7 +570,7 @@ static void tr_parse_poly_param(struct tr *tr, const struct tile_ctx *ctx,
} break;
case 6:
// don't do anything with modifier volume yet
/* don't do anything with modifier volume yet */
return;
default:
@ -560,7 +578,7 @@ static void tr_parse_poly_param(struct tr *tr, const struct tile_ctx *ctx,
break;
}
// setup the new surface
/* setup the new surface */
struct surface *surf = tr_alloc_surf(tr, rctx, false);
surf->depth_write = !param->type0.isp_tsp.z_write_disable;
surf->depth_func =
@ -571,7 +589,7 @@ static void tr_parse_poly_param(struct tr *tr, const struct tile_ctx *ctx,
surf->shade = translate_shade_mode(param->type0.tsp.texture_shading_instr);
surf->ignore_tex_alpha = param->type0.tsp.ignore_tex_alpha;
// override a few surface parameters based on the list type
/* override a few surface parameters based on the list type */
if (tr->list_type != TA_LIST_TRANSLUCENT &&
tr->list_type != TA_LIST_TRANSLUCENT_MODVOL) {
surf->src_blend = BLEND_NONE;
@ -594,10 +612,10 @@ static void tr_parse_poly_param(struct tr *tr, const struct tile_ctx *ctx,
static void tr_parse_spritea_vert(struct tr *tr, const union vert_param *param,
int i, struct vertex *vert) {
// FIXME this is assuming all sprites are billboards
// z isn't specified for i == 3
/* FIXME this is assuming all sprites are billboards */
vert->xyz[0] = param->sprite0.xyz[i][0];
vert->xyz[1] = param->sprite0.xyz[i][1];
/* z isn't specified for i == 3 */
vert->xyz[2] = param->sprite0.xyz[0][2];
tr_parse_color_rgba(tr, tr->face_color[0], tr->face_color[1],
@ -609,10 +627,10 @@ static void tr_parse_spritea_vert(struct tr *tr, const union vert_param *param,
static void tr_parse_spriteb_vert(struct tr *tr, const union vert_param *param,
int i, struct vertex *vert) {
// FIXME this is assuming all sprites are billboards
// z isn't specified for i == 3
/* FIXME this is assuming all sprites are billboards */
vert->xyz[0] = param->sprite1.xyz[i][0];
vert->xyz[1] = param->sprite1.xyz[i][1];
/* z isn't specified for i == 3 */
vert->xyz[2] = param->sprite1.xyz[0][2];
tr_parse_color_rgba(tr, tr->face_color[0], tr->face_color[1],
tr->face_color[2], tr->face_color[3], &vert->color);
@ -632,13 +650,14 @@ 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_ctx *rctx, const uint8_t *data) {
struct render_context *rctx,
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 struct vertex
// Parameter
// for
// the next polygon may be input immediately after inputting a vertex_t
// Parameter for which "End of Strip" was specified.
/*
* 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);
}
@ -779,7 +798,7 @@ static void tr_parse_vert_param(struct tr *tr, const struct tile_ctx *ctx,
} break;
case 17: {
// LOG_WARNING("Unhandled modvol triangle");
/* LOG_WARNING("Unhandled modvol triangle"); */
} break;
default:
@ -787,16 +806,18 @@ static void tr_parse_vert_param(struct tr *tr, const struct tile_ctx *ctx,
break;
}
// In the case of the Polygon type, the last struct vertex Parameter for an
// object
// must have "End of Strip" specified. If Vertex Parameters with the "End
// of Strip" specification were not input, but parameters other than the
// Vertex Parameters were input, the polygon data in question is ignored and
// an interrupt signal is output.
// FIXME is this true for sprites which come through this path as well?
/*
* in the case of the Polygon type, the last Vertex Parameter for an object
* must have "End of Strip" specified. If Vertex Parameters with the "End of
* Strip" specification were not input, but parameters other than the Vertex
* Parameters were input, the polygon data in question is ignored and
* an interrupt signal is output
*/
/* FIXME is this true for sprites which come through this path as well? */
}
static float tr_cmp_surf(struct render_ctx *rctx, const struct surface *a,
static float tr_cmp_surf(struct render_context *rctx, const struct surface *a,
const struct surface *b) {
float minza = FLT_MAX;
for (int i = 0, n = a->num_verts; i < n; i++) {
@ -819,7 +840,7 @@ static float tr_cmp_surf(struct render_ctx *rctx, const struct surface *a,
return minza - minzb;
}
static void tr_merge_surfs(struct render_ctx *rctx, int *low, int *mid,
static void tr_merge_surfs(struct render_context *rctx, int *low, int *mid,
int *high) {
static int tmp[16384];
@ -850,7 +871,7 @@ static void tr_merge_surfs(struct render_ctx *rctx, int *low, int *mid,
memcpy(low, tmp, (k - tmp) * sizeof(tmp[0]));
}
static void tr_sort_surfs(struct render_ctx *rctx, int low, int high) {
static void tr_sort_surfs(struct render_context *rctx, int low, int high) {
if (low >= high) {
return;
}
@ -863,11 +884,13 @@ static void tr_sort_surfs(struct render_ctx *rctx, int low, int high) {
}
static void tr_parse_eol(struct tr *tr, const struct tile_ctx *ctx,
struct render_ctx *rctx, const uint8_t *data) {
struct render_context *rctx, const uint8_t *data) {
tr_discard_incomplete_surf(tr, rctx);
// sort transparent polys by their z value, from back to front. remember, in
// dreamcast coordinates smaller z values are further away from the camera
/*
* 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) {
@ -879,18 +902,20 @@ static void tr_parse_eol(struct tr *tr, const struct tile_ctx *ctx,
tr->last_sorted_surf = rctx->num_surfs;
}
// Vertices coming into the TA are in window space, with the Z component being
// 1/W. These coordinates need to be converted back to clip space in order to
// be rendered with OpenGL, etc. While we want to perform an orthographic
// projection on the vertices as they're already perspective correct, the
// renderer backend will have to deal with setting the W component of each
// in order to perspective correct the texture mapping.
/*
* vertices coming into the TA are in window space, with the Z component being
* 1/W. these coordinates need to be converted back to clip space in order to
* be rendered with OpenGL, etc. while we want to perform an orthographic
* projection on the vertices as they're already perspective correct, the
* renderer backend will have to deal with setting the W component of each
* in order to perspective correct the texture mapping
*/
static void tr_proj_mat(struct tr *tr, const struct tile_ctx *ctx,
struct render_ctx *rctx) {
struct render_context *rctx) {
float znear = FLT_MIN;
float zfar = FLT_MAX;
// Z component is 1/W, so +Z is into the screen
/* Z component is 1/W, so +Z is into the screen */
for (int i = 0; i < rctx->num_verts; i++) {
struct vertex *v = &rctx->verts[i];
if (v->xyz[2] > znear) {
@ -901,15 +926,15 @@ static void tr_proj_mat(struct tr *tr, const struct tile_ctx *ctx,
}
}
// fudge so Z isn't being mapped to exactly 0.0 and 1.0
/* fudge so Z isn't being mapped to exactly 0.0 and 1.0 */
float zdepth = (znear - zfar) * 1.1f;
// fix case where a single polygon being renderered
/* fix case where a single polygon being renderered */
if (zdepth <= 0.0f) {
zdepth = 1.0f;
}
// convert from window space coordinates into clip space
/* convert from window space coordinates into clip space */
rctx->projection[0] = 2.0f / (float)ctx->video_width;
rctx->projection[4] = 0.0f;
rctx->projection[8] = 0.0f;
@ -931,13 +956,13 @@ static void tr_proj_mat(struct tr *tr, const struct tile_ctx *ctx,
rctx->projection[15] = 1.0f;
}
static void tr_reset(struct tr *tr, struct render_ctx *rctx) {
// reset render state
static void tr_reset(struct tr *tr, struct render_context *rctx) {
/* reset render state */
rctx->num_surfs = 0;
rctx->num_verts = 0;
rctx->num_states = 0;
// reset global state
/* reset global state */
tr->last_poly = NULL;
tr->last_vertex = NULL;
tr->list_type = 0;
@ -945,8 +970,10 @@ static void tr_reset(struct tr *tr, struct render_ctx *rctx) {
tr->last_sorted_surf = 0;
}
static void tr_parse_context_inner(struct tr *tr, const struct tile_ctx *ctx,
int frame, struct render_ctx *rctx) {
void tr_parse_context(struct tr *tr, const struct tile_ctx *ctx, int frame,
struct render_context *rctx) {
PROF_ENTER("gpu", "tr_parse_context");
const uint8_t *data = ctx->params;
const uint8_t *end = ctx->params + ctx->size;
@ -957,26 +984,28 @@ static void tr_parse_context_inner(struct tr *tr, const struct tile_ctx *ctx,
while (data < end) {
union pcw pcw = *(union pcw *)data;
// FIXME
// If Vertex Parameters with the "End of Strip" specification were not
// input, but parameters other than the Vertex Parameters were input, the
// polygon data in question is ignored and an interrupt signal is output.
/*
* FIXME
* if Vertex Parameters with the "End of Strip" specification were not
* input, but parameters other than the Vertex Parameters were input, the
* polygon data in question is ignored and an interrupt signal is output
*/
switch (pcw.para_type) {
// control params
/* control params */
case TA_PARAM_END_OF_LIST:
tr_parse_eol(tr, ctx, rctx, data);
break;
case TA_PARAM_USER_TILE_CLIP:
// nothing to do
/* nothing to do */
break;
case TA_PARAM_OBJ_LIST_SET:
LOG_FATAL("TA_PARAM_OBJ_LIST_SET unsupported");
break;
// global params
/* global params */
case TA_PARAM_POLY_OR_VOL:
tr_parse_poly_param(tr, ctx, frame, rctx, data);
break;
@ -985,7 +1014,7 @@ static void tr_parse_context_inner(struct tr *tr, const struct tile_ctx *ctx,
tr_parse_poly_param(tr, ctx, frame, rctx, data);
break;
// vertex params
/* vertex params */
case TA_PARAM_VERTEX:
tr_parse_vert_param(tr, ctx, rctx, data);
break;
@ -995,7 +1024,7 @@ static void tr_parse_context_inner(struct tr *tr, const struct tile_ctx *ctx,
break;
}
// keep track of the surf / vert counts at each parameter offset
/* 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);
@ -1010,39 +1039,32 @@ static void tr_parse_context_inner(struct tr *tr, const struct tile_ctx *ctx,
}
tr_proj_mat(tr, ctx, rctx);
}
void tr_parse_context(struct tr *tr, const struct tile_ctx *ctx, int frame,
struct render_ctx *rctx) {
PROF_ENTER("gpu", "tr_parse_context");
tr_parse_context_inner(tr, ctx, frame, rctx);
PROF_LEAVE();
}
static void tr_render_context_inner(struct tr *tr,
const struct render_ctx *ctx) {
video_begin_surfaces(tr->video, ctx->projection, ctx->verts, ctx->num_verts);
void tr_render_context(struct tr *tr, const struct render_context *rctx) {
PROF_ENTER("gpu", "tr_render_context");
const int *sorted_surf = ctx->sorted_surfs;
const int *sorted_surf_end = ctx->sorted_surfs + ctx->num_surfs;
video_begin_surfaces(tr->video, rctx->projection, rctx->verts,
rctx->num_verts);
const int *sorted_surf = rctx->sorted_surfs;
const int *sorted_surf_end = rctx->sorted_surfs + rctx->num_surfs;
while (sorted_surf < sorted_surf_end) {
video_draw_surface(tr->video, &ctx->surfs[*sorted_surf]);
video_draw_surface(tr->video, &rctx->surfs[*sorted_surf]);
sorted_surf++;
}
video_end_surfaces(tr->video);
}
void tr_render_context(struct tr *tr, const struct render_ctx *ctx) {
PROF_ENTER("gpu", "tr_render_context");
tr_render_context_inner(tr, ctx);
PROF_LEAVE();
}
void tr_destroy(struct tr *tr) {
free(tr);
}
struct tr *tr_create(struct video_backend *video,
struct texture_provider *provider) {
struct tr *tr = calloc(1, sizeof(struct tr));
@ -1052,7 +1074,3 @@ struct tr *tr_create(struct video_backend *video,
return tr;
}
void tr_destroy(struct tr *tr) {
free(tr);
}

View File

@ -13,7 +13,7 @@ struct texture_entry {
union tsp tsp;
union tcw tcw;
// source info
/* source info */
int frame;
int dirty;
const uint8_t *texture;
@ -21,7 +21,7 @@ struct texture_entry {
const uint8_t *palette;
int palette_size;
// backend info
/* backend info */
enum pxl_format format;
enum filter_mode filter;
enum wrap_mode wrap_u;
@ -32,24 +32,28 @@ 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
/*
* 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;
};
// tile context parsed into appropriate structures for the render backend
struct render_ctx {
// supplied by caller
/* tile context parsed into appropriate structures for the video backend */
struct render_context {
/* supplied by caller */
struct surface *surfs;
int surfs_size;
@ -62,7 +66,7 @@ struct render_ctx {
struct param_state *states;
int states_size;
//
/* */
float projection[16];
int num_surfs;
int num_verts;
@ -73,12 +77,12 @@ static inline texture_key_t tr_texture_key(union tsp tsp, union tcw tcw) {
return ((uint64_t)tsp.full << 32) | tcw.full;
}
void tr_parse_context(struct tr *tr, const struct tile_ctx *ctx, int frame,
struct render_ctx *rctx);
void tr_render_context(struct tr *tr, const struct render_ctx *rctx);
struct tr *tr_create(struct video_backend *video,
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);
#endif

View File

@ -100,7 +100,7 @@ struct sh4 *sh4_create(struct dreamcast *dc) {
struct sh4 *sh4 = dc_create_device(dc, sizeof(struct sh4), "sh", &sh4_init);
sh4->execute_if = dc_create_execute_interface(&sh4_run, 0);
sh4->memory_if = dc_create_memory_interface(dc, &sh4_data_map);
sh4->window_if = dc_create_window_interface(NULL, &sh4_debug_menu, NULL);
sh4->window_if = dc_create_window_interface(&sh4_debug_menu, NULL);
return sh4;
}