Path: blob/21.2-virgl/src/gallium/drivers/freedreno/freedreno_gmem.c
4570 views
/*1* Copyright (C) 2012 Rob Clark <[email protected]>2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,19* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE20* SOFTWARE.21*22* Authors:23* Rob Clark <[email protected]>24*/2526#include "pipe/p_state.h"27#include "util/debug.h"28#include "util/format/u_format.h"29#include "util/hash_table.h"30#include "util/u_dump.h"31#include "util/u_inlines.h"32#include "util/u_memory.h"33#include "util/u_string.h"34#include "u_tracepoints.h"3536#include "freedreno_context.h"37#include "freedreno_fence.h"38#include "freedreno_gmem.h"39#include "freedreno_query_hw.h"40#include "freedreno_resource.h"41#include "freedreno_tracepoints.h"42#include "freedreno_util.h"4344/*45* GMEM is the small (ie. 256KiB for a200, 512KiB for a220, etc) tile buffer46* inside the GPU. All rendering happens to GMEM. Larger render targets47* are split into tiles that are small enough for the color (and depth and/or48* stencil, if enabled) buffers to fit within GMEM. Before rendering a tile,49* if there was not a clear invalidating the previous tile contents, we need50* to restore the previous tiles contents (system mem -> GMEM), and after all51* the draw calls, before moving to the next tile, we need to save the tile52* contents (GMEM -> system mem).53*54* The code in this file handles dealing with GMEM and tiling.55*56* The structure of the ringbuffer ends up being:57*58* +--<---<-- IB ---<---+---<---+---<---<---<--+59* | | | |60* v ^ ^ ^61* ------------------------------------------------------62* | clear/draw cmds | Tile0 | Tile1 | .... | TileN |63* ------------------------------------------------------64* ^65* |66* address submitted in issueibcmds67*68* Where the per-tile section handles scissor setup, mem2gmem restore (if69* needed), IB to draw cmds earlier in the ringbuffer, and then gmem2mem70* resolve.71*/7273#ifndef BIN_DEBUG74#define BIN_DEBUG 075#endif7677/*78* GMEM Cache:79*80* Caches GMEM state based on a given framebuffer state. The key is81* meant to be the minimal set of data that results in a unique gmem82* configuration, avoiding multiple keys arriving at the same gmem83* state. For example, the render target format is not part of the84* key, only the size per pixel. And the max_scissor bounds is not85* part of they key, only the minx/miny (after clamping to tile86* alignment) and width/height. This ensures that slightly different87* max_scissor which would result in the same gmem state, do not88* become different keys that map to the same state.89*/9091struct gmem_key {92uint16_t minx, miny;93uint16_t width, height;94uint8_t gmem_page_align; /* alignment in multiples of 0x1000 to reduce key size */95uint8_t nr_cbufs;96uint8_t cbuf_cpp[MAX_RENDER_TARGETS];97uint8_t zsbuf_cpp[2];98};99100static uint32_t101gmem_key_hash(const void *_key)102{103const struct gmem_key *key = _key;104return _mesa_hash_data(key, sizeof(*key));105}106107static bool108gmem_key_equals(const void *_a, const void *_b)109{110const struct gmem_key *a = _a;111const struct gmem_key *b = _b;112return memcmp(a, b, sizeof(*a)) == 0;113}114115static void116dump_gmem_key(const struct gmem_key *key)117{118printf("{ .minx=%u, .miny=%u, .width=%u, .height=%u", key->minx, key->miny,119key->width, key->height);120printf(", .gmem_page_align=%u, .nr_cbufs=%u", key->gmem_page_align,121key->nr_cbufs);122printf(", .cbuf_cpp = {");123for (unsigned i = 0; i < ARRAY_SIZE(key->cbuf_cpp); i++)124printf("%u,", key->cbuf_cpp[i]);125printf("}, .zsbuf_cpp = {");126for (unsigned i = 0; i < ARRAY_SIZE(key->zsbuf_cpp); i++)127printf("%u,", key->zsbuf_cpp[i]);128printf("}},\n");129}130131static void132dump_gmem_state(const struct fd_gmem_stateobj *gmem)133{134unsigned total = 0;135printf("GMEM LAYOUT: bin=%ux%u, nbins=%ux%u\n", gmem->bin_w, gmem->bin_h,136gmem->nbins_x, gmem->nbins_y);137for (int i = 0; i < ARRAY_SIZE(gmem->cbuf_base); i++) {138if (!gmem->cbuf_cpp[i])139continue;140141unsigned size = gmem->cbuf_cpp[i] * gmem->bin_w * gmem->bin_h;142printf(" cbuf[%d]: base=0x%06x, size=0x%x, cpp=%u\n", i,143gmem->cbuf_base[i], size, gmem->cbuf_cpp[i]);144145total = gmem->cbuf_base[i] + size;146}147148for (int i = 0; i < ARRAY_SIZE(gmem->zsbuf_base); i++) {149if (!gmem->zsbuf_cpp[i])150continue;151152unsigned size = gmem->zsbuf_cpp[i] * gmem->bin_w * gmem->bin_h;153printf(" zsbuf[%d]: base=0x%06x, size=0x%x, cpp=%u\n", i,154gmem->zsbuf_base[i], size, gmem->zsbuf_cpp[i]);155156total = gmem->zsbuf_base[i] + size;157}158159printf("total: 0x%06x (of 0x%06x)\n", total, gmem->screen->gmemsize_bytes);160}161162static unsigned163div_align(unsigned num, unsigned denom, unsigned al)164{165return util_align_npot(DIV_ROUND_UP(num, denom), al);166}167168static bool169layout_gmem(struct gmem_key *key, uint32_t nbins_x, uint32_t nbins_y,170struct fd_gmem_stateobj *gmem)171{172struct fd_screen *screen = gmem->screen;173uint32_t gmem_align = key->gmem_page_align * 0x1000;174uint32_t total = 0, i;175176if ((nbins_x == 0) || (nbins_y == 0))177return false;178179uint32_t bin_w, bin_h;180bin_w = div_align(key->width, nbins_x, screen->info->tile_align_w);181bin_h = div_align(key->height, nbins_y, screen->info->tile_align_h);182183if (bin_w > screen->info->tile_max_w)184return false;185186if (bin_h > screen->info->tile_max_h)187return false;188189gmem->bin_w = bin_w;190gmem->bin_h = bin_h;191192/* due to aligning bin_w/h, we could end up with one too193* many bins in either dimension, so recalculate:194*/195gmem->nbins_x = DIV_ROUND_UP(key->width, bin_w);196gmem->nbins_y = DIV_ROUND_UP(key->height, bin_h);197198for (i = 0; i < MAX_RENDER_TARGETS; i++) {199if (key->cbuf_cpp[i]) {200gmem->cbuf_base[i] = util_align_npot(total, gmem_align);201total = gmem->cbuf_base[i] + key->cbuf_cpp[i] * bin_w * bin_h;202}203}204205if (key->zsbuf_cpp[0]) {206gmem->zsbuf_base[0] = util_align_npot(total, gmem_align);207total = gmem->zsbuf_base[0] + key->zsbuf_cpp[0] * bin_w * bin_h;208}209210if (key->zsbuf_cpp[1]) {211gmem->zsbuf_base[1] = util_align_npot(total, gmem_align);212total = gmem->zsbuf_base[1] + key->zsbuf_cpp[1] * bin_w * bin_h;213}214215return total <= screen->gmemsize_bytes;216}217218static void219calc_nbins(struct gmem_key *key, struct fd_gmem_stateobj *gmem)220{221struct fd_screen *screen = gmem->screen;222uint32_t nbins_x = 1, nbins_y = 1;223uint32_t max_width = screen->info->tile_max_w;224uint32_t max_height = screen->info->tile_max_h;225226if (FD_DBG(MSGS)) {227debug_printf("binning input: cbuf cpp:");228for (unsigned i = 0; i < key->nr_cbufs; i++)229debug_printf(" %d", key->cbuf_cpp[i]);230debug_printf(", zsbuf cpp: %d; %dx%d\n", key->zsbuf_cpp[0], key->width,231key->height);232}233234/* first, find a bin size that satisfies the maximum width/235* height restrictions:236*/237while (div_align(key->width, nbins_x, screen->info->tile_align_w) >238max_width) {239nbins_x++;240}241242while (div_align(key->height, nbins_y, screen->info->tile_align_h) >243max_height) {244nbins_y++;245}246247/* then find a bin width/height that satisfies the memory248* constraints:249*/250while (!layout_gmem(key, nbins_x, nbins_y, gmem)) {251if (nbins_y > nbins_x) {252nbins_x++;253} else {254nbins_y++;255}256}257258/* Lets see if we can tweak the layout a bit and come up with259* something better:260*/261if ((((nbins_x - 1) * (nbins_y + 1)) < (nbins_x * nbins_y)) &&262layout_gmem(key, nbins_x - 1, nbins_y + 1, gmem)) {263nbins_x--;264nbins_y++;265} else if ((((nbins_x + 1) * (nbins_y - 1)) < (nbins_x * nbins_y)) &&266layout_gmem(key, nbins_x + 1, nbins_y - 1, gmem)) {267nbins_x++;268nbins_y--;269}270271layout_gmem(key, nbins_x, nbins_y, gmem);272}273274static struct fd_gmem_stateobj *275gmem_stateobj_init(struct fd_screen *screen, struct gmem_key *key)276{277struct fd_gmem_stateobj *gmem =278rzalloc(screen->gmem_cache.ht, struct fd_gmem_stateobj);279pipe_reference_init(&gmem->reference, 1);280gmem->screen = screen;281gmem->key = key;282list_inithead(&gmem->node);283284const unsigned npipes = screen->info->num_vsc_pipes;285uint32_t i, j, t, xoff, yoff;286uint32_t tpp_x, tpp_y;287int tile_n[npipes];288289calc_nbins(key, gmem);290291DBG("using %d bins of size %dx%d", gmem->nbins_x * gmem->nbins_y,292gmem->bin_w, gmem->bin_h);293294memcpy(gmem->cbuf_cpp, key->cbuf_cpp, sizeof(key->cbuf_cpp));295memcpy(gmem->zsbuf_cpp, key->zsbuf_cpp, sizeof(key->zsbuf_cpp));296gmem->minx = key->minx;297gmem->miny = key->miny;298gmem->width = key->width;299gmem->height = key->height;300301if (BIN_DEBUG) {302dump_gmem_state(gmem);303dump_gmem_key(key);304}305306/*307* Assign tiles and pipes:308*309* At some point it might be worth playing with different310* strategies and seeing if that makes much impact on311* performance.312*/313314#define div_round_up(v, a) (((v) + (a)-1) / (a))315/* figure out number of tiles per pipe: */316if (is_a20x(screen)) {317/* for a20x we want to minimize the number of "pipes"318* binning data has 3 bits for x/y (8x8) but the edges are used to319* cull off-screen vertices with hw binning, so we have 6x6 pipes320*/321tpp_x = 6;322tpp_y = 6;323} else {324tpp_x = tpp_y = 1;325while (div_round_up(gmem->nbins_y, tpp_y) > npipes)326tpp_y += 2;327while ((div_round_up(gmem->nbins_y, tpp_y) *328div_round_up(gmem->nbins_x, tpp_x)) > npipes)329tpp_x += 1;330}331332#ifdef DEBUG333tpp_x = env_var_as_unsigned("TPP_X", tpp_x);334tpp_y = env_var_as_unsigned("TPP_Y", tpp_x);335#endif336337gmem->maxpw = tpp_x;338gmem->maxph = tpp_y;339340/* configure pipes: */341xoff = yoff = 0;342for (i = 0; i < npipes; i++) {343struct fd_vsc_pipe *pipe = &gmem->vsc_pipe[i];344345if (xoff >= gmem->nbins_x) {346xoff = 0;347yoff += tpp_y;348}349350if (yoff >= gmem->nbins_y) {351break;352}353354pipe->x = xoff;355pipe->y = yoff;356pipe->w = MIN2(tpp_x, gmem->nbins_x - xoff);357pipe->h = MIN2(tpp_y, gmem->nbins_y - yoff);358359xoff += tpp_x;360}361362/* number of pipes to use for a20x */363gmem->num_vsc_pipes = MAX2(1, i);364365for (; i < npipes; i++) {366struct fd_vsc_pipe *pipe = &gmem->vsc_pipe[i];367pipe->x = pipe->y = pipe->w = pipe->h = 0;368}369370if (BIN_DEBUG) {371printf("%dx%d ... tpp=%dx%d\n", gmem->nbins_x, gmem->nbins_y, tpp_x,372tpp_y);373for (i = 0; i < ARRAY_SIZE(gmem->vsc_pipe); i++) {374struct fd_vsc_pipe *pipe = &gmem->vsc_pipe[i];375printf("pipe[%d]: %ux%u @ %u,%u\n", i, pipe->w, pipe->h, pipe->x,376pipe->y);377}378}379380/* configure tiles: */381t = 0;382yoff = key->miny;383memset(tile_n, 0, sizeof(tile_n));384for (i = 0; i < gmem->nbins_y; i++) {385int bw, bh;386387xoff = key->minx;388389/* clip bin height: */390bh = MIN2(gmem->bin_h, key->miny + key->height - yoff);391assert(bh > 0);392393for (j = 0; j < gmem->nbins_x; j++) {394struct fd_tile *tile = &gmem->tile[t];395uint32_t p;396397assert(t < ARRAY_SIZE(gmem->tile));398399/* pipe number: */400p = ((i / tpp_y) * div_round_up(gmem->nbins_x, tpp_x)) + (j / tpp_x);401assert(p < gmem->num_vsc_pipes);402403/* clip bin width: */404bw = MIN2(gmem->bin_w, key->minx + key->width - xoff);405assert(bw > 0);406407tile->n = !is_a20x(screen) ? tile_n[p]++408: ((i % tpp_y + 1) << 3 | (j % tpp_x + 1));409tile->p = p;410tile->bin_w = bw;411tile->bin_h = bh;412tile->xoff = xoff;413tile->yoff = yoff;414415if (BIN_DEBUG) {416printf("tile[%d]: p=%u, bin=%ux%u+%u+%u\n", t, p, bw, bh, xoff,417yoff);418}419420t++;421422xoff += bw;423}424425yoff += bh;426}427428if (BIN_DEBUG) {429t = 0;430for (i = 0; i < gmem->nbins_y; i++) {431for (j = 0; j < gmem->nbins_x; j++) {432struct fd_tile *tile = &gmem->tile[t++];433printf("|p:%u n:%u|", tile->p, tile->n);434}435printf("\n");436}437}438439return gmem;440}441442void443__fd_gmem_destroy(struct fd_gmem_stateobj *gmem)444{445struct fd_gmem_cache *cache = &gmem->screen->gmem_cache;446447fd_screen_assert_locked(gmem->screen);448449_mesa_hash_table_remove_key(cache->ht, gmem->key);450list_del(&gmem->node);451452ralloc_free(gmem->key);453ralloc_free(gmem);454}455456static struct gmem_key *457gmem_key_init(struct fd_batch *batch, bool assume_zs, bool no_scis_opt)458{459struct fd_screen *screen = batch->ctx->screen;460struct pipe_framebuffer_state *pfb = &batch->framebuffer;461bool has_zs = pfb->zsbuf &&462!!(batch->gmem_reason & (FD_GMEM_DEPTH_ENABLED | FD_GMEM_STENCIL_ENABLED |463FD_GMEM_CLEARS_DEPTH_STENCIL));464struct gmem_key *key = rzalloc(screen->gmem_cache.ht, struct gmem_key);465466if (has_zs || assume_zs) {467struct fd_resource *rsc = fd_resource(pfb->zsbuf->texture);468key->zsbuf_cpp[0] = rsc->layout.cpp;469if (rsc->stencil)470key->zsbuf_cpp[1] = rsc->stencil->layout.cpp;471} else {472/* we might have a zsbuf, but it isn't used */473batch->restore &= ~(FD_BUFFER_DEPTH | FD_BUFFER_STENCIL);474batch->resolve &= ~(FD_BUFFER_DEPTH | FD_BUFFER_STENCIL);475}476477key->nr_cbufs = pfb->nr_cbufs;478for (unsigned i = 0; i < pfb->nr_cbufs; i++) {479if (pfb->cbufs[i])480key->cbuf_cpp[i] = util_format_get_blocksize(pfb->cbufs[i]->format);481else482key->cbuf_cpp[i] = 4;483/* if MSAA, color buffers are super-sampled in GMEM: */484key->cbuf_cpp[i] *= pfb->samples;485}486487/* NOTE: on a6xx, the max-scissor-rect is handled in fd6_gmem, and488* we just rely on CP_COND_EXEC to skip bins with no geometry.489*/490if (no_scis_opt || is_a6xx(screen)) {491key->minx = 0;492key->miny = 0;493key->width = pfb->width;494key->height = pfb->height;495} else {496struct pipe_scissor_state *scissor = &batch->max_scissor;497498if (FD_DBG(NOSCIS)) {499scissor->minx = 0;500scissor->miny = 0;501scissor->maxx = pfb->width;502scissor->maxy = pfb->height;503}504505/* round down to multiple of alignment: */506key->minx = scissor->minx & ~(screen->info->gmem_align_w - 1);507key->miny = scissor->miny & ~(screen->info->gmem_align_h - 1);508key->width = scissor->maxx - key->minx;509key->height = scissor->maxy - key->miny;510}511512if (is_a20x(screen) && batch->cleared) {513/* under normal circumstances the requirement would be 4K514* but the fast clear path requires an alignment of 32K515*/516key->gmem_page_align = 8;517} else if (is_a6xx(screen)) {518key->gmem_page_align = (screen->info->tile_align_w == 96) ? 3 : 1;519} else {520// TODO re-check this across gens.. maybe it should only521// be a single page in some cases:522key->gmem_page_align = 4;523}524525return key;526}527528static struct fd_gmem_stateobj *529lookup_gmem_state(struct fd_batch *batch, bool assume_zs, bool no_scis_opt)530{531struct fd_screen *screen = batch->ctx->screen;532struct fd_gmem_cache *cache = &screen->gmem_cache;533struct fd_gmem_stateobj *gmem = NULL;534535/* Lock before allocating gmem_key, since that a screen-wide536* ralloc pool and ralloc itself is not thread-safe.537*/538fd_screen_lock(screen);539540struct gmem_key *key = gmem_key_init(batch, assume_zs, no_scis_opt);541uint32_t hash = gmem_key_hash(key);542543struct hash_entry *entry =544_mesa_hash_table_search_pre_hashed(cache->ht, hash, key);545if (entry) {546ralloc_free(key);547goto found;548}549550/* limit the # of cached gmem states, discarding the least551* recently used state if needed:552*/553if (cache->ht->entries >= 20) {554struct fd_gmem_stateobj *last =555list_last_entry(&cache->lru, struct fd_gmem_stateobj, node);556fd_gmem_reference(&last, NULL);557}558559entry = _mesa_hash_table_insert_pre_hashed(cache->ht, hash, key,560gmem_stateobj_init(screen, key));561562found:563fd_gmem_reference(&gmem, entry->data);564/* Move to the head of the LRU: */565list_delinit(&gmem->node);566list_add(&gmem->node, &cache->lru);567568fd_screen_unlock(screen);569570return gmem;571}572573/*574* GMEM render pass575*/576577static void578render_tiles(struct fd_batch *batch, struct fd_gmem_stateobj *gmem) assert_dt579{580struct fd_context *ctx = batch->ctx;581int i;582583simple_mtx_lock(&ctx->gmem_lock);584585ctx->emit_tile_init(batch);586587if (batch->restore)588ctx->stats.batch_restore++;589590for (i = 0; i < (gmem->nbins_x * gmem->nbins_y); i++) {591struct fd_tile *tile = &gmem->tile[i];592593trace_start_tile(&batch->trace, tile->bin_h, tile->yoff, tile->bin_w,594tile->xoff);595596ctx->emit_tile_prep(batch, tile);597598if (batch->restore) {599ctx->emit_tile_mem2gmem(batch, tile);600}601602ctx->emit_tile_renderprep(batch, tile);603604if (ctx->query_prepare_tile)605ctx->query_prepare_tile(batch, i, batch->gmem);606607/* emit IB to drawcmds: */608trace_start_draw_ib(&batch->trace);609if (ctx->emit_tile) {610ctx->emit_tile(batch, tile);611} else {612ctx->screen->emit_ib(batch->gmem, batch->draw);613}614trace_end_draw_ib(&batch->trace);615fd_reset_wfi(batch);616617/* emit gmem2mem to transfer tile back to system memory: */618ctx->emit_tile_gmem2mem(batch, tile);619}620621if (ctx->emit_tile_fini)622ctx->emit_tile_fini(batch);623624simple_mtx_unlock(&ctx->gmem_lock);625}626627static void628render_sysmem(struct fd_batch *batch) assert_dt629{630struct fd_context *ctx = batch->ctx;631632ctx->emit_sysmem_prep(batch);633634if (ctx->query_prepare_tile)635ctx->query_prepare_tile(batch, 0, batch->gmem);636637if (!batch->nondraw) {638trace_start_draw_ib(&batch->trace);639}640/* emit IB to drawcmds: */641ctx->screen->emit_ib(batch->gmem, batch->draw);642643if (!batch->nondraw) {644trace_end_draw_ib(&batch->trace);645}646647fd_reset_wfi(batch);648649if (ctx->emit_sysmem_fini)650ctx->emit_sysmem_fini(batch);651}652653static void654flush_ring(struct fd_batch *batch)655{656if (FD_DBG(NOHW))657return;658659fd_submit_flush(batch->submit, batch->in_fence_fd,660batch->fence ? &batch->fence->submit_fence : NULL);661662if (batch->fence)663fd_fence_set_batch(batch->fence, NULL);664}665666void667fd_gmem_render_tiles(struct fd_batch *batch)668{669struct fd_context *ctx = batch->ctx;670struct pipe_framebuffer_state *pfb = &batch->framebuffer;671bool sysmem = false;672673ctx->submit_count++;674675if (!batch->nondraw) {676#if HAVE_PERFETTO677/* For non-draw batches, we don't really have a good place to678* match up the api event submit-id to the on-gpu rendering,679* so skip this for non-draw batches.680*/681fd_perfetto_submit(ctx);682#endif683trace_flush_batch(&batch->trace, batch, batch->cleared,684batch->gmem_reason, batch->num_draws);685trace_framebuffer_state(&batch->trace, pfb);686}687688if (ctx->emit_sysmem_prep && !batch->nondraw) {689if (fd_autotune_use_bypass(&ctx->autotune, batch) && !FD_DBG(NOBYPASS)) {690sysmem = true;691}692693/* For ARB_framebuffer_no_attachments: */694if ((pfb->nr_cbufs == 0) && !pfb->zsbuf) {695sysmem = true;696}697}698699if (FD_DBG(NOGMEM))700sysmem = true;701702/* Layered rendering always needs bypass. */703for (unsigned i = 0; i < pfb->nr_cbufs; i++) {704struct pipe_surface *psurf = pfb->cbufs[i];705if (!psurf)706continue;707if (psurf->u.tex.first_layer < psurf->u.tex.last_layer)708sysmem = true;709}710711/* Tessellation doesn't seem to support tiled rendering so fall back to712* bypass.713*/714if (batch->tessellation) {715debug_assert(ctx->emit_sysmem_prep);716sysmem = true;717}718719fd_reset_wfi(batch);720721ctx->stats.batch_total++;722723if (batch->nondraw) {724DBG("%p: rendering non-draw", batch);725render_sysmem(batch);726ctx->stats.batch_nondraw++;727} else if (sysmem) {728trace_render_sysmem(&batch->trace);729trace_start_render_pass(730&batch->trace, ctx->submit_count, pipe_surface_format(pfb->cbufs[0]),731pipe_surface_format(pfb->zsbuf), pfb->width, pfb->height,732pfb->nr_cbufs, pfb->samples, 0, 0, 0);733if (ctx->query_prepare)734ctx->query_prepare(batch, 1);735render_sysmem(batch);736trace_end_render_pass(&batch->trace);737ctx->stats.batch_sysmem++;738} else {739struct fd_gmem_stateobj *gmem = lookup_gmem_state(batch, false, false);740batch->gmem_state = gmem;741trace_render_gmem(&batch->trace, gmem->nbins_x, gmem->nbins_y,742gmem->bin_w, gmem->bin_h);743trace_start_render_pass(744&batch->trace, ctx->submit_count, pipe_surface_format(pfb->cbufs[0]),745pipe_surface_format(pfb->zsbuf), pfb->width, pfb->height,746pfb->nr_cbufs, pfb->samples, gmem->nbins_x * gmem->nbins_y,747gmem->bin_w, gmem->bin_h);748if (ctx->query_prepare)749ctx->query_prepare(batch, gmem->nbins_x * gmem->nbins_y);750render_tiles(batch, gmem);751trace_end_render_pass(&batch->trace);752batch->gmem_state = NULL;753754fd_screen_lock(ctx->screen);755fd_gmem_reference(&gmem, NULL);756fd_screen_unlock(ctx->screen);757758ctx->stats.batch_gmem++;759}760761flush_ring(batch);762763u_trace_flush(&batch->trace);764}765766/* Determine a worst-case estimate (ie. assuming we don't eliminate an767* unused depth/stencil) number of bins per vsc pipe.768*/769unsigned770fd_gmem_estimate_bins_per_pipe(struct fd_batch *batch)771{772struct pipe_framebuffer_state *pfb = &batch->framebuffer;773struct fd_screen *screen = batch->ctx->screen;774struct fd_gmem_stateobj *gmem = lookup_gmem_state(batch, !!pfb->zsbuf, true);775unsigned nbins = gmem->maxpw * gmem->maxph;776777fd_screen_lock(screen);778fd_gmem_reference(&gmem, NULL);779fd_screen_unlock(screen);780781return nbins;782}783784/* When deciding whether a tile needs mem2gmem, we need to take into785* account the scissor rect(s) that were cleared. To simplify we only786* consider the last scissor rect for each buffer, since the common787* case would be a single clear.788*/789bool790fd_gmem_needs_restore(struct fd_batch *batch, const struct fd_tile *tile,791uint32_t buffers)792{793if (!(batch->restore & buffers))794return false;795796return true;797}798799void800fd_gmem_screen_init(struct pipe_screen *pscreen)801{802struct fd_gmem_cache *cache = &fd_screen(pscreen)->gmem_cache;803804cache->ht = _mesa_hash_table_create(NULL, gmem_key_hash, gmem_key_equals);805list_inithead(&cache->lru);806}807808void809fd_gmem_screen_fini(struct pipe_screen *pscreen)810{811struct fd_gmem_cache *cache = &fd_screen(pscreen)->gmem_cache;812813_mesa_hash_table_destroy(cache->ht, NULL);814}815816817