"Fossies" - the Fresh Open Source Software Archive

Member "mesa-20.1.8/src/gallium/drivers/freedreno/freedreno_gmem.c" (16 Sep 2020, 18882 Bytes) of package /linux/misc/mesa-20.1.8.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "freedreno_gmem.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 20.1.5_vs_20.2.0-rc1.

    1 /*
    2  * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
    3  *
    4  * Permission is hereby granted, free of charge, to any person obtaining a
    5  * copy of this software and associated documentation files (the "Software"),
    6  * to deal in the Software without restriction, including without limitation
    7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
    8  * and/or sell copies of the Software, and to permit persons to whom the
    9  * Software is furnished to do so, subject to the following conditions:
   10  *
   11  * The above copyright notice and this permission notice (including the next
   12  * paragraph) shall be included in all copies or substantial portions of the
   13  * Software.
   14  *
   15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   21  * SOFTWARE.
   22  *
   23  * Authors:
   24  *    Rob Clark <robclark@freedesktop.org>
   25  */
   26 
   27 #include "pipe/p_state.h"
   28 #include "util/hash_table.h"
   29 #include "util/u_dump.h"
   30 #include "util/u_string.h"
   31 #include "util/u_memory.h"
   32 #include "util/u_inlines.h"
   33 #include "util/format/u_format.h"
   34 
   35 #include "freedreno_gmem.h"
   36 #include "freedreno_context.h"
   37 #include "freedreno_fence.h"
   38 #include "freedreno_log.h"
   39 #include "freedreno_resource.h"
   40 #include "freedreno_query_hw.h"
   41 #include "freedreno_util.h"
   42 
   43 /*
   44  * GMEM is the small (ie. 256KiB for a200, 512KiB for a220, etc) tile buffer
   45  * inside the GPU.  All rendering happens to GMEM.  Larger render targets
   46  * are split into tiles that are small enough for the color (and depth and/or
   47  * stencil, if enabled) buffers to fit within GMEM.  Before rendering a tile,
   48  * if there was not a clear invalidating the previous tile contents, we need
   49  * to restore the previous tiles contents (system mem -> GMEM), and after all
   50  * the draw calls, before moving to the next tile, we need to save the tile
   51  * contents (GMEM -> system mem).
   52  *
   53  * The code in this file handles dealing with GMEM and tiling.
   54  *
   55  * The structure of the ringbuffer ends up being:
   56  *
   57  *     +--<---<-- IB ---<---+---<---+---<---<---<--+
   58  *     |                    |       |              |
   59  *     v                    ^       ^              ^
   60  *   ------------------------------------------------------
   61  *     | clear/draw cmds | Tile0 | Tile1 | .... | TileN |
   62  *   ------------------------------------------------------
   63  *                       ^
   64  *                       |
   65  *                       address submitted in issueibcmds
   66  *
   67  * Where the per-tile section handles scissor setup, mem2gmem restore (if
   68  * needed), IB to draw cmds earlier in the ringbuffer, and then gmem2mem
   69  * resolve.
   70  */
   71 
   72 #define BIN_DEBUG 0
   73 
   74 /*
   75  * GMEM Cache:
   76  *
   77  * Caches GMEM state based on a given framebuffer state.  The key is
   78  * meant to be the minimal set of data that results in a unique gmem
   79  * configuration, avoiding multiple keys arriving at the same gmem
   80  * state.  For example, the render target format is not part of the
   81  * key, only the size per pixel.  And the max_scissor bounds is not
   82  * part of they key, only the minx/miny (after clamping to tile
   83  * alignment) and width/height.  This ensures that slightly different
   84  * max_scissor which would result in the same gmem state, do not
   85  * become different keys that map to the same state.
   86  */
   87 
   88 struct gmem_key {
   89     uint16_t minx, miny;
   90     uint16_t width, height;
   91     uint8_t gmem_page_align;      /* alignment in multiples of 0x1000 to reduce key size */
   92     uint8_t nr_cbufs;
   93     uint8_t cbuf_cpp[MAX_RENDER_TARGETS];
   94     uint8_t zsbuf_cpp[2];
   95 };
   96 
   97 static uint32_t
   98 gmem_key_hash(const void *_key)
   99 {
  100     const struct gmem_key *key = _key;
  101     return _mesa_hash_data(key, sizeof(*key));
  102 }
  103 
  104 static bool
  105 gmem_key_equals(const void *_a, const void *_b)
  106 {
  107     const struct gmem_key *a = _a;
  108     const struct gmem_key *b = _b;
  109     return memcmp(a, b, sizeof(*a)) == 0;
  110 }
  111 
  112 static uint32_t bin_width(struct fd_screen *screen)
  113 {
  114     if (is_a4xx(screen) || is_a5xx(screen) || is_a6xx(screen))
  115         return 1024;
  116     if (is_a3xx(screen))
  117         return 992;
  118     return 512;
  119 }
  120 
  121 static uint32_t
  122 total_size(struct gmem_key *key, uint32_t bin_w, uint32_t bin_h,
  123         struct fd_gmem_stateobj *gmem)
  124 {
  125     uint32_t gmem_align = key->gmem_page_align * 0x1000;
  126     uint32_t total = 0, i;
  127 
  128     for (i = 0; i < MAX_RENDER_TARGETS; i++) {
  129         if (key->cbuf_cpp[i]) {
  130             gmem->cbuf_base[i] = align(total, gmem_align);
  131             total = gmem->cbuf_base[i] + key->cbuf_cpp[i] * bin_w * bin_h;
  132         }
  133     }
  134 
  135     if (key->zsbuf_cpp[0]) {
  136         gmem->zsbuf_base[0] = align(total, gmem_align);
  137         total = gmem->zsbuf_base[0] + key->zsbuf_cpp[0] * bin_w * bin_h;
  138     }
  139 
  140     if (key->zsbuf_cpp[1]) {
  141         gmem->zsbuf_base[1] = align(total, gmem_align);
  142         total = gmem->zsbuf_base[1] + key->zsbuf_cpp[1] * bin_w * bin_h;
  143     }
  144 
  145     return total;
  146 }
  147 
  148 static struct fd_gmem_stateobj *
  149 gmem_stateobj_init(struct fd_screen *screen, struct gmem_key *key)
  150 {
  151     struct fd_gmem_stateobj *gmem =
  152             rzalloc(screen->gmem_cache.ht, struct fd_gmem_stateobj);
  153     pipe_reference_init(&gmem->reference, 1);
  154     gmem->screen = screen;
  155     gmem->key = key;
  156     list_inithead(&gmem->node);
  157 
  158     const uint32_t gmem_alignw = screen->gmem_alignw;
  159     const uint32_t gmem_alignh = screen->gmem_alignh;
  160     const unsigned npipes = screen->num_vsc_pipes;
  161     const uint32_t gmem_size = screen->gmemsize_bytes;
  162     uint32_t nbins_x = 1, nbins_y = 1;
  163     uint32_t bin_w, bin_h;
  164     uint32_t max_width = bin_width(screen);
  165     uint32_t i, j, t, xoff, yoff;
  166     uint32_t tpp_x, tpp_y;
  167     int tile_n[npipes];
  168 
  169     bin_w = align(key->width, gmem_alignw);
  170     bin_h = align(key->height, gmem_alignh);
  171 
  172     /* first, find a bin width that satisfies the maximum width
  173      * restrictions:
  174      */
  175     while (bin_w > max_width) {
  176         nbins_x++;
  177         bin_w = align(key->width / nbins_x, gmem_alignw);
  178     }
  179 
  180     if (fd_mesa_debug & FD_DBG_MSGS) {
  181         debug_printf("binning input: cbuf cpp:");
  182         for (i = 0; i < key->nr_cbufs; i++)
  183             debug_printf(" %d", key->cbuf_cpp[i]);
  184         debug_printf(", zsbuf cpp: %d; %dx%d\n",
  185                 key->zsbuf_cpp[0], key->width, key->height);
  186     }
  187 
  188     /* then find a bin width/height that satisfies the memory
  189      * constraints:
  190      */
  191     while (total_size(key, bin_w, bin_h, gmem) > gmem_size) {
  192         if (bin_w > bin_h) {
  193             nbins_x++;
  194             bin_w = align(key->width / nbins_x, gmem_alignw);
  195         } else {
  196             nbins_y++;
  197             bin_h = align(key->height / nbins_y, gmem_alignh);
  198         }
  199     }
  200 
  201     DBG("using %d bins of size %dx%d", nbins_x*nbins_y, bin_w, bin_h);
  202 
  203     memcpy(gmem->cbuf_cpp, key->cbuf_cpp, sizeof(key->cbuf_cpp));
  204     memcpy(gmem->zsbuf_cpp, key->zsbuf_cpp, sizeof(key->zsbuf_cpp));
  205     gmem->bin_h = bin_h;
  206     gmem->bin_w = bin_w;
  207     gmem->nbins_x = nbins_x;
  208     gmem->nbins_y = nbins_y;
  209     gmem->minx = key->minx;
  210     gmem->miny = key->miny;
  211     gmem->width = key->width;
  212     gmem->height = key->height;
  213 
  214     /*
  215      * Assign tiles and pipes:
  216      *
  217      * At some point it might be worth playing with different
  218      * strategies and seeing if that makes much impact on
  219      * performance.
  220      */
  221 
  222 #define div_round_up(v, a)  (((v) + (a) - 1) / (a))
  223     /* figure out number of tiles per pipe: */
  224     if (is_a20x(screen)) {
  225         /* for a20x we want to minimize the number of "pipes"
  226          * binning data has 3 bits for x/y (8x8) but the edges are used to
  227          * cull off-screen vertices with hw binning, so we have 6x6 pipes
  228          */
  229         tpp_x = 6;
  230         tpp_y = 6;
  231     } else {
  232         tpp_x = tpp_y = 1;
  233         while (div_round_up(nbins_y, tpp_y) > npipes)
  234             tpp_y += 2;
  235         while ((div_round_up(nbins_y, tpp_y) *
  236                 div_round_up(nbins_x, tpp_x)) > npipes)
  237             tpp_x += 1;
  238     }
  239 
  240     gmem->maxpw = tpp_x;
  241     gmem->maxph = tpp_y;
  242 
  243     /* configure pipes: */
  244     xoff = yoff = 0;
  245     for (i = 0; i < npipes; i++) {
  246         struct fd_vsc_pipe *pipe = &gmem->vsc_pipe[i];
  247 
  248         if (xoff >= nbins_x) {
  249             xoff = 0;
  250             yoff += tpp_y;
  251         }
  252 
  253         if (yoff >= nbins_y) {
  254             break;
  255         }
  256 
  257         pipe->x = xoff;
  258         pipe->y = yoff;
  259         pipe->w = MIN2(tpp_x, nbins_x - xoff);
  260         pipe->h = MIN2(tpp_y, nbins_y - yoff);
  261 
  262         xoff += tpp_x;
  263     }
  264 
  265     /* number of pipes to use for a20x */
  266     gmem->num_vsc_pipes = MAX2(1, i);
  267 
  268     for (; i < npipes; i++) {
  269         struct fd_vsc_pipe *pipe = &gmem->vsc_pipe[i];
  270         pipe->x = pipe->y = pipe->w = pipe->h = 0;
  271     }
  272 
  273     if (BIN_DEBUG) {
  274         printf("%dx%d ... tpp=%dx%d\n", nbins_x, nbins_y, tpp_x, tpp_y);
  275         for (i = 0; i < ARRAY_SIZE(gmem->vsc_pipe); i++) {
  276             struct fd_vsc_pipe *pipe = &gmem->vsc_pipe[i];
  277             printf("pipe[%d]: %ux%u @ %u,%u\n", i,
  278                     pipe->w, pipe->h, pipe->x, pipe->y);
  279         }
  280     }
  281 
  282     /* configure tiles: */
  283     t = 0;
  284     yoff = key->miny;
  285     memset(tile_n, 0, sizeof(tile_n));
  286     for (i = 0; i < nbins_y; i++) {
  287         uint32_t bw, bh;
  288 
  289         xoff = key->minx;
  290 
  291         /* clip bin height: */
  292         bh = MIN2(bin_h, key->miny + key->height - yoff);
  293 
  294         for (j = 0; j < nbins_x; j++) {
  295             struct fd_tile *tile = &gmem->tile[t];
  296             uint32_t p;
  297 
  298             assert(t < ARRAY_SIZE(gmem->tile));
  299 
  300             /* pipe number: */
  301             p = ((i / tpp_y) * div_round_up(nbins_x, tpp_x)) + (j / tpp_x);
  302             assert(p < gmem->num_vsc_pipes);
  303 
  304             /* clip bin width: */
  305             bw = MIN2(bin_w, key->minx + key->width - xoff);
  306             tile->n = !is_a20x(screen) ? tile_n[p]++ :
  307                 ((i % tpp_y + 1) << 3 | (j % tpp_x + 1));
  308             tile->p = p;
  309             tile->bin_w = bw;
  310             tile->bin_h = bh;
  311             tile->xoff = xoff;
  312             tile->yoff = yoff;
  313 
  314             if (BIN_DEBUG) {
  315                 printf("tile[%d]: p=%u, bin=%ux%u+%u+%u\n", t,
  316                         p, bw, bh, xoff, yoff);
  317             }
  318 
  319             t++;
  320 
  321             xoff += bw;
  322         }
  323 
  324         yoff += bh;
  325     }
  326 
  327     if (BIN_DEBUG) {
  328         t = 0;
  329         for (i = 0; i < nbins_y; i++) {
  330             for (j = 0; j < nbins_x; j++) {
  331                 struct fd_tile *tile = &gmem->tile[t++];
  332                 printf("|p:%u n:%u|", tile->p, tile->n);
  333             }
  334             printf("\n");
  335         }
  336     }
  337 
  338     return gmem;
  339 }
  340 
  341 void
  342 __fd_gmem_destroy(struct fd_gmem_stateobj *gmem)
  343 {
  344     struct fd_gmem_cache *cache = &gmem->screen->gmem_cache;
  345 
  346     pipe_mutex_assert_locked(gmem->screen->lock);
  347 
  348     _mesa_hash_table_remove_key(cache->ht, gmem->key);
  349     list_del(&gmem->node);
  350 
  351     ralloc_free(gmem->key);
  352     ralloc_free(gmem);
  353 }
  354 
  355 static struct gmem_key *
  356 gmem_key_init(struct fd_batch *batch, bool assume_zs)
  357 {
  358     struct fd_screen *screen = batch->ctx->screen;
  359     struct pipe_framebuffer_state *pfb = &batch->framebuffer;
  360     bool has_zs = pfb->zsbuf && !!(batch->gmem_reason & (FD_GMEM_DEPTH_ENABLED |
  361         FD_GMEM_STENCIL_ENABLED | FD_GMEM_CLEARS_DEPTH_STENCIL));
  362     struct gmem_key *key = rzalloc(screen->gmem_cache.ht, struct gmem_key);
  363 
  364     if (has_zs || assume_zs) {
  365         struct fd_resource *rsc = fd_resource(pfb->zsbuf->texture);
  366         key->zsbuf_cpp[0] = rsc->layout.cpp;
  367         if (rsc->stencil)
  368             key->zsbuf_cpp[1] = rsc->stencil->layout.cpp;
  369     } else {
  370         /* we might have a zsbuf, but it isn't used */
  371         batch->restore &= ~(FD_BUFFER_DEPTH | FD_BUFFER_STENCIL);
  372         batch->resolve &= ~(FD_BUFFER_DEPTH | FD_BUFFER_STENCIL);
  373     }
  374 
  375     key->nr_cbufs = pfb->nr_cbufs;
  376     for (unsigned i = 0; i < pfb->nr_cbufs; i++) {
  377         if (pfb->cbufs[i])
  378             key->cbuf_cpp[i] = util_format_get_blocksize(pfb->cbufs[i]->format);
  379         else
  380             key->cbuf_cpp[i] = 4;
  381         /* if MSAA, color buffers are super-sampled in GMEM: */
  382         key->cbuf_cpp[i] *= pfb->samples;
  383     }
  384 
  385     if (fd_mesa_debug & FD_DBG_NOSCIS) {
  386         key->minx = 0;
  387         key->miny = 0;
  388         key->width = pfb->width;
  389         key->height = pfb->height;
  390     } else {
  391         struct pipe_scissor_state *scissor = &batch->max_scissor;
  392 
  393         /* round down to multiple of alignment: */
  394         key->minx = scissor->minx & ~(screen->gmem_alignw - 1);
  395         key->miny = scissor->miny & ~(screen->gmem_alignh - 1);
  396         key->width = scissor->maxx - key->minx;
  397         key->height = scissor->maxy - key->miny;
  398     }
  399 
  400     if (is_a20x(screen) && batch->cleared) {
  401         /* under normal circumstances the requirement would be 4K
  402          * but the fast clear path requires an alignment of 32K
  403          */
  404         key->gmem_page_align = 8;
  405     } else {
  406         // TODO re-check this across gens.. maybe it should only
  407         // be a single page in some cases:
  408         key->gmem_page_align = 4;
  409     }
  410 
  411     return key;
  412 }
  413 
  414 static struct fd_gmem_stateobj *
  415 lookup_gmem_state(struct fd_batch *batch, bool assume_zs)
  416 {
  417     struct fd_screen *screen = batch->ctx->screen;
  418     struct fd_gmem_cache *cache = &screen->gmem_cache;
  419     struct fd_gmem_stateobj *gmem = NULL;
  420     struct gmem_key *key = gmem_key_init(batch, assume_zs);
  421     uint32_t hash = gmem_key_hash(key);
  422 
  423     mtx_lock(&screen->lock);
  424 
  425     struct hash_entry *entry =
  426         _mesa_hash_table_search_pre_hashed(cache->ht, hash, key);
  427     if (entry) {
  428         ralloc_free(key);
  429         goto found;
  430     }
  431 
  432     /* limit the # of cached gmem states, discarding the least
  433      * recently used state if needed:
  434      */
  435     if (cache->ht->entries >= 20) {
  436         struct fd_gmem_stateobj *last =
  437             list_last_entry(&cache->lru, struct fd_gmem_stateobj, node);
  438         fd_gmem_reference(&last, NULL);
  439     }
  440 
  441     entry = _mesa_hash_table_insert_pre_hashed(cache->ht,
  442             hash, key, gmem_stateobj_init(screen, key));
  443 
  444 found:
  445     fd_gmem_reference(&gmem, entry->data);
  446     /* Move to the head of the LRU: */
  447     list_delinit(&gmem->node);
  448     list_add(&gmem->node, &cache->lru);
  449 
  450     mtx_unlock(&screen->lock);
  451 
  452     return gmem;
  453 }
  454 
  455 /*
  456  * GMEM render pass
  457  */
  458 
  459 static void
  460 render_tiles(struct fd_batch *batch, struct fd_gmem_stateobj *gmem)
  461 {
  462     struct fd_context *ctx = batch->ctx;
  463     int i;
  464 
  465     mtx_lock(&ctx->gmem_lock);
  466 
  467     ctx->emit_tile_init(batch);
  468 
  469     if (batch->restore)
  470         ctx->stats.batch_restore++;
  471 
  472     for (i = 0; i < (gmem->nbins_x * gmem->nbins_y); i++) {
  473         struct fd_tile *tile = &gmem->tile[i];
  474 
  475         fd_log(batch, "bin_h=%d, yoff=%d, bin_w=%d, xoff=%d",
  476             tile->bin_h, tile->yoff, tile->bin_w, tile->xoff);
  477 
  478         ctx->emit_tile_prep(batch, tile);
  479 
  480         if (batch->restore) {
  481             ctx->emit_tile_mem2gmem(batch, tile);
  482         }
  483 
  484         ctx->emit_tile_renderprep(batch, tile);
  485 
  486         if (ctx->query_prepare_tile)
  487             ctx->query_prepare_tile(batch, i, batch->gmem);
  488 
  489         /* emit IB to drawcmds: */
  490         fd_log(batch, "TILE[%d]: START DRAW IB", i);
  491         if (ctx->emit_tile) {
  492             ctx->emit_tile(batch, tile);
  493         } else {
  494             ctx->screen->emit_ib(batch->gmem, batch->draw);
  495         }
  496         fd_log(batch, "TILE[%d]: END DRAW IB", i);
  497         fd_reset_wfi(batch);
  498 
  499         /* emit gmem2mem to transfer tile back to system memory: */
  500         ctx->emit_tile_gmem2mem(batch, tile);
  501     }
  502 
  503     if (ctx->emit_tile_fini)
  504         ctx->emit_tile_fini(batch);
  505 
  506     mtx_unlock(&ctx->gmem_lock);
  507 }
  508 
  509 static void
  510 render_sysmem(struct fd_batch *batch)
  511 {
  512     struct fd_context *ctx = batch->ctx;
  513 
  514     ctx->emit_sysmem_prep(batch);
  515 
  516     if (ctx->query_prepare_tile)
  517         ctx->query_prepare_tile(batch, 0, batch->gmem);
  518 
  519     /* emit IB to drawcmds: */
  520     fd_log(batch, "SYSMEM: START DRAW IB");
  521     ctx->screen->emit_ib(batch->gmem, batch->draw);
  522     fd_log(batch, "SYSMEM: END DRAW IB");
  523     fd_reset_wfi(batch);
  524 
  525     if (ctx->emit_sysmem_fini)
  526         ctx->emit_sysmem_fini(batch);
  527 }
  528 
  529 static void
  530 flush_ring(struct fd_batch *batch)
  531 {
  532     uint32_t timestamp;
  533     int out_fence_fd = -1;
  534 
  535     fd_submit_flush(batch->submit, batch->in_fence_fd,
  536             batch->needs_out_fence_fd ? &out_fence_fd : NULL,
  537             &timestamp);
  538 
  539     fd_fence_populate(batch->fence, timestamp, out_fence_fd);
  540     fd_log_flush(batch);
  541 }
  542 
  543 void
  544 fd_gmem_render_tiles(struct fd_batch *batch)
  545 {
  546     struct fd_context *ctx = batch->ctx;
  547     struct pipe_framebuffer_state *pfb = &batch->framebuffer;
  548     bool sysmem = false;
  549 
  550     if (ctx->emit_sysmem_prep && !batch->nondraw) {
  551         if (batch->cleared || batch->gmem_reason ||
  552                 ((batch->num_draws > 5) && !batch->blit) ||
  553                 (pfb->samples > 1)) {
  554             fd_log(batch, "GMEM: cleared=%x, gmem_reason=%x, num_draws=%u, samples=%u",
  555                 batch->cleared, batch->gmem_reason, batch->num_draws,
  556                 pfb->samples);
  557         } else if (!(fd_mesa_debug & FD_DBG_NOBYPASS)) {
  558             sysmem = true;
  559         }
  560 
  561         /* For ARB_framebuffer_no_attachments: */
  562         if ((pfb->nr_cbufs == 0) && !pfb->zsbuf) {
  563             sysmem = true;
  564         }
  565     }
  566 
  567     if (fd_mesa_debug & FD_DBG_NOGMEM)
  568         sysmem = true;
  569 
  570     /* Layered rendering always needs bypass. */
  571     for (unsigned i = 0; i < pfb->nr_cbufs; i++) {
  572         struct pipe_surface *psurf = pfb->cbufs[i];
  573         if (!psurf)
  574             continue;
  575         if (psurf->u.tex.first_layer < psurf->u.tex.last_layer)
  576             sysmem = true;
  577     }
  578 
  579     /* Tessellation doesn't seem to support tiled rendering so fall back to
  580      * bypass.
  581      */
  582     if (batch->tessellation) {
  583         debug_assert(ctx->emit_sysmem_prep);
  584         sysmem = true;
  585     }
  586 
  587     fd_reset_wfi(batch);
  588 
  589     ctx->stats.batch_total++;
  590 
  591     if (unlikely(fd_mesa_debug & FD_DBG_LOG) && !batch->nondraw) {
  592         fd_log_stream(batch, stream, util_dump_framebuffer_state(stream, pfb));
  593         for (unsigned i = 0; i < pfb->nr_cbufs; i++) {
  594             fd_log_stream(batch, stream, util_dump_surface(stream, pfb->cbufs[i]));
  595         }
  596         fd_log_stream(batch, stream, util_dump_surface(stream, pfb->zsbuf));
  597     }
  598 
  599     if (batch->nondraw) {
  600         DBG("%p: rendering non-draw", batch);
  601         ctx->stats.batch_nondraw++;
  602     } else if (sysmem) {
  603         fd_log(batch, "%p: rendering sysmem %ux%u (%s/%s), num_draws=%u",
  604             batch, pfb->width, pfb->height,
  605             util_format_short_name(pipe_surface_format(pfb->cbufs[0])),
  606             util_format_short_name(pipe_surface_format(pfb->zsbuf)),
  607             batch->num_draws);
  608         if (ctx->query_prepare)
  609             ctx->query_prepare(batch, 1);
  610         render_sysmem(batch);
  611         ctx->stats.batch_sysmem++;
  612     } else {
  613         struct fd_gmem_stateobj *gmem = lookup_gmem_state(batch, false);
  614         batch->gmem_state = gmem;
  615         fd_log(batch, "%p: rendering %dx%d tiles %ux%u (%s/%s)",
  616             batch, pfb->width, pfb->height, gmem->nbins_x, gmem->nbins_y,
  617             util_format_short_name(pipe_surface_format(pfb->cbufs[0])),
  618             util_format_short_name(pipe_surface_format(pfb->zsbuf)));
  619         if (ctx->query_prepare)
  620             ctx->query_prepare(batch, gmem->nbins_x * gmem->nbins_y);
  621         render_tiles(batch, gmem);
  622         batch->gmem_state = NULL;
  623 
  624         mtx_lock(&ctx->screen->lock);
  625         fd_gmem_reference(&gmem, NULL);
  626         mtx_unlock(&ctx->screen->lock);
  627 
  628         ctx->stats.batch_gmem++;
  629     }
  630 
  631     flush_ring(batch);
  632 }
  633 
  634 /* Determine a worst-case estimate (ie. assuming we don't eliminate an
  635  * unused depth/stencil) number of bins per vsc pipe.
  636  */
  637 unsigned
  638 fd_gmem_estimate_bins_per_pipe(struct fd_batch *batch)
  639 {
  640     struct pipe_framebuffer_state *pfb = &batch->framebuffer;
  641     struct fd_screen *screen = batch->ctx->screen;
  642     struct fd_gmem_stateobj *gmem = lookup_gmem_state(batch, !!pfb->zsbuf);
  643     unsigned nbins = gmem->maxpw * gmem->maxph;
  644 
  645     mtx_lock(&screen->lock);
  646     fd_gmem_reference(&gmem, NULL);
  647     mtx_unlock(&screen->lock);
  648 
  649     return nbins;
  650 }
  651 
  652 /* When deciding whether a tile needs mem2gmem, we need to take into
  653  * account the scissor rect(s) that were cleared.  To simplify we only
  654  * consider the last scissor rect for each buffer, since the common
  655  * case would be a single clear.
  656  */
  657 bool
  658 fd_gmem_needs_restore(struct fd_batch *batch, const struct fd_tile *tile,
  659         uint32_t buffers)
  660 {
  661     if (!(batch->restore & buffers))
  662         return false;
  663 
  664     return true;
  665 }
  666 
  667 void
  668 fd_gmem_screen_init(struct pipe_screen *pscreen)
  669 {
  670     struct fd_gmem_cache *cache = &fd_screen(pscreen)->gmem_cache;
  671 
  672     cache->ht = _mesa_hash_table_create(NULL, gmem_key_hash, gmem_key_equals);
  673     list_inithead(&cache->lru);
  674 }
  675 
  676 void
  677 fd_gmem_screen_fini(struct pipe_screen *pscreen)
  678 {
  679     struct fd_gmem_cache *cache = &fd_screen(pscreen)->gmem_cache;
  680 
  681     _mesa_hash_table_destroy(cache->ht, NULL);
  682 }