mirror of https://github.com/inolen/redream.git
tile accelerator / renderer tlc
standardized some parameter names, added comments to provide an overview of the ta functionality
This commit is contained in:
parent
6040ef924d
commit
1067df8099
|
@ -93,7 +93,7 @@ struct emu {
|
|||
cond_t frame_cond;
|
||||
|
||||
/* latest context from the dreamcast, ready to be rendered */
|
||||
struct tile_context *pending_ctx;
|
||||
struct ta_context *pending_ctx;
|
||||
struct tr_context pending_rc;
|
||||
unsigned pending_id;
|
||||
|
||||
|
@ -275,10 +275,10 @@ static void emu_register_texture_source(struct emu *emu, union tsp tsp,
|
|||
}
|
||||
|
||||
static void emu_register_texture_sources(struct emu *emu,
|
||||
struct tile_context *ctx) {
|
||||
struct ta_context *ctx) {
|
||||
const uint8_t *data = ctx->params;
|
||||
const uint8_t *end = ctx->params + ctx->size;
|
||||
int vertex_type = 0;
|
||||
int vert_type = 0;
|
||||
|
||||
while (data < end) {
|
||||
union pcw pcw = *(union pcw *)data;
|
||||
|
@ -288,7 +288,7 @@ static void emu_register_texture_sources(struct emu *emu,
|
|||
case TA_PARAM_SPRITE: {
|
||||
const union poly_param *param = (const union poly_param *)data;
|
||||
|
||||
vertex_type = ta_get_vert_type(param->type0.pcw);
|
||||
vert_type = ta_vert_type(param->type0.pcw);
|
||||
|
||||
if (param->type0.pcw.texture) {
|
||||
emu_register_texture_source(emu, param->type0.tsp, param->type0.tcw);
|
||||
|
@ -299,7 +299,7 @@ static void emu_register_texture_sources(struct emu *emu,
|
|||
break;
|
||||
}
|
||||
|
||||
data += ta_get_param_size(pcw, vertex_type);
|
||||
data += ta_param_size(pcw, vert_type);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -366,7 +366,7 @@ static void emu_guest_finish_render(void *userdata) {
|
|||
}
|
||||
}
|
||||
|
||||
static void emu_guest_start_render(void *userdata, struct tile_context *ctx) {
|
||||
static void emu_guest_start_render(void *userdata, struct ta_context *ctx) {
|
||||
struct emu *emu = userdata;
|
||||
|
||||
/* incement internal frame number. this frame number is assigned to the each
|
||||
|
|
|
@ -14,7 +14,7 @@ void trace_writer_close(struct trace_writer *writer) {
|
|||
}
|
||||
|
||||
void trace_writer_render_context(struct trace_writer *writer,
|
||||
struct tile_context *ctx) {
|
||||
struct ta_context *ctx) {
|
||||
struct trace_cmd cmd = {0};
|
||||
cmd.type = TRACE_CMD_CONTEXT;
|
||||
cmd.context.autosort = ctx->autosort;
|
||||
|
@ -161,7 +161,7 @@ void trace_destroy(struct trace *trace) {
|
|||
free(trace);
|
||||
}
|
||||
|
||||
void trace_copy_context(const struct trace_cmd *cmd, struct tile_context *ctx) {
|
||||
void trace_copy_context(const struct trace_cmd *cmd, struct ta_context *ctx) {
|
||||
CHECK_EQ(cmd->type, TRACE_CMD_CONTEXT);
|
||||
|
||||
ctx->autosort = cmd->context.autosort;
|
||||
|
|
|
@ -31,7 +31,7 @@ struct trace_cmd {
|
|||
const uint8_t *texture;
|
||||
} texture;
|
||||
|
||||
/* slimmed down version of the tile_context structure, will need to be in
|
||||
/* slimmed down version of the ta_context structure, will need to be in
|
||||
sync */
|
||||
struct {
|
||||
uint32_t frame;
|
||||
|
@ -64,7 +64,7 @@ struct trace_writer {
|
|||
void get_next_trace_filename(char *filename, size_t size);
|
||||
|
||||
struct trace *trace_parse(const char *filename);
|
||||
void trace_copy_context(const struct trace_cmd *cmd, struct tile_context *ctx);
|
||||
void trace_copy_context(const struct trace_cmd *cmd, struct ta_context *ctx);
|
||||
void trace_destroy(struct trace *trace);
|
||||
|
||||
struct trace_writer *trace_writer_open(const char *filename);
|
||||
|
@ -73,7 +73,7 @@ void trace_writer_insert_texture(struct trace_writer *writer, union tsp tsp,
|
|||
const uint8_t *palette, int palette_size,
|
||||
const uint8_t *texture, int texture_size);
|
||||
void trace_writer_render_context(struct trace_writer *writer,
|
||||
struct tile_context *ctx);
|
||||
struct ta_context *ctx);
|
||||
void trace_writer_close(struct trace_writer *writer);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -32,7 +32,7 @@ void dc_finish_render(struct dreamcast *dc) {
|
|||
dc->finish_render(dc->userdata);
|
||||
}
|
||||
|
||||
void dc_start_render(struct dreamcast *dc, struct tile_context *ctx) {
|
||||
void dc_start_render(struct dreamcast *dc, struct ta_context *ctx) {
|
||||
if (!dc->start_render) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ struct pvr;
|
|||
struct scheduler;
|
||||
struct sh4;
|
||||
struct ta;
|
||||
struct tile_context;
|
||||
struct ta_context;
|
||||
|
||||
/*
|
||||
* register callbacks
|
||||
|
@ -123,7 +123,7 @@ struct device {
|
|||
* machine
|
||||
*/
|
||||
typedef void (*push_audio_cb)(void *, const int16_t *, int);
|
||||
typedef void (*start_render_cb)(void *, struct tile_context *);
|
||||
typedef void (*start_render_cb)(void *, struct ta_context *);
|
||||
typedef void (*finish_render_cb)(void *);
|
||||
typedef void (*vertical_blank_cb)(void *);
|
||||
|
||||
|
@ -190,7 +190,7 @@ void dc_input(struct dreamcast *dc, int port, int button, int16_t value);
|
|||
|
||||
/* client functionality */
|
||||
void dc_push_audio(struct dreamcast *dc, const int16_t *data, int frames);
|
||||
void dc_start_render(struct dreamcast *dc, struct tile_context *ctx);
|
||||
void dc_start_render(struct dreamcast *dc, struct ta_context *ctx);
|
||||
void dc_finish_render(struct dreamcast *dc);
|
||||
void dc_vertical_blank(struct dreamcast *dc);
|
||||
|
||||
|
|
|
@ -1,3 +1,23 @@
|
|||
/*
|
||||
* the HOLLY contained two graphics-related units:
|
||||
*
|
||||
* 1.) the tile accelerator. the ta acted as a frontend which received data from
|
||||
* programs and converted / sanitized this data into display lists which
|
||||
* were written back out to texture memory
|
||||
* 2.) the core. the core acted as the backend, which took the display lists
|
||||
* generated by the ta, rendered them, and wrote the results out to the
|
||||
* framebuffer
|
||||
*
|
||||
* in our world, the display list generation used by the ta and core hardware
|
||||
* is not emulated. instead, the parameters submitted to the ta are recorded
|
||||
* to our ta_context structures, which are later converted to an appropriate
|
||||
* format for the host's render backend in tr.c
|
||||
*
|
||||
* this file is responsible for processing the data fed to the ta into our
|
||||
* internal ta_context format, and passing these contexts to the host for
|
||||
* rendering when initiated
|
||||
*/
|
||||
|
||||
#include "guest/pvr/ta.h"
|
||||
#include "core/exception_handler.h"
|
||||
#include "core/filesystem.h"
|
||||
|
@ -12,11 +32,6 @@
|
|||
DEFINE_AGGREGATE_COUNTER(ta_data);
|
||||
DEFINE_AGGREGATE_COUNTER(ta_renders);
|
||||
|
||||
#define TA_YUV420_MACROBLOCK_SIZE 384
|
||||
#define TA_YUV422_MACROBLOCK_SIZE 512
|
||||
#define TA_MAX_MACROBLOCK_SIZE \
|
||||
MAX(TA_YUV420_MACROBLOCK_SIZE, TA_YUV422_MACROBLOCK_SIZE)
|
||||
|
||||
struct ta {
|
||||
struct device;
|
||||
uint8_t *video_ram;
|
||||
|
@ -29,26 +44,160 @@ struct ta {
|
|||
int yuv_macroblock_count;
|
||||
|
||||
/* tile context pool */
|
||||
struct tile_context contexts[8];
|
||||
struct ta_context contexts[8];
|
||||
struct list free_contexts;
|
||||
struct list live_contexts;
|
||||
struct tile_context *curr_context;
|
||||
struct ta_context *curr_context;
|
||||
};
|
||||
|
||||
int g_param_sizes[0x100 * TA_NUM_PARAMS * TA_NUM_VERTS];
|
||||
int g_poly_types[0x100 * TA_NUM_PARAMS * TA_NUM_LISTS];
|
||||
int g_vertex_types[0x100 * TA_NUM_PARAMS * TA_NUM_LISTS];
|
||||
/*
|
||||
* texture info helpers
|
||||
*/
|
||||
int ta_texture_stride(union tsp tsp, union tcw tcw, int stride) {
|
||||
int twiddled = ta_texture_twiddled(tcw);
|
||||
|
||||
static holly_interrupt_t list_interrupts[] = {
|
||||
HOLLY_INT_TAEOINT, /* TA_LIST_OPAQUE */
|
||||
HOLLY_INT_TAEOMINT, /* TA_LIST_OPAQUE_MODVOL */
|
||||
HOLLY_INT_TAETINT, /* TA_LIST_TRANSLUCENT */
|
||||
HOLLY_INT_TAETMINT, /* TA_LIST_TRANSLUCENT_MODVOL */
|
||||
HOLLY_INT_TAEPTIN /* TA_LIST_PUNCH_THROUGH */
|
||||
};
|
||||
if (!tcw.stride_select || twiddled) {
|
||||
return ta_texture_width(tsp, tcw);
|
||||
}
|
||||
|
||||
/* See "57.1.1.2 Parameter Combinations" for information on the poly types. */
|
||||
static int ta_get_poly_type_raw(union pcw pcw) {
|
||||
return stride;
|
||||
}
|
||||
|
||||
int ta_texture_height(union tsp tsp, union tcw tcw) {
|
||||
int mipmaps = ta_texture_mipmaps(tcw);
|
||||
int height = 8 << tsp.texture_v_size;
|
||||
if (mipmaps) {
|
||||
height = ta_texture_width(tsp, tcw);
|
||||
}
|
||||
return height;
|
||||
}
|
||||
|
||||
int ta_texture_width(union tsp tsp, union tcw tcw) {
|
||||
return 8 << tsp.texture_u_size;
|
||||
}
|
||||
|
||||
int ta_texture_mipmaps(union tcw tcw) {
|
||||
return ta_texture_twiddled(tcw) && tcw.mip_mapped;
|
||||
}
|
||||
|
||||
int ta_texture_twiddled(union tcw tcw) {
|
||||
return !tcw.scan_order ||
|
||||
/* paletted textures are always twiddled */
|
||||
tcw.pixel_fmt == PVR_PXL_8BPP || tcw.pixel_fmt == PVR_PXL_4BPP;
|
||||
}
|
||||
|
||||
int ta_texture_compressed(union tcw tcw) {
|
||||
return tcw.vq_compressed;
|
||||
}
|
||||
|
||||
int ta_texture_format(union tcw tcw) {
|
||||
int compressed = ta_texture_compressed(tcw);
|
||||
int twiddled = ta_texture_twiddled(tcw);
|
||||
int mipmaps = ta_texture_mipmaps(tcw);
|
||||
|
||||
int texture_fmt = PVR_TEX_INVALID;
|
||||
|
||||
if (compressed) {
|
||||
if (mipmaps) {
|
||||
texture_fmt = PVR_TEX_VQ_MIPMAPS;
|
||||
} else {
|
||||
texture_fmt = PVR_TEX_VQ;
|
||||
}
|
||||
} else if (tcw.pixel_fmt == PVR_PXL_4BPP) {
|
||||
if (mipmaps) {
|
||||
texture_fmt = PVR_TEX_PALETTE_4BPP_MIPMAPS;
|
||||
} else {
|
||||
texture_fmt = PVR_TEX_PALETTE_4BPP;
|
||||
}
|
||||
} else if (tcw.pixel_fmt == PVR_PXL_8BPP) {
|
||||
if (mipmaps) {
|
||||
texture_fmt = PVR_TEX_PALETTE_8BPP_MIPMAPS;
|
||||
} else {
|
||||
texture_fmt = PVR_TEX_PALETTE_8BPP;
|
||||
}
|
||||
} else if (twiddled) {
|
||||
if (mipmaps) {
|
||||
texture_fmt = PVR_TEX_TWIDDLED_MIPMAPS;
|
||||
} else {
|
||||
texture_fmt = PVR_TEX_TWIDDLED;
|
||||
}
|
||||
} else {
|
||||
texture_fmt = PVR_TEX_BITMAP;
|
||||
}
|
||||
|
||||
return texture_fmt;
|
||||
}
|
||||
|
||||
uint32_t ta_palette_addr(union tcw tcw, int *size) {
|
||||
uint32_t palette_addr = 0;
|
||||
int palette_size = 0;
|
||||
|
||||
if (tcw.pixel_fmt == PVR_PXL_4BPP || tcw.pixel_fmt == PVR_PXL_8BPP) {
|
||||
/* palette ram is 4096 bytes, with each palette entry being 4 bytes each,
|
||||
resulting in 1 << 10 indexes */
|
||||
if (tcw.pixel_fmt == PVR_PXL_4BPP) {
|
||||
/* in 4bpp mode, the palette selector represents the upper 6 bits of the
|
||||
palette index, with the remaining 4 bits being filled in by the
|
||||
texture */
|
||||
palette_addr = tcw.p.palette_selector << 6;
|
||||
palette_size = 1 << 6;
|
||||
} else if (tcw.pixel_fmt == PVR_PXL_8BPP) {
|
||||
/* in 8bpp mode, the palette selector represents the upper 2 bits of the
|
||||
palette index, with the remaining 8 bits being filled in by the
|
||||
texture */
|
||||
palette_addr = (tcw.p.palette_selector >> 4) << 10;
|
||||
palette_size = 1 << 10;
|
||||
}
|
||||
}
|
||||
|
||||
if (size) {
|
||||
*size = palette_size;
|
||||
}
|
||||
|
||||
return palette_addr;
|
||||
}
|
||||
|
||||
uint32_t ta_texture_addr(union tsp tsp, union tcw tcw, int *size) {
|
||||
uint32_t texture_addr = tcw.texture_addr << 3;
|
||||
int texture_size = 0;
|
||||
|
||||
/* compressed textures have the additional fixed-size codebook */
|
||||
if (ta_texture_compressed(tcw)) {
|
||||
texture_size += PVR_CODEBOOK_SIZE;
|
||||
}
|
||||
|
||||
/* calculate the size of each mipmap level */
|
||||
int width = ta_texture_width(tsp, tcw);
|
||||
int height = ta_texture_height(tsp, tcw);
|
||||
int bpp = 16;
|
||||
if (tcw.pixel_fmt == PVR_PXL_8BPP) {
|
||||
bpp = 8;
|
||||
} else if (tcw.pixel_fmt == PVR_PXL_4BPP) {
|
||||
bpp = 4;
|
||||
}
|
||||
int mipmaps = ta_texture_mipmaps(tcw);
|
||||
int levels = mipmaps ? ctz32(width) + 1 : 1;
|
||||
while (levels--) {
|
||||
int mip_width = width >> levels;
|
||||
int mip_height = height >> levels;
|
||||
texture_size += (mip_width * mip_height * bpp) >> 3;
|
||||
}
|
||||
|
||||
if (size) {
|
||||
*size = texture_size;
|
||||
}
|
||||
|
||||
return texture_addr;
|
||||
}
|
||||
|
||||
/*
|
||||
* parameter stream processing helpers
|
||||
*/
|
||||
int ta_param_sizes[0x100 * TA_NUM_PARAMS * TA_NUM_VERTS];
|
||||
int ta_poly_types[0x100 * TA_NUM_PARAMS * TA_NUM_LISTS];
|
||||
int ta_vert_types[0x100 * TA_NUM_PARAMS * TA_NUM_LISTS];
|
||||
|
||||
static int ta_poly_type_raw(union pcw pcw) {
|
||||
if (pcw.list_type == TA_LIST_OPAQUE_MODVOL ||
|
||||
pcw.list_type == TA_LIST_TRANSLUCENT_MODVOL) {
|
||||
return 6;
|
||||
|
@ -86,8 +235,7 @@ static int ta_get_poly_type_raw(union pcw pcw) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* See "57.1.1.2 Parameter Combinations" for information on the vertex types. */
|
||||
static int ta_get_vert_type_raw(union pcw pcw) {
|
||||
static int ta_vert_type_raw(union pcw pcw) {
|
||||
if (pcw.list_type == TA_LIST_OPAQUE_MODVOL ||
|
||||
pcw.list_type == TA_LIST_TRANSLUCENT_MODVOL) {
|
||||
return 17;
|
||||
|
@ -140,10 +288,7 @@ static int ta_get_vert_type_raw(union pcw pcw) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Parameter size can be determined by only the union pcw for every parameter
|
||||
other than vertex parameters. For vertex parameters, the vertex type derived
|
||||
from the last poly or modifier volume parameter is needed. */
|
||||
static int ta_get_param_size_raw(union pcw pcw, int vertex_type) {
|
||||
static int ta_param_size_raw(union pcw pcw, int vert_type) {
|
||||
switch (pcw.para_type) {
|
||||
case TA_PARAM_END_OF_LIST:
|
||||
return 32;
|
||||
|
@ -152,15 +297,15 @@ static int ta_get_param_size_raw(union pcw pcw, int vertex_type) {
|
|||
case TA_PARAM_OBJ_LIST_SET:
|
||||
return 32;
|
||||
case TA_PARAM_POLY_OR_VOL: {
|
||||
int type = ta_get_poly_type_raw(pcw);
|
||||
int type = ta_poly_type_raw(pcw);
|
||||
return type == 0 || type == 1 || type == 3 ? 32 : 64;
|
||||
}
|
||||
case TA_PARAM_SPRITE:
|
||||
return 32;
|
||||
case TA_PARAM_VERTEX: {
|
||||
return vertex_type == 0 || vertex_type == 1 || vertex_type == 2 ||
|
||||
vertex_type == 3 || vertex_type == 4 || vertex_type == 7 ||
|
||||
vertex_type == 8 || vertex_type == 9 || vertex_type == 10
|
||||
return vert_type == 0 || vert_type == 1 || vert_type == 2 ||
|
||||
vert_type == 3 || vert_type == 4 || vert_type == 7 ||
|
||||
vert_type == 8 || vert_type == 9 || vert_type == 10
|
||||
? 32
|
||||
: 64;
|
||||
}
|
||||
|
@ -173,8 +318,38 @@ static void ta_soft_reset(struct ta *ta) {
|
|||
/* FIXME what are we supposed to do here? */
|
||||
}
|
||||
|
||||
static struct tile_context *ta_get_context(struct ta *ta, uint32_t addr) {
|
||||
list_for_each_entry(ctx, &ta->live_contexts, struct tile_context, it) {
|
||||
/*
|
||||
* ta parameter handling
|
||||
*
|
||||
* ta contexts are an encapsulation of all the state necessary to render a given
|
||||
* frame submitted to the ta. this includes the raw poly and vertex parameters,
|
||||
* as well as the relevant pvr register state at the time of rendering
|
||||
*
|
||||
* to understand this code, it's important to know how programs submitted data:
|
||||
*
|
||||
* 1.) initialize the TA_ISP_BASE / TA_ISP_LIMIT to an address range in memory
|
||||
* where the poly and vertex parameters were to be stored
|
||||
* 2.) initialize the TA_OL_BASE / TA_OL_LIMIT to an address in memory where the
|
||||
* object lists generated by core would be stored
|
||||
* 3.) write to TA_LIST_INIT to initialize the ta's internal registers
|
||||
* 4.) start dma'ing poly / vertex parameters to 0x10000000
|
||||
* 5.) wait for interrupts confirming that all of the data for a particular list
|
||||
* has been transferred to texture memory
|
||||
*
|
||||
* due to the TA_ISP_BASE register, it was possible to have multiple frames of
|
||||
* data in memory at a time, which is why a tree is maintained mapping a guest
|
||||
* address to its respective ta_context
|
||||
*/
|
||||
static holly_interrupt_t list_interrupts[] = {
|
||||
HOLLY_INT_TAEOINT, /* TA_LIST_OPAQUE */
|
||||
HOLLY_INT_TAEOMINT, /* TA_LIST_OPAQUE_MODVOL */
|
||||
HOLLY_INT_TAETINT, /* TA_LIST_TRANSLUCENT */
|
||||
HOLLY_INT_TAETMINT, /* TA_LIST_TRANSLUCENT_MODVOL */
|
||||
HOLLY_INT_TAEPTIN /* TA_LIST_PUNCH_THROUGH */
|
||||
};
|
||||
|
||||
static struct ta_context *ta_get_context(struct ta *ta, uint32_t addr) {
|
||||
list_for_each_entry(ctx, &ta->live_contexts, struct ta_context, it) {
|
||||
if (ctx->addr == addr) {
|
||||
return ctx;
|
||||
}
|
||||
|
@ -182,15 +357,15 @@ static struct tile_context *ta_get_context(struct ta *ta, uint32_t addr) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static struct tile_context *ta_demand_context(struct ta *ta, uint32_t addr) {
|
||||
struct tile_context *ctx = ta_get_context(ta, addr);
|
||||
static struct ta_context *ta_demand_context(struct ta *ta, uint32_t addr) {
|
||||
struct ta_context *ctx = ta_get_context(ta, addr);
|
||||
|
||||
if (ctx) {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/* remove from the object pool */
|
||||
ctx = list_first_entry(&ta->free_contexts, struct tile_context, it);
|
||||
ctx = list_first_entry(&ta->free_contexts, struct ta_context, it);
|
||||
CHECK_NOTNULL(ctx);
|
||||
list_remove(&ta->free_contexts, &ctx->it);
|
||||
|
||||
|
@ -199,7 +374,7 @@ static struct tile_context *ta_demand_context(struct ta *ta, uint32_t addr) {
|
|||
ctx->cursor = 0;
|
||||
ctx->size = 0;
|
||||
ctx->list_type = 0;
|
||||
ctx->vertex_type = 0;
|
||||
ctx->vert_type = 0;
|
||||
|
||||
/* add to live list */
|
||||
list_add(&ta->live_contexts, &ctx->it);
|
||||
|
@ -207,29 +382,29 @@ static struct tile_context *ta_demand_context(struct ta *ta, uint32_t addr) {
|
|||
return ctx;
|
||||
}
|
||||
|
||||
static void ta_unlink_context(struct ta *ta, struct tile_context *ctx) {
|
||||
static void ta_unlink_context(struct ta *ta, struct ta_context *ctx) {
|
||||
/* remove from live list, but don't add back to object pool */
|
||||
list_remove(&ta->live_contexts, &ctx->it);
|
||||
}
|
||||
|
||||
static void ta_free_context(struct ta *ta, struct tile_context *ctx) {
|
||||
static void ta_free_context(struct ta *ta, struct ta_context *ctx) {
|
||||
/* add back to object pool */
|
||||
list_add(&ta->free_contexts, &ctx->it);
|
||||
}
|
||||
|
||||
static void ta_cont_context(struct ta *ta, struct tile_context *ctx) {
|
||||
static void ta_cont_context(struct ta *ta, struct ta_context *ctx) {
|
||||
ctx->list_type = TA_NUM_LISTS;
|
||||
ctx->vertex_type = TA_NUM_VERTS;
|
||||
ctx->vert_type = TA_NUM_VERTS;
|
||||
}
|
||||
|
||||
static void ta_init_context(struct ta *ta, struct tile_context *ctx) {
|
||||
static void ta_init_context(struct ta *ta, struct ta_context *ctx) {
|
||||
ctx->cursor = 0;
|
||||
ctx->size = 0;
|
||||
ctx->list_type = TA_NUM_LISTS;
|
||||
ctx->vertex_type = TA_NUM_VERTS;
|
||||
ctx->vert_type = TA_NUM_VERTS;
|
||||
}
|
||||
|
||||
static void ta_write_context(struct ta *ta, struct tile_context *ctx, void *ptr,
|
||||
static void ta_write_context(struct ta *ta, struct ta_context *ctx, void *ptr,
|
||||
int size) {
|
||||
CHECK_LT(ctx->size + size, (int)sizeof(ctx->params));
|
||||
memcpy(&ctx->params[ctx->size], ptr, size);
|
||||
|
@ -245,7 +420,7 @@ static void ta_write_context(struct ta *ta, struct tile_context *ctx, void *ptr,
|
|||
void *param = &ctx->params[ctx->cursor];
|
||||
union pcw pcw = *(union pcw *)param;
|
||||
|
||||
int size = ta_get_param_size(pcw, ctx->vertex_type);
|
||||
int size = ta_param_size(pcw, ctx->vert_type);
|
||||
int recv = ctx->size - ctx->cursor;
|
||||
|
||||
if (recv < size) {
|
||||
|
@ -266,7 +441,7 @@ static void ta_write_context(struct ta *ta, struct tile_context *ctx, void *ptr,
|
|||
holly_raise_interrupt(ta->holly, list_interrupts[ctx->list_type]);
|
||||
}
|
||||
ctx->list_type = TA_NUM_LISTS;
|
||||
ctx->vertex_type = TA_NUM_VERTS;
|
||||
ctx->vert_type = TA_NUM_VERTS;
|
||||
break;
|
||||
|
||||
case TA_PARAM_USER_TILE_CLIP:
|
||||
|
@ -279,7 +454,7 @@ static void ta_write_context(struct ta *ta, struct tile_context *ctx, void *ptr,
|
|||
/* global params */
|
||||
case TA_PARAM_POLY_OR_VOL:
|
||||
case TA_PARAM_SPRITE:
|
||||
ctx->vertex_type = ta_get_vert_type(pcw);
|
||||
ctx->vert_type = ta_vert_type(pcw);
|
||||
break;
|
||||
|
||||
/* vertex params */
|
||||
|
@ -295,40 +470,19 @@ static void ta_write_context(struct ta *ta, struct tile_context *ctx, void *ptr,
|
|||
}
|
||||
}
|
||||
|
||||
void ta_texture_info(struct ta *ta, union tsp tsp, union tcw tcw,
|
||||
const uint8_t **texture, int *texture_size,
|
||||
const uint8_t **palette, int *palette_size) {
|
||||
uint32_t texture_addr = ta_texture_addr(tcw);
|
||||
*texture = &ta->video_ram[texture_addr];
|
||||
*texture_size = ta_texture_size(tsp, tcw);
|
||||
|
||||
if (tcw.pixel_fmt == TA_PXL_4BPP || tcw.pixel_fmt == TA_PXL_8BPP) {
|
||||
uint32_t palette_addr = 0;
|
||||
|
||||
/* palette ram is 4096 bytes, with each palette entry being 4 bytes each,
|
||||
resulting in 1 << 10 indexes */
|
||||
if (tcw.pixel_fmt == TA_PXL_4BPP) {
|
||||
/* in 4bpp mode, the palette selector represents the upper 6 bits of the
|
||||
palette index, with the remaining 4 bits being filled in by the
|
||||
texture */
|
||||
palette_addr = tcw.p.palette_selector << 6;
|
||||
*palette_size = 1 << 6;
|
||||
} else if (tcw.pixel_fmt == TA_PXL_8BPP) {
|
||||
/* in 8bpp mode, the palette selector represents the upper 2 bits of the
|
||||
palette index, with the remaining 8 bits being filled in by the
|
||||
texture */
|
||||
palette_addr = (tcw.p.palette_selector >> 4) << 10;
|
||||
*palette_size = 1 << 10;
|
||||
}
|
||||
|
||||
*palette = &ta->pvr->palette_ram[palette_addr];
|
||||
} else {
|
||||
*palette = NULL;
|
||||
*palette_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ta_save_state(struct ta *ta, struct tile_context *ctx) {
|
||||
/*
|
||||
* ta rendering flow
|
||||
*
|
||||
* after dma'ing input parameters to texture memory, rendering is initiated by:
|
||||
* 1.) writing the address of the parameters in the PARAM_BASE register
|
||||
* 2.) writing to the STARTRENDER register
|
||||
*
|
||||
* once rendering is done, an interrupt is raised to signal so. many games take
|
||||
* advantage of this time between start and end render to run additional cpu
|
||||
* code, making it very adventageous to also render asynchronously at the host
|
||||
* level in order to squeeze out extra free performance
|
||||
*/
|
||||
static void ta_save_state(struct ta *ta, struct ta_context *ctx) {
|
||||
struct pvr *pvr = ta->pvr;
|
||||
struct address_space *space = ta->sh4->memory_if->space;
|
||||
|
||||
|
@ -430,7 +584,7 @@ static void ta_save_state(struct ta *ta, struct tile_context *ctx) {
|
|||
}
|
||||
|
||||
static void ta_finish_render(void *data) {
|
||||
struct tile_context *ctx = data;
|
||||
struct ta_context *ctx = data;
|
||||
struct ta *ta = ctx->userdata;
|
||||
|
||||
/* ensure the client has finished rendering */
|
||||
|
@ -445,7 +599,7 @@ static void ta_finish_render(void *data) {
|
|||
holly_raise_interrupt(ta->holly, HOLLY_INT_PCEOTINT);
|
||||
}
|
||||
|
||||
static void ta_start_render(struct ta *ta, struct tile_context *ctx) {
|
||||
static void ta_start_render(struct ta *ta, struct ta_context *ctx) {
|
||||
prof_counter_add(COUNTER_ta_renders, 1);
|
||||
|
||||
/* remove context from pool */
|
||||
|
@ -465,6 +619,14 @@ static void ta_start_render(struct ta *ta, struct tile_context *ctx) {
|
|||
scheduler_start_timer(ta->scheduler, &ta_finish_render, ctx, end);
|
||||
}
|
||||
|
||||
/*
|
||||
* yuv420 -> yuv422 conversion routines
|
||||
*/
|
||||
#define TA_YUV420_MACROBLOCK_SIZE 384
|
||||
#define TA_YUV422_MACROBLOCK_SIZE 512
|
||||
#define TA_MAX_MACROBLOCK_SIZE \
|
||||
MAX(TA_YUV420_MACROBLOCK_SIZE, TA_YUV422_MACROBLOCK_SIZE)
|
||||
|
||||
static void ta_yuv_init(struct ta *ta) {
|
||||
struct pvr *pvr = ta->pvr;
|
||||
|
||||
|
@ -561,9 +723,15 @@ static void ta_yuv_process_macroblock(struct ta *ta, void *data) {
|
|||
}
|
||||
}
|
||||
|
||||
static void ta_poly_fifo_write(struct ta *ta, uint32_t dst, void *ptr,
|
||||
int size) {
|
||||
PROF_ENTER("cpu", "ta_poly_fifo_write");
|
||||
/* ta data handlers
|
||||
*
|
||||
* three types of data are written to the ta:
|
||||
* 1.) polygon data - input parameters for display lists
|
||||
* 2.) yuv data - yuv macroblocks that are to be reencoded as yuv422
|
||||
* 3.) texture data - data that is written directly to vram
|
||||
*/
|
||||
static void ta_poly_write(struct ta *ta, uint32_t dst, void *ptr, int size) {
|
||||
PROF_ENTER("cpu", "ta_poly_write");
|
||||
|
||||
CHECK(size % 32 == 0);
|
||||
|
||||
|
@ -577,9 +745,8 @@ static void ta_poly_fifo_write(struct ta *ta, uint32_t dst, void *ptr,
|
|||
PROF_LEAVE();
|
||||
}
|
||||
|
||||
static void ta_yuv_fifo_write(struct ta *ta, uint32_t dst, void *ptr,
|
||||
int size) {
|
||||
PROF_ENTER("cpu", "ta_yuv_fifo_write");
|
||||
static void ta_yuv_write(struct ta *ta, uint32_t dst, void *ptr, int size) {
|
||||
PROF_ENTER("cpu", "ta_yuv_write");
|
||||
|
||||
struct holly *holly = ta->holly;
|
||||
struct pvr *pvr = ta->pvr;
|
||||
|
@ -596,9 +763,8 @@ static void ta_yuv_fifo_write(struct ta *ta, uint32_t dst, void *ptr,
|
|||
PROF_LEAVE();
|
||||
}
|
||||
|
||||
static void ta_texture_fifo_write(struct ta *ta, uint32_t dst, void *ptr,
|
||||
int size) {
|
||||
PROF_ENTER("cpu", "ta_texture_fifo_write");
|
||||
static void ta_texture_write(struct ta *ta, uint32_t dst, void *ptr, int size) {
|
||||
PROF_ENTER("cpu", "ta_texture_write");
|
||||
|
||||
uint8_t *src = ptr;
|
||||
dst &= 0xeeffffff;
|
||||
|
@ -607,6 +773,9 @@ static void ta_texture_fifo_write(struct ta *ta, uint32_t dst, void *ptr,
|
|||
PROF_LEAVE();
|
||||
}
|
||||
|
||||
/*
|
||||
* ta device interface
|
||||
*/
|
||||
static int ta_init(struct device *dev) {
|
||||
struct ta *ta = (struct ta *)dev;
|
||||
struct dreamcast *dc = ta->dc;
|
||||
|
@ -614,7 +783,7 @@ static int ta_init(struct device *dev) {
|
|||
ta->video_ram = memory_translate(dc->memory, "video ram", 0x0);
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(ta->contexts); i++) {
|
||||
struct tile_context *ctx = &ta->contexts[i];
|
||||
struct ta_context *ctx = &ta->contexts[i];
|
||||
list_add(&ta->free_contexts, &ctx->it);
|
||||
}
|
||||
|
||||
|
@ -637,8 +806,8 @@ void ta_init_tables() {
|
|||
pcw.para_type = j;
|
||||
|
||||
for (int k = 0; k < TA_NUM_VERTS; k++) {
|
||||
g_param_sizes[i * TA_NUM_PARAMS * TA_NUM_VERTS + j * TA_NUM_VERTS + k] =
|
||||
ta_get_param_size_raw(pcw, k);
|
||||
int param_idx = i * TA_NUM_PARAMS * TA_NUM_VERTS + j * TA_NUM_VERTS + k;
|
||||
ta_param_sizes[param_idx] = ta_param_size_raw(pcw, k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -652,15 +821,26 @@ void ta_init_tables() {
|
|||
for (int k = 0; k < TA_NUM_LISTS; k++) {
|
||||
pcw.list_type = k;
|
||||
|
||||
g_poly_types[i * TA_NUM_PARAMS * TA_NUM_LISTS + j * TA_NUM_LISTS + k] =
|
||||
ta_get_poly_type_raw(pcw);
|
||||
g_vertex_types[i * TA_NUM_PARAMS * TA_NUM_LISTS + j * TA_NUM_LISTS +
|
||||
k] = ta_get_vert_type_raw(pcw);
|
||||
int poly_idx = i * TA_NUM_PARAMS * TA_NUM_LISTS + j * TA_NUM_LISTS + k;
|
||||
ta_poly_types[poly_idx] = ta_poly_type_raw(pcw);
|
||||
|
||||
int vert_idx = i * TA_NUM_PARAMS * TA_NUM_LISTS + j * TA_NUM_LISTS + k;
|
||||
ta_vert_types[vert_idx] = ta_vert_type_raw(pcw);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ta_texture_info(struct ta *ta, union tsp tsp, union tcw tcw,
|
||||
const uint8_t **texture, int *texture_size,
|
||||
const uint8_t **palette, int *palette_size) {
|
||||
uint32_t texture_addr = ta_texture_addr(tsp, tcw, texture_size);
|
||||
*texture = &ta->video_ram[texture_addr];
|
||||
|
||||
uint32_t palette_addr = ta_palette_addr(tcw, palette_size);
|
||||
*palette = *palette_size ? &ta->pvr->palette_ram[palette_addr] : NULL;
|
||||
}
|
||||
|
||||
void ta_destroy(struct ta *ta) {
|
||||
dc_destroy_device((struct device *)ta);
|
||||
}
|
||||
|
@ -673,6 +853,9 @@ struct ta *ta_create(struct dreamcast *dc) {
|
|||
return ta;
|
||||
}
|
||||
|
||||
/*
|
||||
* ta mmio registers
|
||||
*/
|
||||
REG_W32(pvr_cb, SOFTRESET) {
|
||||
struct ta *ta = dc->ta;
|
||||
|
||||
|
@ -690,7 +873,7 @@ REG_W32(pvr_cb, STARTRENDER) {
|
|||
return;
|
||||
}
|
||||
|
||||
struct tile_context *ctx =
|
||||
struct ta_context *ctx =
|
||||
ta_get_context(ta, ta->pvr->PARAM_BASE->base_address);
|
||||
CHECK_NOTNULL(ctx);
|
||||
ta_start_render(ta, ctx);
|
||||
|
@ -703,7 +886,7 @@ REG_W32(pvr_cb, TA_LIST_INIT) {
|
|||
return;
|
||||
}
|
||||
|
||||
struct tile_context *ctx =
|
||||
struct ta_context *ctx =
|
||||
ta_demand_context(ta, ta->pvr->TA_ISP_BASE->base_address);
|
||||
ta_init_context(ta, ctx);
|
||||
ta->curr_context = ctx;
|
||||
|
@ -716,7 +899,7 @@ REG_W32(pvr_cb, TA_LIST_CONT) {
|
|||
return;
|
||||
}
|
||||
|
||||
struct tile_context *ctx =
|
||||
struct ta_context *ctx =
|
||||
ta_get_context(ta, ta->pvr->TA_ISP_BASE->base_address);
|
||||
CHECK_NOTNULL(ctx);
|
||||
ta_cont_context(ta, ctx);
|
||||
|
@ -733,15 +916,15 @@ REG_W32(pvr_cb, TA_YUV_TEX_BASE) {
|
|||
}
|
||||
|
||||
/* clang-format off */
|
||||
AM_BEGIN(struct ta, ta_fifo_map);
|
||||
AM_BEGIN(struct ta, ta_data_map);
|
||||
AM_RANGE(0x00000000, 0x007fffff) AM_HANDLE("ta poly fifo",
|
||||
NULL, NULL, NULL,
|
||||
(mmio_write_string_cb)&ta_poly_fifo_write)
|
||||
(mmio_write_string_cb)&ta_poly_write)
|
||||
AM_RANGE(0x00800000, 0x00ffffff) AM_HANDLE("ta yuv fifo",
|
||||
NULL, NULL, NULL,
|
||||
(mmio_write_string_cb)&ta_yuv_fifo_write)
|
||||
(mmio_write_string_cb)&ta_yuv_write)
|
||||
AM_RANGE(0x01000000, 0x01ffffff) AM_HANDLE("ta texture fifo",
|
||||
NULL, NULL, NULL,
|
||||
(mmio_write_string_cb)&ta_texture_fifo_write)
|
||||
(mmio_write_string_cb)&ta_texture_write)
|
||||
AM_END();
|
||||
/* clang-format on */
|
||||
|
|
|
@ -8,29 +8,38 @@
|
|||
|
||||
struct dreamcast;
|
||||
struct ta;
|
||||
struct tr_provider;
|
||||
|
||||
DECLARE_COUNTER(ta_renders);
|
||||
|
||||
AM_DECLARE(ta_fifo_map);
|
||||
AM_DECLARE(ta_data_map);
|
||||
|
||||
extern int g_param_sizes[0x100 * TA_NUM_PARAMS * TA_NUM_VERTS];
|
||||
extern int g_poly_types[0x100 * TA_NUM_PARAMS * TA_NUM_LISTS];
|
||||
extern int g_vertex_types[0x100 * TA_NUM_PARAMS * TA_NUM_LISTS];
|
||||
struct ta *ta_create(struct dreamcast *dc);
|
||||
void ta_destroy(struct ta *ta);
|
||||
|
||||
static inline int ta_get_param_size(union pcw pcw, int vertex_type) {
|
||||
return g_param_sizes[pcw.obj_control * TA_NUM_PARAMS * TA_NUM_VERTS +
|
||||
pcw.para_type * TA_NUM_VERTS + vertex_type];
|
||||
void ta_texture_info(struct ta *ta, union tsp tsp, union tcw tcw,
|
||||
const uint8_t **texture, int *texture_size,
|
||||
const uint8_t **palette, int *palette_size);
|
||||
|
||||
/*
|
||||
* parameter stream processing helpers, shared by both the ta and tr
|
||||
*/
|
||||
extern int ta_param_sizes[0x100 * TA_NUM_PARAMS * TA_NUM_VERTS];
|
||||
extern int ta_poly_types[0x100 * TA_NUM_PARAMS * TA_NUM_LISTS];
|
||||
extern int ta_vert_types[0x100 * TA_NUM_PARAMS * TA_NUM_LISTS];
|
||||
|
||||
static inline int ta_param_size(union pcw pcw, int vert_type) {
|
||||
return ta_param_sizes[pcw.obj_control * TA_NUM_PARAMS * TA_NUM_VERTS +
|
||||
pcw.para_type * TA_NUM_VERTS + vert_type];
|
||||
}
|
||||
|
||||
static inline int ta_get_poly_type(union pcw pcw) {
|
||||
return g_poly_types[pcw.obj_control * TA_NUM_PARAMS * TA_NUM_LISTS +
|
||||
pcw.para_type * TA_NUM_LISTS + pcw.list_type];
|
||||
static inline int ta_poly_type(union pcw pcw) {
|
||||
return ta_poly_types[pcw.obj_control * TA_NUM_PARAMS * TA_NUM_LISTS +
|
||||
pcw.para_type * TA_NUM_LISTS + pcw.list_type];
|
||||
}
|
||||
|
||||
static inline int ta_get_vert_type(union pcw pcw) {
|
||||
return g_vertex_types[pcw.obj_control * TA_NUM_PARAMS * TA_NUM_LISTS +
|
||||
pcw.para_type * TA_NUM_LISTS + pcw.list_type];
|
||||
static inline int ta_vert_type(union pcw pcw) {
|
||||
return ta_vert_types[pcw.obj_control * TA_NUM_PARAMS * TA_NUM_LISTS +
|
||||
pcw.para_type * TA_NUM_LISTS + pcw.list_type];
|
||||
}
|
||||
|
||||
static inline int ta_pcw_list_type_valid(union pcw pcw, int current_list_type) {
|
||||
|
@ -42,71 +51,19 @@ static inline int ta_pcw_list_type_valid(union pcw pcw, int current_list_type) {
|
|||
pcw.para_type == TA_PARAM_SPRITE);
|
||||
}
|
||||
|
||||
static inline uint32_t ta_texture_addr(union tcw tcw) {
|
||||
return tcw.texture_addr << 3;
|
||||
}
|
||||
|
||||
static inline int ta_texture_twiddled(union tcw tcw) {
|
||||
return !tcw.scan_order ||
|
||||
/* paletted textures are always twiddled */
|
||||
tcw.pixel_fmt == TA_PXL_8BPP || tcw.pixel_fmt == TA_PXL_4BPP;
|
||||
}
|
||||
|
||||
static inline int ta_texture_compressed(union tcw tcw) {
|
||||
return tcw.vq_compressed;
|
||||
}
|
||||
|
||||
static inline int ta_texture_mipmaps(union tcw tcw) {
|
||||
return ta_texture_twiddled(tcw) && tcw.mip_mapped;
|
||||
}
|
||||
|
||||
static inline int ta_texture_width(union tsp tsp, union tcw tcw) {
|
||||
return 8 << tsp.texture_u_size;
|
||||
}
|
||||
|
||||
static inline int ta_texture_height(union tsp tsp, union tcw tcw) {
|
||||
int mipmaps = ta_texture_mipmaps(tcw);
|
||||
int height = 8 << tsp.texture_v_size;
|
||||
if (mipmaps) {
|
||||
height = ta_texture_width(tsp, tcw);
|
||||
}
|
||||
return height;
|
||||
}
|
||||
|
||||
static inline int ta_texture_bpp(union tcw tcw) {
|
||||
int bpp = 16;
|
||||
if (tcw.pixel_fmt == TA_PXL_8BPP) {
|
||||
bpp = 8;
|
||||
} else if (tcw.pixel_fmt == TA_PXL_4BPP) {
|
||||
bpp = 4;
|
||||
}
|
||||
return bpp;
|
||||
}
|
||||
|
||||
static inline int ta_texture_size(union tsp tsp, union tcw tcw) {
|
||||
int compressed = ta_texture_compressed(tcw);
|
||||
int mipmaps = ta_texture_mipmaps(tcw);
|
||||
int width = ta_texture_width(tsp, tcw);
|
||||
int height = ta_texture_height(tsp, tcw);
|
||||
int bpp = ta_texture_bpp(tcw);
|
||||
int texture_size = 0;
|
||||
if (compressed) {
|
||||
texture_size += PVR_CODEBOOK_SIZE;
|
||||
}
|
||||
int min_width = mipmaps ? 1 : width;
|
||||
for (int i = width; i >= min_width; i /= 2) {
|
||||
texture_size += (width * height * bpp) >> 3;
|
||||
}
|
||||
return texture_size;
|
||||
}
|
||||
|
||||
void ta_init_tables();
|
||||
|
||||
struct ta *ta_create(struct dreamcast *dc);
|
||||
void ta_destroy(struct ta *ta);
|
||||
|
||||
void ta_texture_info(struct ta *ta, union tsp tsp, union tcw tcw,
|
||||
const uint8_t **texture, int *texture_size,
|
||||
const uint8_t **palette, int *palette_size);
|
||||
/*
|
||||
* texture info helpers, shared by both the ta and tr
|
||||
*/
|
||||
uint32_t ta_texture_addr(union tsp tsp, union tcw tcw, int *size);
|
||||
uint32_t ta_palette_addr(union tcw tcw, int *size);
|
||||
int ta_texture_format(union tcw tcw);
|
||||
int ta_texture_compressed(union tcw tcw);
|
||||
int ta_texture_twiddled(union tcw tcw);
|
||||
int ta_texture_mipmaps(union tcw tcw);
|
||||
int ta_texture_width(union tsp tsp, union tcw tcw);
|
||||
int ta_texture_height(union tsp tsp, union tcw tcw);
|
||||
int ta_texture_stride(union tsp tsp, union tcw tcw, int stride);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,7 +3,11 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include "core/list.h"
|
||||
#include "core/rb_tree.h"
|
||||
|
||||
#define TA_MAX_PARAMS 0x10000
|
||||
|
||||
/* worst case background vertex size, see ISP_BACKGND_T field */
|
||||
#define TA_BG_VERTEX_SIZE ((0b111 * 2 + 3) * 4 * 3)
|
||||
|
||||
enum {
|
||||
/* control params */
|
||||
|
@ -33,24 +37,6 @@ enum {
|
|||
TA_NUM_LISTS,
|
||||
};
|
||||
|
||||
enum {
|
||||
TA_PXL_1555,
|
||||
TA_PXL_565,
|
||||
TA_PXL_4444,
|
||||
TA_PXL_YUV422,
|
||||
TA_PXL_BUMPMAP,
|
||||
TA_PXL_4BPP,
|
||||
TA_PXL_8BPP,
|
||||
TA_PXL_RESERVED,
|
||||
};
|
||||
|
||||
enum {
|
||||
TA_PAL_ARGB1555,
|
||||
TA_PAL_RGB565,
|
||||
TA_PAL_ARGB4444,
|
||||
TA_PAL_ARGB8888,
|
||||
};
|
||||
|
||||
union pcw {
|
||||
struct {
|
||||
/* obj control */
|
||||
|
@ -77,7 +63,7 @@ union pcw {
|
|||
uint32_t full;
|
||||
};
|
||||
|
||||
/* Image Synthesis Processor parameters */
|
||||
/* image synthesis processor parameters */
|
||||
union isp {
|
||||
struct {
|
||||
uint32_t : 20;
|
||||
|
@ -94,7 +80,7 @@ union isp {
|
|||
uint32_t full;
|
||||
};
|
||||
|
||||
/* Texture and Shading Processor parameters */
|
||||
/* texture and shading processor parameters */
|
||||
union tsp {
|
||||
struct {
|
||||
uint32_t texture_v_size : 3;
|
||||
|
@ -119,7 +105,7 @@ union tsp {
|
|||
uint32_t full;
|
||||
};
|
||||
|
||||
/* Texture parameters */
|
||||
/* texture parameters */
|
||||
union tcw {
|
||||
/* rgb, yuv and bumpmap textures */
|
||||
struct {
|
||||
|
@ -430,15 +416,7 @@ union vert_param {
|
|||
} sprite1;
|
||||
};
|
||||
|
||||
/* shared by tracer */
|
||||
#define TA_MAX_SURFS (1024 * 16)
|
||||
#define TA_MAX_VERTS (1024 * 64)
|
||||
#define TA_MAX_PARAMS 0x10000
|
||||
|
||||
/* worst case background vertex size, see ISP_BACKGND_T field */
|
||||
#define TA_BG_VERTEX_SIZE ((0b111 * 2 + 3) * 4 * 3)
|
||||
|
||||
struct tile_context {
|
||||
struct ta_context {
|
||||
void *user;
|
||||
uint32_t addr;
|
||||
void *userdata;
|
||||
|
@ -463,7 +441,7 @@ struct tile_context {
|
|||
|
||||
/* current global state */
|
||||
int list_type;
|
||||
int vertex_type;
|
||||
int vert_type;
|
||||
|
||||
struct list_node it;
|
||||
};
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
/*
|
||||
* tile accelerator rendering
|
||||
*
|
||||
* responsible for parsing a context generated by the ta frontend into draw
|
||||
* commands to be passed to the host's render backend
|
||||
*/
|
||||
|
||||
#include "guest/pvr/tr.h"
|
||||
#include "core/assert.h"
|
||||
#include "core/core.h"
|
||||
|
@ -16,7 +23,7 @@ struct tr {
|
|||
const union poly_param *last_poly;
|
||||
const union vert_param *last_vertex;
|
||||
int list_type;
|
||||
int vertex_type;
|
||||
int vert_type;
|
||||
float face_color[4];
|
||||
float face_offset_color[4];
|
||||
int merged_surfs;
|
||||
|
@ -118,7 +125,7 @@ static inline uint32_t float_to_rgba(float r, float g, float b, float a) {
|
|||
}
|
||||
|
||||
static texture_handle_t tr_convert_texture(struct tr *tr,
|
||||
const struct tile_context *ctx,
|
||||
const struct ta_context *ctx,
|
||||
union tsp tsp, union tcw tcw) {
|
||||
PROF_ENTER("gpu", "tr_convert_texture");
|
||||
|
||||
|
@ -146,47 +153,13 @@ static texture_handle_t tr_convert_texture(struct tr *tr,
|
|||
const uint8_t *texture = entry->texture;
|
||||
|
||||
/* get texture dimensions */
|
||||
int compressed = ta_texture_compressed(tcw);
|
||||
int twiddled = ta_texture_twiddled(tcw);
|
||||
int texture_fmt = ta_texture_format(tcw);
|
||||
int mipmaps = ta_texture_mipmaps(tcw);
|
||||
int width = ta_texture_width(tsp, tcw);
|
||||
int height = ta_texture_height(tsp, tcw);
|
||||
int stride = width;
|
||||
if (!twiddled && tcw.stride_select) {
|
||||
stride = ctx->stride;
|
||||
}
|
||||
int stride = ta_texture_stride(tsp, tcw, ctx->stride);
|
||||
|
||||
/* figure out the texture format */
|
||||
int texture_fmt = PVR_TEX_INVALID;
|
||||
|
||||
if (compressed) {
|
||||
if (mipmaps) {
|
||||
texture_fmt = PVR_TEX_VQ_MIPMAPS;
|
||||
} else {
|
||||
texture_fmt = PVR_TEX_VQ;
|
||||
}
|
||||
} else if (tcw.pixel_fmt == TA_PXL_4BPP) {
|
||||
if (mipmaps) {
|
||||
texture_fmt = PVR_TEX_PALETTE_4BPP_MIPMAPS;
|
||||
} else {
|
||||
texture_fmt = PVR_TEX_PALETTE_4BPP;
|
||||
}
|
||||
} else if (tcw.pixel_fmt == TA_PXL_8BPP) {
|
||||
if (mipmaps) {
|
||||
texture_fmt = PVR_TEX_PALETTE_8BPP_MIPMAPS;
|
||||
} else {
|
||||
texture_fmt = PVR_TEX_PALETTE_8BPP;
|
||||
}
|
||||
} else if (twiddled) {
|
||||
if (mipmaps) {
|
||||
texture_fmt = PVR_TEX_TWIDDLED_MIPMAPS;
|
||||
} else {
|
||||
texture_fmt = PVR_TEX_TWIDDLED;
|
||||
}
|
||||
} else {
|
||||
texture_fmt = PVR_TEX_BITMAP;
|
||||
}
|
||||
|
||||
pvr_tex_decode(texture, width, height, stride, texture_fmt, tcw.pixel_fmt,
|
||||
palette, ctx->palette_fmt, converted, sizeof(converted));
|
||||
|
||||
|
@ -361,9 +334,8 @@ static void tr_commit_surf(struct tr *tr, struct tr_context *rc) {
|
|||
tr->face_offset_color[3]); \
|
||||
}
|
||||
|
||||
static int tr_parse_bg_vert(const struct tile_context *ctx,
|
||||
struct tr_context *rc, int offset,
|
||||
struct ta_vertex *v) {
|
||||
static int tr_parse_bg_vert(const struct ta_context *ctx, struct tr_context *rc,
|
||||
int offset, struct ta_vertex *v) {
|
||||
PARSE_XYZ(*(float *)&ctx->bg_vertices[offset],
|
||||
*(float *)&ctx->bg_vertices[offset + 4],
|
||||
*(float *)&ctx->bg_vertices[offset + 8], v->xyz);
|
||||
|
@ -393,7 +365,7 @@ static int tr_parse_bg_vert(const struct tile_context *ctx,
|
|||
return offset;
|
||||
}
|
||||
|
||||
static void tr_parse_bg(struct tr *tr, const struct tile_context *ctx,
|
||||
static void tr_parse_bg(struct tr *tr, const struct ta_context *ctx,
|
||||
struct tr_context *rc) {
|
||||
tr->list_type = TA_LIST_OPAQUE;
|
||||
|
||||
|
@ -438,16 +410,16 @@ static void tr_parse_bg(struct tr *tr, const struct tile_context *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_context *ctx,
|
||||
static void tr_parse_poly_param(struct tr *tr, const struct ta_context *ctx,
|
||||
struct tr_context *rc, const uint8_t *data) {
|
||||
const union poly_param *param = (const union poly_param *)data;
|
||||
|
||||
/* reset state */
|
||||
tr->last_poly = param;
|
||||
tr->last_vertex = NULL;
|
||||
tr->vertex_type = ta_get_vert_type(param->type0.pcw);
|
||||
tr->vert_type = ta_vert_type(param->type0.pcw);
|
||||
|
||||
int poly_type = ta_get_poly_type(param->type0.pcw);
|
||||
int poly_type = ta_poly_type(param->type0.pcw);
|
||||
|
||||
if (poly_type == 6) {
|
||||
/* FIXME handle modifier volumes */
|
||||
|
@ -533,11 +505,11 @@ static void tr_parse_poly_param(struct tr *tr, const struct tile_context *ctx,
|
|||
}
|
||||
}
|
||||
|
||||
static void tr_parse_vert_param(struct tr *tr, const struct tile_context *ctx,
|
||||
static void tr_parse_vert_param(struct tr *tr, const struct ta_context *ctx,
|
||||
struct tr_context *rc, const uint8_t *data) {
|
||||
const union vert_param *param = (const union vert_param *)data;
|
||||
|
||||
if (tr->vertex_type == 17) {
|
||||
if (tr->vert_type == 17) {
|
||||
/* FIXME handle modifier volumes */
|
||||
return;
|
||||
}
|
||||
|
@ -550,7 +522,7 @@ static void tr_parse_vert_param(struct tr *tr, const struct tile_context *ctx,
|
|||
}
|
||||
tr->last_vertex = param;
|
||||
|
||||
switch (tr->vertex_type) {
|
||||
switch (tr->vert_type) {
|
||||
case 0: {
|
||||
struct ta_vertex *vert = tr_reserve_vert(tr, rc);
|
||||
PARSE_XYZ(param->type0.xyz[0], param->type0.xyz[1], param->type0.xyz[2],
|
||||
|
@ -714,7 +686,7 @@ static void tr_parse_vert_param(struct tr *tr, const struct tile_context *ctx,
|
|||
} break;
|
||||
|
||||
default:
|
||||
LOG_FATAL("unsupported vertex type %d", tr->vertex_type);
|
||||
LOG_FATAL("unsupported vertex type %d", tr->vert_type);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -729,8 +701,8 @@ static void tr_parse_vert_param(struct tr *tr, const struct tile_context *ctx,
|
|||
}
|
||||
|
||||
/* scratch buffers used by surface merge sort */
|
||||
static int sort_tmp[TA_MAX_SURFS];
|
||||
static float sort_minz[TA_MAX_SURFS];
|
||||
static int sort_tmp[TR_MAX_SURFS];
|
||||
static float sort_minz[TR_MAX_SURFS];
|
||||
|
||||
static int tr_compare_surf(const void *a, const void *b) {
|
||||
int i = *(const int *)a;
|
||||
|
@ -767,12 +739,12 @@ static void tr_sort_render_list(struct tr *tr, struct tr_context *rc,
|
|||
PROF_LEAVE();
|
||||
}
|
||||
|
||||
static void tr_parse_eol(struct tr *tr, const struct tile_context *ctx,
|
||||
static void tr_parse_eol(struct tr *tr, const struct ta_context *ctx,
|
||||
struct tr_context *rc, const uint8_t *data) {
|
||||
tr->last_poly = NULL;
|
||||
tr->last_vertex = NULL;
|
||||
tr->list_type = TA_NUM_LISTS;
|
||||
tr->vertex_type = TA_NUM_VERTS;
|
||||
tr->vert_type = TA_NUM_VERTS;
|
||||
}
|
||||
|
||||
static void tr_reset(struct tr *tr, struct tr_context *rc) {
|
||||
|
@ -780,7 +752,7 @@ static void tr_reset(struct tr *tr, struct tr_context *rc) {
|
|||
tr->last_poly = NULL;
|
||||
tr->last_vertex = NULL;
|
||||
tr->list_type = TA_NUM_LISTS;
|
||||
tr->vertex_type = TA_NUM_VERTS;
|
||||
tr->vert_type = TA_NUM_VERTS;
|
||||
tr->merged_surfs = 0;
|
||||
|
||||
/* reset render context state */
|
||||
|
@ -841,7 +813,7 @@ void tr_render_context(struct render_backend *r, const struct tr_context *rc) {
|
|||
|
||||
void tr_convert_context(struct render_backend *r, void *userdata,
|
||||
tr_find_texture_cb find_texture,
|
||||
const struct tile_context *ctx, struct tr_context *rc) {
|
||||
const struct ta_context *ctx, struct tr_context *rc) {
|
||||
PROF_ENTER("gpu", "tr_convert_context");
|
||||
|
||||
struct tr tr;
|
||||
|
@ -897,11 +869,11 @@ void tr_convert_context(struct render_backend *r, void *userdata,
|
|||
struct tr_param *rp = &rc->params[rc->num_params++];
|
||||
rp->offset = (int)(data - ctx->params);
|
||||
rp->list_type = tr.list_type;
|
||||
rp->vertex_type = tr.list_type;
|
||||
rp->vert_type = tr.list_type;
|
||||
rp->last_surf = rc->num_surfs - 1;
|
||||
rp->last_vert = rc->num_verts - 1;
|
||||
|
||||
data += ta_get_param_size(pcw, tr.vertex_type);
|
||||
data += ta_param_size(pcw, tr.vert_type);
|
||||
}
|
||||
|
||||
/* sort blended surface lists if requested */
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
#ifndef TR_H
|
||||
#define TR_H
|
||||
|
||||
/* tile renderer code. responsible for parsing a raw tile_context into
|
||||
draw commands to be passed to the supplied render backend */
|
||||
|
||||
#include "core/rb_tree.h"
|
||||
#include "guest/pvr/ta_types.h"
|
||||
#include "render/render_backend.h"
|
||||
|
||||
struct tr;
|
||||
struct tr_texture;
|
||||
|
||||
#define TR_MAX_SURFS (1024 * 16)
|
||||
#define TR_MAX_VERTS (1024 * 64)
|
||||
|
||||
typedef uint64_t tr_texture_key_t;
|
||||
|
||||
|
@ -36,18 +34,18 @@ struct tr_texture {
|
|||
};
|
||||
|
||||
struct tr_param {
|
||||
/* offset of parameter in tile_context param stream */
|
||||
/* offset of parameter in ta_context param stream */
|
||||
int offset;
|
||||
/* global list and vertex types at time of parsing */
|
||||
int list_type;
|
||||
int vertex_type;
|
||||
int vert_type;
|
||||
/* last surf / vert generated for the param */
|
||||
int last_surf;
|
||||
int last_vert;
|
||||
};
|
||||
|
||||
struct tr_list {
|
||||
int surfs[TA_MAX_SURFS];
|
||||
int surfs[TR_MAX_SURFS];
|
||||
int num_surfs;
|
||||
};
|
||||
|
||||
|
@ -57,13 +55,13 @@ struct tr_context {
|
|||
int height;
|
||||
|
||||
/* parsed surfaces and vertices, ready to be passed to the render backend */
|
||||
struct ta_surface surfs[TA_MAX_SURFS];
|
||||
struct ta_surface surfs[TR_MAX_SURFS];
|
||||
int num_surfs;
|
||||
|
||||
struct ta_vertex verts[TA_MAX_VERTS];
|
||||
struct ta_vertex verts[TR_MAX_VERTS];
|
||||
int num_verts;
|
||||
|
||||
uint16_t indices[TA_MAX_VERTS * 3];
|
||||
uint16_t indices[TR_MAX_VERTS * 3];
|
||||
int num_indices;
|
||||
|
||||
/* sorted list of surfaces corresponding to each of the ta's polygon lists */
|
||||
|
@ -82,7 +80,7 @@ typedef struct tr_texture *(*tr_find_texture_cb)(void *, union tsp, union tcw);
|
|||
|
||||
void tr_convert_context(struct render_backend *r, void *userdata,
|
||||
tr_find_texture_cb find_texture,
|
||||
const struct tile_context *ctx, struct tr_context *rc);
|
||||
const struct ta_context *ctx, struct tr_context *rc);
|
||||
void tr_render_context(struct render_backend *r, const struct tr_context *rc);
|
||||
void tr_render_context_until(struct render_backend *r,
|
||||
const struct tr_context *rc, int end_surf);
|
||||
|
|
|
@ -403,7 +403,7 @@ AM_BEGIN(struct sh4, sh4_data_map)
|
|||
AM_RANGE(0x01000000, 0x01ffffff) AM_DEVICE("holly", holly_expansion0_map)
|
||||
AM_RANGE(0x02700000, 0x02ffffff) AM_DEVICE("holly", holly_expansion1_map)
|
||||
AM_RANGE(0x04000000, 0x057fffff) AM_DEVICE("pvr", pvr_vram_map)
|
||||
AM_RANGE(0x10000000, 0x11ffffff) AM_DEVICE("ta", ta_fifo_map)
|
||||
AM_RANGE(0x10000000, 0x11ffffff) AM_DEVICE("ta", ta_data_map)
|
||||
AM_RANGE(0x14000000, 0x17ffffff) AM_DEVICE("holly", holly_expansion2_map)
|
||||
|
||||
/* internal registers */
|
||||
|
|
12
src/tracer.c
12
src/tracer.c
|
@ -1,5 +1,6 @@
|
|||
#include "tracer.h"
|
||||
#include "core/math.h"
|
||||
#include "core/rb_tree.h"
|
||||
#include "file/trace.h"
|
||||
#include "guest/pvr/ta.h"
|
||||
#include "guest/pvr/tr.h"
|
||||
|
@ -98,7 +99,7 @@ struct tracer {
|
|||
|
||||
/* trace state */
|
||||
struct trace *trace;
|
||||
struct tile_context ctx;
|
||||
struct ta_context ctx;
|
||||
struct trace_cmd *current_cmd;
|
||||
int frame;
|
||||
int current_param;
|
||||
|
@ -346,7 +347,7 @@ static void tracer_param_tooltip(struct tracer *tracer, struct tr_param *rp) {
|
|||
igText("tsp: 0x%x", param->type0.tsp.full);
|
||||
igText("tcw: 0x%x", param->type0.tcw.full);
|
||||
|
||||
int poly_type = ta_get_poly_type(param->type0.pcw);
|
||||
int poly_type = ta_poly_type(param->type0.pcw);
|
||||
|
||||
igText("poly type: %d", poly_type);
|
||||
|
||||
|
@ -378,9 +379,9 @@ static void tracer_param_tooltip(struct tracer *tracer, struct tr_param *rp) {
|
|||
const union vert_param *param =
|
||||
(const union vert_param *)(tracer->ctx.params + rp->offset);
|
||||
|
||||
igText("vert type: %d", rp->vertex_type);
|
||||
igText("vert type: %d", rp->vert_type);
|
||||
|
||||
switch (rp->vertex_type) {
|
||||
switch (rp->vert_type) {
|
||||
case 0:
|
||||
igText("xyz: {%.2f, %.2f, %f}", param->type0.xyz[0],
|
||||
param->type0.xyz[1], param->type0.xyz[2]);
|
||||
|
@ -610,9 +611,6 @@ static void tracer_render_side_menu(struct tracer *tracer) {
|
|||
igText("filter: %s", filter_names[tex->filter]);
|
||||
igText("wrap_u: %s", wrap_names[tex->wrap_u]);
|
||||
igText("wrap_v: %s", wrap_names[tex->wrap_v]);
|
||||
igText("twiddled: %d", ta_texture_twiddled(tex->tcw));
|
||||
igText("compressed: %d", ta_texture_compressed(tex->tcw));
|
||||
igText("mipmaps: %d", ta_texture_mipmaps(tex->tcw));
|
||||
igText("width: %d", tex->width);
|
||||
igText("height: %d", tex->height);
|
||||
|
||||
|
|
Loading…
Reference in New Issue