X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fdrivers%2Ffreedreno%2Ffreedreno_gmem.c;h=6119f564400c51de3499e8225e489d582ec38920;hb=3bb61e21f8bf290773897778fbf391775ba706b9;hp=5bf809e652d8a9df4e16ba336c19f770364a172a;hpb=ef5f238fd08bb470e0f6327ec76723d37704f13f;p=mesa.git diff --git a/src/gallium/drivers/freedreno/freedreno_gmem.c b/src/gallium/drivers/freedreno/freedreno_gmem.c index 5bf809e652d..6119f564400 100644 --- a/src/gallium/drivers/freedreno/freedreno_gmem.c +++ b/src/gallium/drivers/freedreno/freedreno_gmem.c @@ -69,7 +69,9 @@ * resolve. */ -#define BIN_DEBUG 0 +#ifndef BIN_DEBUG +# define BIN_DEBUG 0 +#endif /* * GMEM Cache: @@ -169,97 +171,125 @@ static uint32_t bin_width(struct fd_screen *screen) static unsigned div_align(unsigned num, unsigned denom, unsigned al) { - return align(DIV_ROUND_UP(num, denom), al); + return util_align_npot(DIV_ROUND_UP(num, denom), al); } -static uint32_t -total_size(struct gmem_key *key, uint32_t bin_w, uint32_t bin_h, +static bool +layout_gmem(struct gmem_key *key, uint32_t nbins_x, uint32_t nbins_y, struct fd_gmem_stateobj *gmem) { + struct fd_screen *screen = gmem->screen; uint32_t gmem_align = key->gmem_page_align * 0x1000; uint32_t total = 0, i; + if ((nbins_x == 0) || (nbins_y == 0)) + return false; + + uint32_t bin_w, bin_h; + bin_w = div_align(key->width, nbins_x, screen->tile_alignw); + bin_h = div_align(key->height, nbins_y, screen->tile_alignh); + + gmem->bin_w = bin_w; + gmem->bin_h = bin_h; + + /* due to aligning bin_w/h, we could end up with one too + * many bins in either dimension, so recalculate: + */ + gmem->nbins_x = DIV_ROUND_UP(key->width, bin_w); + gmem->nbins_y = DIV_ROUND_UP(key->height, bin_h); + for (i = 0; i < MAX_RENDER_TARGETS; i++) { if (key->cbuf_cpp[i]) { - gmem->cbuf_base[i] = align(total, gmem_align); + gmem->cbuf_base[i] = util_align_npot(total, gmem_align); total = gmem->cbuf_base[i] + key->cbuf_cpp[i] * bin_w * bin_h; } } if (key->zsbuf_cpp[0]) { - gmem->zsbuf_base[0] = align(total, gmem_align); + gmem->zsbuf_base[0] = util_align_npot(total, gmem_align); total = gmem->zsbuf_base[0] + key->zsbuf_cpp[0] * bin_w * bin_h; } if (key->zsbuf_cpp[1]) { - gmem->zsbuf_base[1] = align(total, gmem_align); + gmem->zsbuf_base[1] = util_align_npot(total, gmem_align); total = gmem->zsbuf_base[1] + key->zsbuf_cpp[1] * bin_w * bin_h; } - return total; + return total <= screen->gmemsize_bytes; } -static struct fd_gmem_stateobj * -gmem_stateobj_init(struct fd_screen *screen, struct gmem_key *key) +static void +calc_nbins(struct gmem_key *key, struct fd_gmem_stateobj *gmem) { - struct fd_gmem_stateobj *gmem = - rzalloc(screen->gmem_cache.ht, struct fd_gmem_stateobj); - pipe_reference_init(&gmem->reference, 1); - gmem->screen = screen; - gmem->key = key; - list_inithead(&gmem->node); - - const uint32_t gmem_alignw = screen->gmem_alignw; - const uint32_t gmem_alignh = screen->gmem_alignh; - const unsigned npipes = screen->num_vsc_pipes; - const uint32_t gmem_size = screen->gmemsize_bytes; + struct fd_screen *screen = gmem->screen; uint32_t nbins_x = 1, nbins_y = 1; - uint32_t bin_w, bin_h; uint32_t max_width = bin_width(screen); - uint32_t i, j, t, xoff, yoff; - uint32_t tpp_x, tpp_y; - int tile_n[npipes]; - - bin_w = div_align(key->width, 1, gmem_alignw); - bin_h = div_align(key->height, 1, gmem_alignh); - - /* first, find a bin width that satisfies the maximum width - * restrictions: - */ - while (bin_w > max_width) { - nbins_x++; - bin_w = div_align(key->width, nbins_x, gmem_alignw); - } if (fd_mesa_debug & FD_DBG_MSGS) { debug_printf("binning input: cbuf cpp:"); - for (i = 0; i < key->nr_cbufs; i++) + for (unsigned i = 0; i < key->nr_cbufs; i++) debug_printf(" %d", key->cbuf_cpp[i]); debug_printf(", zsbuf cpp: %d; %dx%d\n", key->zsbuf_cpp[0], key->width, key->height); } + /* first, find a bin width that satisfies the maximum width + * restrictions: + */ + while (div_align(key->width, nbins_x, screen->tile_alignw) > max_width) { + nbins_x++; + } + /* then find a bin width/height that satisfies the memory * constraints: */ - while (total_size(key, bin_w, bin_h, gmem) > gmem_size) { - if (bin_w > bin_h) { + while (!layout_gmem(key, nbins_x, nbins_y, gmem)) { + if (nbins_y > nbins_x) { nbins_x++; - bin_w = div_align(key->width, nbins_x, gmem_alignw); } else { nbins_y++; - bin_h = div_align(key->height, nbins_y, gmem_alignh); } } - DBG("using %d bins of size %dx%d", nbins_x*nbins_y, bin_w, bin_h); + /* Lets see if we can tweak the layout a bit and come up with + * something better: + */ + if ((((nbins_x - 1) * (nbins_y + 1)) < (nbins_x * nbins_y)) && + layout_gmem(key, nbins_x - 1, nbins_y + 1, gmem)) { + nbins_x--; + nbins_y++; + } else if ((((nbins_x + 1) * (nbins_y - 1)) < (nbins_x * nbins_y)) && + layout_gmem(key, nbins_x + 1, nbins_y - 1, gmem)) { + nbins_x++; + nbins_y--; + } + + layout_gmem(key, nbins_x, nbins_y, gmem); + +} + +static struct fd_gmem_stateobj * +gmem_stateobj_init(struct fd_screen *screen, struct gmem_key *key) +{ + struct fd_gmem_stateobj *gmem = + rzalloc(screen->gmem_cache.ht, struct fd_gmem_stateobj); + pipe_reference_init(&gmem->reference, 1); + gmem->screen = screen; + gmem->key = key; + list_inithead(&gmem->node); + + const unsigned npipes = screen->num_vsc_pipes; + uint32_t i, j, t, xoff, yoff; + uint32_t tpp_x, tpp_y; + int tile_n[npipes]; + + calc_nbins(key, gmem); + + DBG("using %d bins of size %dx%d", gmem->nbins_x * gmem->nbins_y, + gmem->bin_w, gmem->bin_h); memcpy(gmem->cbuf_cpp, key->cbuf_cpp, sizeof(key->cbuf_cpp)); memcpy(gmem->zsbuf_cpp, key->zsbuf_cpp, sizeof(key->zsbuf_cpp)); - gmem->bin_h = bin_h; - gmem->bin_w = bin_w; - gmem->nbins_x = nbins_x; - gmem->nbins_y = nbins_y; gmem->minx = key->minx; gmem->miny = key->miny; gmem->width = key->width; @@ -289,10 +319,10 @@ gmem_stateobj_init(struct fd_screen *screen, struct gmem_key *key) tpp_y = 6; } else { tpp_x = tpp_y = 1; - while (div_round_up(nbins_y, tpp_y) > npipes) + while (div_round_up(gmem->nbins_y, tpp_y) > npipes) tpp_y += 2; - while ((div_round_up(nbins_y, tpp_y) * - div_round_up(nbins_x, tpp_x)) > npipes) + while ((div_round_up(gmem->nbins_y, tpp_y) * + div_round_up(gmem->nbins_x, tpp_x)) > npipes) tpp_x += 1; } @@ -304,19 +334,19 @@ gmem_stateobj_init(struct fd_screen *screen, struct gmem_key *key) for (i = 0; i < npipes; i++) { struct fd_vsc_pipe *pipe = &gmem->vsc_pipe[i]; - if (xoff >= nbins_x) { + if (xoff >= gmem->nbins_x) { xoff = 0; yoff += tpp_y; } - if (yoff >= nbins_y) { + if (yoff >= gmem->nbins_y) { break; } pipe->x = xoff; pipe->y = yoff; - pipe->w = MIN2(tpp_x, nbins_x - xoff); - pipe->h = MIN2(tpp_y, nbins_y - yoff); + pipe->w = MIN2(tpp_x, gmem->nbins_x - xoff); + pipe->h = MIN2(tpp_y, gmem->nbins_y - yoff); xoff += tpp_x; } @@ -330,7 +360,7 @@ gmem_stateobj_init(struct fd_screen *screen, struct gmem_key *key) } if (BIN_DEBUG) { - printf("%dx%d ... tpp=%dx%d\n", nbins_x, nbins_y, tpp_x, tpp_y); + printf("%dx%d ... tpp=%dx%d\n", gmem->nbins_x, gmem->nbins_y, tpp_x, tpp_y); for (i = 0; i < ARRAY_SIZE(gmem->vsc_pipe); i++) { struct fd_vsc_pipe *pipe = &gmem->vsc_pipe[i]; printf("pipe[%d]: %ux%u @ %u,%u\n", i, @@ -342,26 +372,29 @@ gmem_stateobj_init(struct fd_screen *screen, struct gmem_key *key) t = 0; yoff = key->miny; memset(tile_n, 0, sizeof(tile_n)); - for (i = 0; i < nbins_y; i++) { - uint32_t bw, bh; + for (i = 0; i < gmem->nbins_y; i++) { + int bw, bh; xoff = key->minx; /* clip bin height: */ - bh = MIN2(bin_h, key->miny + key->height - yoff); + bh = MIN2(gmem->bin_h, key->miny + key->height - yoff); + assert(bh > 0); - for (j = 0; j < nbins_x; j++) { + for (j = 0; j < gmem->nbins_x; j++) { struct fd_tile *tile = &gmem->tile[t]; uint32_t p; assert(t < ARRAY_SIZE(gmem->tile)); /* pipe number: */ - p = ((i / tpp_y) * div_round_up(nbins_x, tpp_x)) + (j / tpp_x); + p = ((i / tpp_y) * div_round_up(gmem->nbins_x, tpp_x)) + (j / tpp_x); assert(p < gmem->num_vsc_pipes); /* clip bin width: */ - bw = MIN2(bin_w, key->minx + key->width - xoff); + bw = MIN2(gmem->bin_w, key->minx + key->width - xoff); + assert(bw > 0); + tile->n = !is_a20x(screen) ? tile_n[p]++ : ((i % tpp_y + 1) << 3 | (j % tpp_x + 1)); tile->p = p; @@ -385,8 +418,8 @@ gmem_stateobj_init(struct fd_screen *screen, struct gmem_key *key) if (BIN_DEBUG) { t = 0; - for (i = 0; i < nbins_y; i++) { - for (j = 0; j < nbins_x; j++) { + for (i = 0; i < gmem->nbins_y; i++) { + for (j = 0; j < gmem->nbins_x; j++) { struct fd_tile *tile = &gmem->tile[t++]; printf("|p:%u n:%u|", tile->p, tile->n); } @@ -441,7 +474,10 @@ gmem_key_init(struct fd_batch *batch, bool assume_zs, bool no_scis_opt) key->cbuf_cpp[i] *= pfb->samples; } - if ((fd_mesa_debug & FD_DBG_NOSCIS) || no_scis_opt) { + /* NOTE: on a6xx, the max-scissor-rect is handled in fd6_gmem, and + * we just rely on CP_COND_EXEC to skip bins with no geometry. + */ + if (no_scis_opt || is_a6xx(screen)) { key->minx = 0; key->miny = 0; key->width = pfb->width; @@ -449,6 +485,13 @@ gmem_key_init(struct fd_batch *batch, bool assume_zs, bool no_scis_opt) } else { struct pipe_scissor_state *scissor = &batch->max_scissor; + if (fd_mesa_debug & FD_DBG_NOSCIS) { + scissor->minx = 0; + scissor->miny = 0; + scissor->maxx = pfb->width; + scissor->maxy = pfb->height; + } + /* round down to multiple of alignment: */ key->minx = scissor->minx & ~(screen->gmem_alignw - 1); key->miny = scissor->miny & ~(screen->gmem_alignh - 1); @@ -461,6 +504,8 @@ gmem_key_init(struct fd_batch *batch, bool assume_zs, bool no_scis_opt) * but the fast clear path requires an alignment of 32K */ key->gmem_page_align = 8; + } else if (is_a6xx(screen)) { + key->gmem_page_align = is_a650(screen) ? 3 : 1; } else { // TODO re-check this across gens.. maybe it should only // be a single page in some cases: @@ -591,6 +636,9 @@ flush_ring(struct fd_batch *batch) uint32_t timestamp; int out_fence_fd = -1; + if (unlikely(fd_mesa_debug & FD_DBG_NOHW)) + return; + fd_submit_flush(batch->submit, batch->in_fence_fd, batch->needs_out_fence_fd ? &out_fence_fd : NULL, ×tamp);