#include <inttypes.h> /* for PRIu64 macro */
|
#include "util/u_math.h"
|
#include "lp_rast_priv.h"
|
#include "lp_state_fs.h"
|
|
struct tile {
|
int coverage;
|
int overdraw;
|
const struct lp_rast_state *state;
|
char data[TILE_SIZE][TILE_SIZE];
|
};
|
|
static char get_label( int i )
|
{
|
static const char *cmd_labels = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
unsigned max_label = (2*26+10);
|
|
if (i < max_label)
|
return cmd_labels[i];
|
else
|
return '?';
|
}
|
|
|
|
static const char *cmd_names[LP_RAST_OP_MAX] =
|
{
|
"clear_color",
|
"clear_zstencil",
|
"triangle_1",
|
"triangle_2",
|
"triangle_3",
|
"triangle_4",
|
"triangle_5",
|
"triangle_6",
|
"triangle_7",
|
"triangle_8",
|
"triangle_3_4",
|
"triangle_3_16",
|
"triangle_4_16",
|
"shade_tile",
|
"shade_tile_opaque",
|
"begin_query",
|
"end_query",
|
"set_state",
|
"triangle_32_1",
|
"triangle_32_2",
|
"triangle_32_3",
|
"triangle_32_4",
|
"triangle_32_5",
|
"triangle_32_6",
|
"triangle_32_7",
|
"triangle_32_8",
|
"triangle_32_3_4",
|
"triangle_32_3_16",
|
"triangle_32_4_16",
|
};
|
|
static const char *cmd_name(unsigned cmd)
|
{
|
assert(ARRAY_SIZE(cmd_names) > cmd);
|
return cmd_names[cmd];
|
}
|
|
static const struct lp_fragment_shader_variant *
|
get_variant( const struct lp_rast_state *state,
|
const struct cmd_block *block,
|
int k )
|
{
|
if (!state)
|
return NULL;
|
|
if (block->cmd[k] == LP_RAST_OP_SHADE_TILE ||
|
block->cmd[k] == LP_RAST_OP_SHADE_TILE_OPAQUE ||
|
block->cmd[k] == LP_RAST_OP_TRIANGLE_1 ||
|
block->cmd[k] == LP_RAST_OP_TRIANGLE_2 ||
|
block->cmd[k] == LP_RAST_OP_TRIANGLE_3 ||
|
block->cmd[k] == LP_RAST_OP_TRIANGLE_4 ||
|
block->cmd[k] == LP_RAST_OP_TRIANGLE_5 ||
|
block->cmd[k] == LP_RAST_OP_TRIANGLE_6 ||
|
block->cmd[k] == LP_RAST_OP_TRIANGLE_7)
|
return state->variant;
|
|
return NULL;
|
}
|
|
|
static boolean
|
is_blend( const struct lp_rast_state *state,
|
const struct cmd_block *block,
|
int k )
|
{
|
const struct lp_fragment_shader_variant *variant = get_variant(state, block, k);
|
|
if (variant)
|
return variant->key.blend.rt[0].blend_enable;
|
|
return FALSE;
|
}
|
|
|
|
static void
|
debug_bin( const struct cmd_bin *bin, int x, int y )
|
{
|
const struct lp_rast_state *state = NULL;
|
const struct cmd_block *head = bin->head;
|
int i, j = 0;
|
|
debug_printf("bin %d,%d:\n", x, y);
|
|
while (head) {
|
for (i = 0; i < head->count; i++, j++) {
|
if (head->cmd[i] == LP_RAST_OP_SET_STATE)
|
state = head->arg[i].state;
|
|
debug_printf("%d: %s %s\n", j,
|
cmd_name(head->cmd[i]),
|
is_blend(state, head, i) ? "blended" : "");
|
}
|
head = head->next;
|
}
|
}
|
|
|
static void plot(struct tile *tile,
|
int x, int y,
|
char val,
|
boolean blend)
|
{
|
if (tile->data[x][y] == ' ')
|
tile->coverage++;
|
else
|
tile->overdraw++;
|
|
tile->data[x][y] = val;
|
}
|
|
|
|
|
|
|
static int
|
debug_shade_tile(int x, int y,
|
const union lp_rast_cmd_arg arg,
|
struct tile *tile,
|
char val)
|
{
|
const struct lp_rast_shader_inputs *inputs = arg.shade_tile;
|
boolean blend;
|
unsigned i,j;
|
|
if (!tile->state)
|
return 0;
|
|
blend = tile->state->variant->key.blend.rt[0].blend_enable;
|
|
if (inputs->disable)
|
return 0;
|
|
for (i = 0; i < TILE_SIZE; i++)
|
for (j = 0; j < TILE_SIZE; j++)
|
plot(tile, i, j, val, blend);
|
|
return TILE_SIZE * TILE_SIZE;
|
}
|
|
static int
|
debug_clear_tile(int x, int y,
|
const union lp_rast_cmd_arg arg,
|
struct tile *tile,
|
char val)
|
{
|
unsigned i,j;
|
|
for (i = 0; i < TILE_SIZE; i++)
|
for (j = 0; j < TILE_SIZE; j++)
|
plot(tile, i, j, val, FALSE);
|
|
return TILE_SIZE * TILE_SIZE;
|
|
}
|
|
|
static int
|
debug_triangle(int tilex, int tiley,
|
const union lp_rast_cmd_arg arg,
|
struct tile *tile,
|
char val)
|
{
|
const struct lp_rast_triangle *tri = arg.triangle.tri;
|
unsigned plane_mask = arg.triangle.plane_mask;
|
const struct lp_rast_plane *tri_plane = GET_PLANES(tri);
|
struct lp_rast_plane plane[8];
|
int x, y;
|
int count = 0;
|
unsigned i, nr_planes = 0;
|
boolean blend = tile->state->variant->key.blend.rt[0].blend_enable;
|
|
if (tri->inputs.disable) {
|
/* This triangle was partially binned and has been disabled */
|
return 0;
|
}
|
|
while (plane_mask) {
|
plane[nr_planes] = tri_plane[u_bit_scan(&plane_mask)];
|
plane[nr_planes].c = (plane[nr_planes].c +
|
IMUL64(plane[nr_planes].dcdy, tiley) -
|
IMUL64(plane[nr_planes].dcdx, tilex));
|
nr_planes++;
|
}
|
|
for(y = 0; y < TILE_SIZE; y++)
|
{
|
for(x = 0; x < TILE_SIZE; x++)
|
{
|
for (i = 0; i < nr_planes; i++)
|
if (plane[i].c <= 0)
|
goto out;
|
|
plot(tile, x, y, val, blend);
|
count++;
|
|
out:
|
for (i = 0; i < nr_planes; i++)
|
plane[i].c -= plane[i].dcdx;
|
}
|
|
for (i = 0; i < nr_planes; i++) {
|
plane[i].c += IMUL64(plane[i].dcdx, TILE_SIZE);
|
plane[i].c += plane[i].dcdy;
|
}
|
}
|
return count;
|
}
|
|
|
|
|
|
static void
|
do_debug_bin( struct tile *tile,
|
const struct cmd_bin *bin,
|
int x, int y,
|
boolean print_cmds)
|
{
|
unsigned k, j = 0;
|
const struct cmd_block *block;
|
|
int tx = x * TILE_SIZE;
|
int ty = y * TILE_SIZE;
|
|
memset(tile->data, ' ', sizeof tile->data);
|
tile->coverage = 0;
|
tile->overdraw = 0;
|
tile->state = NULL;
|
|
for (block = bin->head; block; block = block->next) {
|
for (k = 0; k < block->count; k++, j++) {
|
boolean blend = is_blend(tile->state, block, k);
|
char val = get_label(j);
|
int count = 0;
|
|
if (print_cmds)
|
debug_printf("%c: %15s", val, cmd_name(block->cmd[k]));
|
|
if (block->cmd[k] == LP_RAST_OP_SET_STATE)
|
tile->state = block->arg[k].state;
|
|
if (block->cmd[k] == LP_RAST_OP_CLEAR_COLOR ||
|
block->cmd[k] == LP_RAST_OP_CLEAR_ZSTENCIL)
|
count = debug_clear_tile(tx, ty, block->arg[k], tile, val);
|
|
if (block->cmd[k] == LP_RAST_OP_SHADE_TILE ||
|
block->cmd[k] == LP_RAST_OP_SHADE_TILE_OPAQUE)
|
count = debug_shade_tile(tx, ty, block->arg[k], tile, val);
|
|
if (block->cmd[k] == LP_RAST_OP_TRIANGLE_1 ||
|
block->cmd[k] == LP_RAST_OP_TRIANGLE_2 ||
|
block->cmd[k] == LP_RAST_OP_TRIANGLE_3 ||
|
block->cmd[k] == LP_RAST_OP_TRIANGLE_4 ||
|
block->cmd[k] == LP_RAST_OP_TRIANGLE_5 ||
|
block->cmd[k] == LP_RAST_OP_TRIANGLE_6 ||
|
block->cmd[k] == LP_RAST_OP_TRIANGLE_7)
|
count = debug_triangle(tx, ty, block->arg[k], tile, val);
|
|
if (print_cmds) {
|
debug_printf(" % 5d", count);
|
|
if (blend)
|
debug_printf(" blended");
|
|
debug_printf("\n");
|
}
|
}
|
}
|
}
|
|
void
|
lp_debug_bin( const struct cmd_bin *bin, int i, int j)
|
{
|
struct tile tile;
|
int x,y;
|
|
if (bin->head) {
|
do_debug_bin(&tile, bin, i, j, TRUE);
|
|
debug_printf("------------------------------------------------------------------\n");
|
for (y = 0; y < TILE_SIZE; y++) {
|
for (x = 0; x < TILE_SIZE; x++) {
|
debug_printf("%c", tile.data[y][x]);
|
}
|
debug_printf("|\n");
|
}
|
debug_printf("------------------------------------------------------------------\n");
|
|
debug_printf("each pixel drawn avg %f times\n",
|
((float)tile.overdraw + tile.coverage)/(float)tile.coverage);
|
}
|
}
|
|
|
|
|
|
|
/** Return number of bytes used for a single bin */
|
static unsigned
|
lp_scene_bin_size( const struct lp_scene *scene, unsigned x, unsigned y )
|
{
|
struct cmd_bin *bin = lp_scene_get_bin((struct lp_scene *) scene, x, y);
|
const struct cmd_block *cmd;
|
unsigned size = 0;
|
for (cmd = bin->head; cmd; cmd = cmd->next) {
|
size += (cmd->count *
|
(sizeof(uint8_t) + sizeof(union lp_rast_cmd_arg)));
|
}
|
return size;
|
}
|
|
|
|
void
|
lp_debug_draw_bins_by_coverage( struct lp_scene *scene )
|
{
|
unsigned x, y;
|
unsigned total = 0;
|
unsigned possible = 0;
|
static uint64_t _total = 0;
|
static uint64_t _possible = 0;
|
|
for (x = 0; x < scene->tiles_x; x++)
|
debug_printf("-");
|
debug_printf("\n");
|
|
for (y = 0; y < scene->tiles_y; y++) {
|
for (x = 0; x < scene->tiles_x; x++) {
|
struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);
|
const char *bits = "0123456789";
|
struct tile tile;
|
|
if (bin->head) {
|
//lp_debug_bin(bin, x, y);
|
|
do_debug_bin(&tile, bin, x, y, FALSE);
|
|
total += tile.coverage;
|
possible += 64*64;
|
|
if (tile.coverage == 64*64)
|
debug_printf("*");
|
else if (tile.coverage) {
|
int bit = tile.coverage/(64.0*64.0)*10;
|
debug_printf("%c", bits[MIN2(bit,10)]);
|
}
|
else
|
debug_printf("?");
|
}
|
else {
|
debug_printf(" ");
|
}
|
}
|
debug_printf("|\n");
|
}
|
|
for (x = 0; x < scene->tiles_x; x++)
|
debug_printf("-");
|
debug_printf("\n");
|
|
debug_printf("this tile total: %u possible %u: percentage: %f\n",
|
total,
|
possible,
|
total * 100.0 / (float)possible);
|
|
_total += total;
|
_possible += possible;
|
|
|
debug_printf("overall total: %" PRIu64
|
" possible %" PRIu64 ": percentage: %f\n",
|
_total,
|
_possible,
|
(double) _total * 100.0 / (double)_possible);
|
}
|
|
|
void
|
lp_debug_draw_bins_by_cmd_length( struct lp_scene *scene )
|
{
|
unsigned x, y;
|
|
for (y = 0; y < scene->tiles_y; y++) {
|
for (x = 0; x < scene->tiles_x; x++) {
|
const char *bits = " ...,-~:;=o+xaw*#XAWWWWWWWWWWWWWWWW";
|
unsigned sz = lp_scene_bin_size(scene, x, y);
|
unsigned sz2 = util_logbase2(sz);
|
debug_printf("%c", bits[MIN2(sz2,32)]);
|
}
|
debug_printf("\n");
|
}
|
}
|
|
|
void
|
lp_debug_bins( struct lp_scene *scene )
|
{
|
unsigned x, y;
|
|
for (y = 0; y < scene->tiles_y; y++) {
|
for (x = 0; x < scene->tiles_x; x++) {
|
struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);
|
if (bin->head) {
|
debug_bin(bin, x, y);
|
}
|
}
|
}
|
}
|