#include /* 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", }; static const char *cmd_name(unsigned cmd) { assert(Elements(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 + plane[nr_planes].dcdy * tiley - 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 += 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); } } } }