1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org> 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21bf215546Sopenharmony_ci * SOFTWARE. 22bf215546Sopenharmony_ci * 23bf215546Sopenharmony_ci * Authors: 24bf215546Sopenharmony_ci * Rob Clark <robclark@freedesktop.org> 25bf215546Sopenharmony_ci */ 26bf215546Sopenharmony_ci 27bf215546Sopenharmony_ci#include "util/format/u_format.h" 28bf215546Sopenharmony_ci#include "util/format/u_format_rgtc.h" 29bf215546Sopenharmony_ci#include "util/format/u_format_zs.h" 30bf215546Sopenharmony_ci#include "util/set.h" 31bf215546Sopenharmony_ci#include "util/u_drm.h" 32bf215546Sopenharmony_ci#include "util/u_inlines.h" 33bf215546Sopenharmony_ci#include "util/u_string.h" 34bf215546Sopenharmony_ci#include "util/u_surface.h" 35bf215546Sopenharmony_ci#include "util/u_transfer.h" 36bf215546Sopenharmony_ci 37bf215546Sopenharmony_ci#include "decode/util.h" 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_ci#include "freedreno_batch_cache.h" 40bf215546Sopenharmony_ci#include "freedreno_blitter.h" 41bf215546Sopenharmony_ci#include "freedreno_context.h" 42bf215546Sopenharmony_ci#include "freedreno_fence.h" 43bf215546Sopenharmony_ci#include "freedreno_query_hw.h" 44bf215546Sopenharmony_ci#include "freedreno_resource.h" 45bf215546Sopenharmony_ci#include "freedreno_screen.h" 46bf215546Sopenharmony_ci#include "freedreno_surface.h" 47bf215546Sopenharmony_ci#include "freedreno_util.h" 48bf215546Sopenharmony_ci 49bf215546Sopenharmony_ci#include <errno.h> 50bf215546Sopenharmony_ci#include "drm-uapi/drm_fourcc.h" 51bf215546Sopenharmony_ci 52bf215546Sopenharmony_ci/* XXX this should go away, needed for 'struct winsys_handle' */ 53bf215546Sopenharmony_ci#include "frontend/drm_driver.h" 54bf215546Sopenharmony_ci 55bf215546Sopenharmony_ci/* A private modifier for now, so we have a way to request tiled but not 56bf215546Sopenharmony_ci * compressed. It would perhaps be good to get real modifiers for the 57bf215546Sopenharmony_ci * tiled formats, but would probably need to do some work to figure out 58bf215546Sopenharmony_ci * the layout(s) of the tiled modes, and whether they are the same 59bf215546Sopenharmony_ci * across generations. 60bf215546Sopenharmony_ci */ 61bf215546Sopenharmony_ci#define FD_FORMAT_MOD_QCOM_TILED fourcc_mod_code(QCOM, 0xffffffff) 62bf215546Sopenharmony_ci 63bf215546Sopenharmony_ci/** 64bf215546Sopenharmony_ci * Go through the entire state and see if the resource is bound 65bf215546Sopenharmony_ci * anywhere. If it is, mark the relevant state as dirty. This is 66bf215546Sopenharmony_ci * called on realloc_bo to ensure the necessary state is re- 67bf215546Sopenharmony_ci * emitted so the GPU looks at the new backing bo. 68bf215546Sopenharmony_ci */ 69bf215546Sopenharmony_cistatic void 70bf215546Sopenharmony_cirebind_resource_in_ctx(struct fd_context *ctx, 71bf215546Sopenharmony_ci struct fd_resource *rsc) assert_dt 72bf215546Sopenharmony_ci{ 73bf215546Sopenharmony_ci struct pipe_resource *prsc = &rsc->b.b; 74bf215546Sopenharmony_ci 75bf215546Sopenharmony_ci if (ctx->rebind_resource) 76bf215546Sopenharmony_ci ctx->rebind_resource(ctx, rsc); 77bf215546Sopenharmony_ci 78bf215546Sopenharmony_ci /* VBOs */ 79bf215546Sopenharmony_ci if (rsc->dirty & FD_DIRTY_VTXBUF) { 80bf215546Sopenharmony_ci struct fd_vertexbuf_stateobj *vb = &ctx->vtx.vertexbuf; 81bf215546Sopenharmony_ci for (unsigned i = 0; i < vb->count && !(ctx->dirty & FD_DIRTY_VTXBUF); 82bf215546Sopenharmony_ci i++) { 83bf215546Sopenharmony_ci if (vb->vb[i].buffer.resource == prsc) 84bf215546Sopenharmony_ci fd_context_dirty(ctx, FD_DIRTY_VTXBUF); 85bf215546Sopenharmony_ci } 86bf215546Sopenharmony_ci } 87bf215546Sopenharmony_ci 88bf215546Sopenharmony_ci const enum fd_dirty_3d_state per_stage_dirty = 89bf215546Sopenharmony_ci FD_DIRTY_CONST | FD_DIRTY_TEX | FD_DIRTY_IMAGE | FD_DIRTY_SSBO; 90bf215546Sopenharmony_ci 91bf215546Sopenharmony_ci if (!(rsc->dirty & per_stage_dirty)) 92bf215546Sopenharmony_ci return; 93bf215546Sopenharmony_ci 94bf215546Sopenharmony_ci /* per-shader-stage resources: */ 95bf215546Sopenharmony_ci for (unsigned stage = 0; stage < PIPE_SHADER_TYPES; stage++) { 96bf215546Sopenharmony_ci /* Constbufs.. note that constbuf[0] is normal uniforms emitted in 97bf215546Sopenharmony_ci * cmdstream rather than by pointer.. 98bf215546Sopenharmony_ci */ 99bf215546Sopenharmony_ci if ((rsc->dirty & FD_DIRTY_CONST) && 100bf215546Sopenharmony_ci !(ctx->dirty_shader[stage] & FD_DIRTY_CONST)) { 101bf215546Sopenharmony_ci struct fd_constbuf_stateobj *cb = &ctx->constbuf[stage]; 102bf215546Sopenharmony_ci const unsigned num_ubos = util_last_bit(cb->enabled_mask); 103bf215546Sopenharmony_ci for (unsigned i = 1; i < num_ubos; i++) { 104bf215546Sopenharmony_ci if (cb->cb[i].buffer == prsc) { 105bf215546Sopenharmony_ci fd_context_dirty_shader(ctx, stage, FD_DIRTY_SHADER_CONST); 106bf215546Sopenharmony_ci break; 107bf215546Sopenharmony_ci } 108bf215546Sopenharmony_ci } 109bf215546Sopenharmony_ci } 110bf215546Sopenharmony_ci 111bf215546Sopenharmony_ci /* Textures */ 112bf215546Sopenharmony_ci if ((rsc->dirty & FD_DIRTY_TEX) && 113bf215546Sopenharmony_ci !(ctx->dirty_shader[stage] & FD_DIRTY_TEX)) { 114bf215546Sopenharmony_ci struct fd_texture_stateobj *tex = &ctx->tex[stage]; 115bf215546Sopenharmony_ci for (unsigned i = 0; i < tex->num_textures; i++) { 116bf215546Sopenharmony_ci if (tex->textures[i] && (tex->textures[i]->texture == prsc)) { 117bf215546Sopenharmony_ci fd_context_dirty_shader(ctx, stage, FD_DIRTY_SHADER_TEX); 118bf215546Sopenharmony_ci break; 119bf215546Sopenharmony_ci } 120bf215546Sopenharmony_ci } 121bf215546Sopenharmony_ci } 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_ci /* Images */ 124bf215546Sopenharmony_ci if ((rsc->dirty & FD_DIRTY_IMAGE) && 125bf215546Sopenharmony_ci !(ctx->dirty_shader[stage] & FD_DIRTY_IMAGE)) { 126bf215546Sopenharmony_ci struct fd_shaderimg_stateobj *si = &ctx->shaderimg[stage]; 127bf215546Sopenharmony_ci const unsigned num_images = util_last_bit(si->enabled_mask); 128bf215546Sopenharmony_ci for (unsigned i = 0; i < num_images; i++) { 129bf215546Sopenharmony_ci if (si->si[i].resource == prsc) { 130bf215546Sopenharmony_ci fd_context_dirty_shader(ctx, stage, FD_DIRTY_SHADER_IMAGE); 131bf215546Sopenharmony_ci break; 132bf215546Sopenharmony_ci } 133bf215546Sopenharmony_ci } 134bf215546Sopenharmony_ci } 135bf215546Sopenharmony_ci 136bf215546Sopenharmony_ci /* SSBOs */ 137bf215546Sopenharmony_ci if ((rsc->dirty & FD_DIRTY_SSBO) && 138bf215546Sopenharmony_ci !(ctx->dirty_shader[stage] & FD_DIRTY_SSBO)) { 139bf215546Sopenharmony_ci struct fd_shaderbuf_stateobj *sb = &ctx->shaderbuf[stage]; 140bf215546Sopenharmony_ci const unsigned num_ssbos = util_last_bit(sb->enabled_mask); 141bf215546Sopenharmony_ci for (unsigned i = 0; i < num_ssbos; i++) { 142bf215546Sopenharmony_ci if (sb->sb[i].buffer == prsc) { 143bf215546Sopenharmony_ci fd_context_dirty_shader(ctx, stage, FD_DIRTY_SHADER_SSBO); 144bf215546Sopenharmony_ci break; 145bf215546Sopenharmony_ci } 146bf215546Sopenharmony_ci } 147bf215546Sopenharmony_ci } 148bf215546Sopenharmony_ci } 149bf215546Sopenharmony_ci} 150bf215546Sopenharmony_ci 151bf215546Sopenharmony_cistatic void 152bf215546Sopenharmony_cirebind_resource(struct fd_resource *rsc) assert_dt 153bf215546Sopenharmony_ci{ 154bf215546Sopenharmony_ci struct fd_screen *screen = fd_screen(rsc->b.b.screen); 155bf215546Sopenharmony_ci 156bf215546Sopenharmony_ci fd_screen_lock(screen); 157bf215546Sopenharmony_ci fd_resource_lock(rsc); 158bf215546Sopenharmony_ci 159bf215546Sopenharmony_ci if (rsc->dirty) 160bf215546Sopenharmony_ci list_for_each_entry (struct fd_context, ctx, &screen->context_list, node) 161bf215546Sopenharmony_ci rebind_resource_in_ctx(ctx, rsc); 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_ci fd_resource_unlock(rsc); 164bf215546Sopenharmony_ci fd_screen_unlock(screen); 165bf215546Sopenharmony_ci} 166bf215546Sopenharmony_ci 167bf215546Sopenharmony_cistatic inline void 168bf215546Sopenharmony_cifd_resource_set_bo(struct fd_resource *rsc, struct fd_bo *bo) 169bf215546Sopenharmony_ci{ 170bf215546Sopenharmony_ci struct fd_screen *screen = fd_screen(rsc->b.b.screen); 171bf215546Sopenharmony_ci 172bf215546Sopenharmony_ci rsc->bo = bo; 173bf215546Sopenharmony_ci rsc->seqno = p_atomic_inc_return(&screen->rsc_seqno); 174bf215546Sopenharmony_ci} 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_ciint 177bf215546Sopenharmony_ci__fd_resource_wait(struct fd_context *ctx, struct fd_resource *rsc, unsigned op, 178bf215546Sopenharmony_ci const char *func) 179bf215546Sopenharmony_ci{ 180bf215546Sopenharmony_ci if (op & FD_BO_PREP_NOSYNC) 181bf215546Sopenharmony_ci return fd_bo_cpu_prep(rsc->bo, ctx->pipe, op); 182bf215546Sopenharmony_ci 183bf215546Sopenharmony_ci int ret; 184bf215546Sopenharmony_ci 185bf215546Sopenharmony_ci perf_time_ctx (ctx, 10000, "%s: a busy \"%" PRSC_FMT "\" BO stalled", func, 186bf215546Sopenharmony_ci PRSC_ARGS(&rsc->b.b)) { 187bf215546Sopenharmony_ci ret = fd_bo_cpu_prep(rsc->bo, ctx->pipe, op); 188bf215546Sopenharmony_ci } 189bf215546Sopenharmony_ci 190bf215546Sopenharmony_ci return ret; 191bf215546Sopenharmony_ci} 192bf215546Sopenharmony_ci 193bf215546Sopenharmony_cistatic void 194bf215546Sopenharmony_cirealloc_bo(struct fd_resource *rsc, uint32_t size) 195bf215546Sopenharmony_ci{ 196bf215546Sopenharmony_ci struct pipe_resource *prsc = &rsc->b.b; 197bf215546Sopenharmony_ci struct fd_screen *screen = fd_screen(rsc->b.b.screen); 198bf215546Sopenharmony_ci uint32_t flags = 199bf215546Sopenharmony_ci COND(rsc->layout.tile_mode, FD_BO_NOMAP) | 200bf215546Sopenharmony_ci COND(prsc->usage & PIPE_USAGE_STAGING, FD_BO_CACHED_COHERENT) | 201bf215546Sopenharmony_ci COND(prsc->bind & PIPE_BIND_SHARED, FD_BO_SHARED) | 202bf215546Sopenharmony_ci COND(prsc->bind & PIPE_BIND_SCANOUT, FD_BO_SCANOUT); 203bf215546Sopenharmony_ci /* TODO other flags? */ 204bf215546Sopenharmony_ci 205bf215546Sopenharmony_ci /* if we start using things other than write-combine, 206bf215546Sopenharmony_ci * be sure to check for PIPE_RESOURCE_FLAG_MAP_COHERENT 207bf215546Sopenharmony_ci */ 208bf215546Sopenharmony_ci 209bf215546Sopenharmony_ci if (rsc->bo) 210bf215546Sopenharmony_ci fd_bo_del(rsc->bo); 211bf215546Sopenharmony_ci 212bf215546Sopenharmony_ci struct fd_bo *bo = 213bf215546Sopenharmony_ci fd_bo_new(screen->dev, size, flags, "%ux%ux%u@%u:%x", prsc->width0, 214bf215546Sopenharmony_ci prsc->height0, prsc->depth0, rsc->layout.cpp, prsc->bind); 215bf215546Sopenharmony_ci fd_resource_set_bo(rsc, bo); 216bf215546Sopenharmony_ci 217bf215546Sopenharmony_ci /* Zero out the UBWC area on allocation. This fixes intermittent failures 218bf215546Sopenharmony_ci * with UBWC, which I suspect are due to the HW having a hard time 219bf215546Sopenharmony_ci * interpreting arbitrary values populating the flags buffer when the BO 220bf215546Sopenharmony_ci * was recycled through the bo cache (instead of fresh allocations from 221bf215546Sopenharmony_ci * the kernel, which are zeroed). sleep(1) in this spot didn't work 222bf215546Sopenharmony_ci * around the issue, but any memset value seems to. 223bf215546Sopenharmony_ci */ 224bf215546Sopenharmony_ci if (rsc->layout.ubwc) { 225bf215546Sopenharmony_ci rsc->needs_ubwc_clear = true; 226bf215546Sopenharmony_ci } 227bf215546Sopenharmony_ci 228bf215546Sopenharmony_ci util_range_set_empty(&rsc->valid_buffer_range); 229bf215546Sopenharmony_ci fd_bc_invalidate_resource(rsc, true); 230bf215546Sopenharmony_ci} 231bf215546Sopenharmony_ci 232bf215546Sopenharmony_cistatic void 233bf215546Sopenharmony_cido_blit(struct fd_context *ctx, const struct pipe_blit_info *blit, 234bf215546Sopenharmony_ci bool fallback) assert_dt 235bf215546Sopenharmony_ci{ 236bf215546Sopenharmony_ci struct pipe_context *pctx = &ctx->base; 237bf215546Sopenharmony_ci 238bf215546Sopenharmony_ci assert(!ctx->in_blit); 239bf215546Sopenharmony_ci ctx->in_blit = true; 240bf215546Sopenharmony_ci 241bf215546Sopenharmony_ci /* TODO size threshold too?? */ 242bf215546Sopenharmony_ci if (fallback || !fd_blit(pctx, blit)) { 243bf215546Sopenharmony_ci /* do blit on cpu: */ 244bf215546Sopenharmony_ci util_resource_copy_region(pctx, blit->dst.resource, blit->dst.level, 245bf215546Sopenharmony_ci blit->dst.box.x, blit->dst.box.y, 246bf215546Sopenharmony_ci blit->dst.box.z, blit->src.resource, 247bf215546Sopenharmony_ci blit->src.level, &blit->src.box); 248bf215546Sopenharmony_ci } 249bf215546Sopenharmony_ci 250bf215546Sopenharmony_ci ctx->in_blit = false; 251bf215546Sopenharmony_ci} 252bf215546Sopenharmony_ci 253bf215546Sopenharmony_ci/** 254bf215546Sopenharmony_ci * Replace the storage of dst with src. This is only used by TC in the 255bf215546Sopenharmony_ci * DISCARD_WHOLE_RESOURCE path, and src is a freshly allocated buffer. 256bf215546Sopenharmony_ci */ 257bf215546Sopenharmony_civoid 258bf215546Sopenharmony_cifd_replace_buffer_storage(struct pipe_context *pctx, struct pipe_resource *pdst, 259bf215546Sopenharmony_ci struct pipe_resource *psrc, unsigned num_rebinds, uint32_t rebind_mask, 260bf215546Sopenharmony_ci uint32_t delete_buffer_id) 261bf215546Sopenharmony_ci{ 262bf215546Sopenharmony_ci struct fd_context *ctx = fd_context(pctx); 263bf215546Sopenharmony_ci struct fd_resource *dst = fd_resource(pdst); 264bf215546Sopenharmony_ci struct fd_resource *src = fd_resource(psrc); 265bf215546Sopenharmony_ci 266bf215546Sopenharmony_ci DBG("pdst=%p, psrc=%p", pdst, psrc); 267bf215546Sopenharmony_ci 268bf215546Sopenharmony_ci /* This should only be called with buffers.. which side-steps some tricker 269bf215546Sopenharmony_ci * cases, like a rsc that is in a batch-cache key... 270bf215546Sopenharmony_ci */ 271bf215546Sopenharmony_ci assert(pdst->target == PIPE_BUFFER); 272bf215546Sopenharmony_ci assert(psrc->target == PIPE_BUFFER); 273bf215546Sopenharmony_ci assert(dst->track->bc_batch_mask == 0); 274bf215546Sopenharmony_ci assert(src->track->bc_batch_mask == 0); 275bf215546Sopenharmony_ci assert(src->track->batch_mask == 0); 276bf215546Sopenharmony_ci assert(src->track->write_batch == NULL); 277bf215546Sopenharmony_ci assert(memcmp(&dst->layout, &src->layout, sizeof(dst->layout)) == 0); 278bf215546Sopenharmony_ci 279bf215546Sopenharmony_ci /* get rid of any references that batch-cache might have to us (which 280bf215546Sopenharmony_ci * should empty/destroy rsc->batches hashset) 281bf215546Sopenharmony_ci * 282bf215546Sopenharmony_ci * Note that we aren't actually destroying dst, but we are replacing 283bf215546Sopenharmony_ci * it's storage so we want to go thru the same motions of decoupling 284bf215546Sopenharmony_ci * it's batch connections. 285bf215546Sopenharmony_ci */ 286bf215546Sopenharmony_ci fd_bc_invalidate_resource(dst, true); 287bf215546Sopenharmony_ci rebind_resource(dst); 288bf215546Sopenharmony_ci 289bf215546Sopenharmony_ci util_idalloc_mt_free(&ctx->screen->buffer_ids, delete_buffer_id); 290bf215546Sopenharmony_ci 291bf215546Sopenharmony_ci fd_screen_lock(ctx->screen); 292bf215546Sopenharmony_ci 293bf215546Sopenharmony_ci fd_bo_del(dst->bo); 294bf215546Sopenharmony_ci dst->bo = fd_bo_ref(src->bo); 295bf215546Sopenharmony_ci 296bf215546Sopenharmony_ci fd_resource_tracking_reference(&dst->track, src->track); 297bf215546Sopenharmony_ci src->is_replacement = true; 298bf215546Sopenharmony_ci 299bf215546Sopenharmony_ci dst->seqno = p_atomic_inc_return(&ctx->screen->rsc_seqno); 300bf215546Sopenharmony_ci 301bf215546Sopenharmony_ci fd_screen_unlock(ctx->screen); 302bf215546Sopenharmony_ci} 303bf215546Sopenharmony_ci 304bf215546Sopenharmony_cistatic unsigned 305bf215546Sopenharmony_citranslate_usage(unsigned usage) 306bf215546Sopenharmony_ci{ 307bf215546Sopenharmony_ci uint32_t op = 0; 308bf215546Sopenharmony_ci 309bf215546Sopenharmony_ci if (usage & PIPE_MAP_READ) 310bf215546Sopenharmony_ci op |= FD_BO_PREP_READ; 311bf215546Sopenharmony_ci 312bf215546Sopenharmony_ci if (usage & PIPE_MAP_WRITE) 313bf215546Sopenharmony_ci op |= FD_BO_PREP_WRITE; 314bf215546Sopenharmony_ci 315bf215546Sopenharmony_ci return op; 316bf215546Sopenharmony_ci} 317bf215546Sopenharmony_ci 318bf215546Sopenharmony_cibool 319bf215546Sopenharmony_cifd_resource_busy(struct pipe_screen *pscreen, struct pipe_resource *prsc, 320bf215546Sopenharmony_ci unsigned usage) 321bf215546Sopenharmony_ci{ 322bf215546Sopenharmony_ci struct fd_resource *rsc = fd_resource(prsc); 323bf215546Sopenharmony_ci 324bf215546Sopenharmony_ci if (pending(rsc, !!(usage & PIPE_MAP_WRITE))) 325bf215546Sopenharmony_ci return true; 326bf215546Sopenharmony_ci 327bf215546Sopenharmony_ci if (resource_busy(rsc, translate_usage(usage))) 328bf215546Sopenharmony_ci return true; 329bf215546Sopenharmony_ci 330bf215546Sopenharmony_ci return false; 331bf215546Sopenharmony_ci} 332bf215546Sopenharmony_ci 333bf215546Sopenharmony_cistatic void flush_resource(struct fd_context *ctx, struct fd_resource *rsc, 334bf215546Sopenharmony_ci unsigned usage); 335bf215546Sopenharmony_ci 336bf215546Sopenharmony_ci/** 337bf215546Sopenharmony_ci * Helper to check if the format is something that we can blit/render 338bf215546Sopenharmony_ci * to.. if the format is not renderable, there is no point in trying 339bf215546Sopenharmony_ci * to do a staging blit (as it will still end up being a cpu copy) 340bf215546Sopenharmony_ci */ 341bf215546Sopenharmony_cistatic bool 342bf215546Sopenharmony_ciis_renderable(struct pipe_resource *prsc) 343bf215546Sopenharmony_ci{ 344bf215546Sopenharmony_ci struct pipe_screen *pscreen = prsc->screen; 345bf215546Sopenharmony_ci return pscreen->is_format_supported( 346bf215546Sopenharmony_ci pscreen, prsc->format, prsc->target, prsc->nr_samples, 347bf215546Sopenharmony_ci prsc->nr_storage_samples, PIPE_BIND_RENDER_TARGET); 348bf215546Sopenharmony_ci} 349bf215546Sopenharmony_ci 350bf215546Sopenharmony_ci/** 351bf215546Sopenharmony_ci * @rsc: the resource to shadow 352bf215546Sopenharmony_ci * @level: the level to discard (if box != NULL, otherwise ignored) 353bf215546Sopenharmony_ci * @box: the box to discard (or NULL if none) 354bf215546Sopenharmony_ci * @modifier: the modifier for the new buffer state 355bf215546Sopenharmony_ci */ 356bf215546Sopenharmony_cistatic bool 357bf215546Sopenharmony_cifd_try_shadow_resource(struct fd_context *ctx, struct fd_resource *rsc, 358bf215546Sopenharmony_ci unsigned level, const struct pipe_box *box, 359bf215546Sopenharmony_ci uint64_t modifier) assert_dt 360bf215546Sopenharmony_ci{ 361bf215546Sopenharmony_ci struct pipe_context *pctx = &ctx->base; 362bf215546Sopenharmony_ci struct pipe_resource *prsc = &rsc->b.b; 363bf215546Sopenharmony_ci struct fd_screen *screen = fd_screen(pctx->screen); 364bf215546Sopenharmony_ci struct fd_batch *batch; 365bf215546Sopenharmony_ci bool fallback = false; 366bf215546Sopenharmony_ci 367bf215546Sopenharmony_ci if (prsc->next) 368bf215546Sopenharmony_ci return false; 369bf215546Sopenharmony_ci 370bf215546Sopenharmony_ci /* Flush any pending batches writing the resource before we go mucking around 371bf215546Sopenharmony_ci * in its insides. The blit would immediately cause the batch to be flushed, 372bf215546Sopenharmony_ci * anyway. 373bf215546Sopenharmony_ci */ 374bf215546Sopenharmony_ci fd_bc_flush_writer(ctx, rsc); 375bf215546Sopenharmony_ci 376bf215546Sopenharmony_ci /* Because IB1 ("gmem") cmdstream is built only when we flush the 377bf215546Sopenharmony_ci * batch, we need to flush any batches that reference this rsc as 378bf215546Sopenharmony_ci * a render target. Otherwise the framebuffer state emitted in 379bf215546Sopenharmony_ci * IB1 will reference the resources new state, and not the state 380bf215546Sopenharmony_ci * at the point in time that the earlier draws referenced it. 381bf215546Sopenharmony_ci * 382bf215546Sopenharmony_ci * Note that being in the gmem key doesn't necessarily mean the 383bf215546Sopenharmony_ci * batch was considered a writer! 384bf215546Sopenharmony_ci */ 385bf215546Sopenharmony_ci foreach_batch (batch, &screen->batch_cache, rsc->track->bc_batch_mask) { 386bf215546Sopenharmony_ci fd_batch_flush(batch); 387bf215546Sopenharmony_ci } 388bf215546Sopenharmony_ci 389bf215546Sopenharmony_ci /* TODO: somehow munge dimensions and format to copy unsupported 390bf215546Sopenharmony_ci * render target format to something that is supported? 391bf215546Sopenharmony_ci */ 392bf215546Sopenharmony_ci if (!is_renderable(prsc)) 393bf215546Sopenharmony_ci fallback = true; 394bf215546Sopenharmony_ci 395bf215546Sopenharmony_ci /* do shadowing back-blits on the cpu for buffers -- requires about a page of 396bf215546Sopenharmony_ci * DMA to make GPU copies worth it according to robclark. Note, if you 397bf215546Sopenharmony_ci * decide to do it on the GPU then you'll need to update valid_buffer_range 398bf215546Sopenharmony_ci * in the swap()s below. 399bf215546Sopenharmony_ci */ 400bf215546Sopenharmony_ci if (prsc->target == PIPE_BUFFER) 401bf215546Sopenharmony_ci fallback = true; 402bf215546Sopenharmony_ci 403bf215546Sopenharmony_ci bool discard_whole_level = box && util_texrange_covers_whole_level( 404bf215546Sopenharmony_ci prsc, level, box->x, box->y, box->z, 405bf215546Sopenharmony_ci box->width, box->height, box->depth); 406bf215546Sopenharmony_ci 407bf215546Sopenharmony_ci /* TODO need to be more clever about current level */ 408bf215546Sopenharmony_ci if ((prsc->target >= PIPE_TEXTURE_2D) && box && !discard_whole_level) 409bf215546Sopenharmony_ci return false; 410bf215546Sopenharmony_ci 411bf215546Sopenharmony_ci struct pipe_resource *pshadow = pctx->screen->resource_create_with_modifiers( 412bf215546Sopenharmony_ci pctx->screen, prsc, &modifier, 1); 413bf215546Sopenharmony_ci 414bf215546Sopenharmony_ci if (!pshadow) 415bf215546Sopenharmony_ci return false; 416bf215546Sopenharmony_ci 417bf215546Sopenharmony_ci assert(!ctx->in_shadow); 418bf215546Sopenharmony_ci ctx->in_shadow = true; 419bf215546Sopenharmony_ci 420bf215546Sopenharmony_ci /* get rid of any references that batch-cache might have to us (which 421bf215546Sopenharmony_ci * should empty/destroy rsc->batches hashset) 422bf215546Sopenharmony_ci */ 423bf215546Sopenharmony_ci fd_bc_invalidate_resource(rsc, false); 424bf215546Sopenharmony_ci rebind_resource(rsc); 425bf215546Sopenharmony_ci 426bf215546Sopenharmony_ci fd_screen_lock(ctx->screen); 427bf215546Sopenharmony_ci 428bf215546Sopenharmony_ci /* Swap the backing bo's, so shadow becomes the old buffer, 429bf215546Sopenharmony_ci * blit from shadow to new buffer. From here on out, we 430bf215546Sopenharmony_ci * cannot fail. 431bf215546Sopenharmony_ci * 432bf215546Sopenharmony_ci * Note that we need to do it in this order, otherwise if 433bf215546Sopenharmony_ci * we go down cpu blit path, the recursive transfer_map() 434bf215546Sopenharmony_ci * sees the wrong status.. 435bf215546Sopenharmony_ci */ 436bf215546Sopenharmony_ci struct fd_resource *shadow = fd_resource(pshadow); 437bf215546Sopenharmony_ci 438bf215546Sopenharmony_ci DBG("shadow: %p (%d, %p) -> %p (%d, %p)", rsc, rsc->b.b.reference.count, 439bf215546Sopenharmony_ci rsc->track, shadow, shadow->b.b.reference.count, shadow->track); 440bf215546Sopenharmony_ci 441bf215546Sopenharmony_ci swap(rsc->bo, shadow->bo); 442bf215546Sopenharmony_ci swap(rsc->valid, shadow->valid); 443bf215546Sopenharmony_ci 444bf215546Sopenharmony_ci /* swap() doesn't work because you can't typeof() the bitfield. */ 445bf215546Sopenharmony_ci bool temp = shadow->needs_ubwc_clear; 446bf215546Sopenharmony_ci shadow->needs_ubwc_clear = rsc->needs_ubwc_clear; 447bf215546Sopenharmony_ci rsc->needs_ubwc_clear = temp; 448bf215546Sopenharmony_ci 449bf215546Sopenharmony_ci swap(rsc->layout, shadow->layout); 450bf215546Sopenharmony_ci rsc->seqno = p_atomic_inc_return(&ctx->screen->rsc_seqno); 451bf215546Sopenharmony_ci 452bf215546Sopenharmony_ci /* at this point, the newly created shadow buffer is not referenced 453bf215546Sopenharmony_ci * by any batches, but the existing rsc (probably) is. We need to 454bf215546Sopenharmony_ci * transfer those references over: 455bf215546Sopenharmony_ci */ 456bf215546Sopenharmony_ci assert(shadow->track->batch_mask == 0); 457bf215546Sopenharmony_ci foreach_batch (batch, &ctx->screen->batch_cache, rsc->track->batch_mask) { 458bf215546Sopenharmony_ci struct set_entry *entry = _mesa_set_search_pre_hashed(batch->resources, rsc->hash, rsc); 459bf215546Sopenharmony_ci _mesa_set_remove(batch->resources, entry); 460bf215546Sopenharmony_ci _mesa_set_add_pre_hashed(batch->resources, shadow->hash, shadow); 461bf215546Sopenharmony_ci } 462bf215546Sopenharmony_ci swap(rsc->track, shadow->track); 463bf215546Sopenharmony_ci 464bf215546Sopenharmony_ci fd_screen_unlock(ctx->screen); 465bf215546Sopenharmony_ci 466bf215546Sopenharmony_ci struct pipe_blit_info blit = {}; 467bf215546Sopenharmony_ci blit.dst.resource = prsc; 468bf215546Sopenharmony_ci blit.dst.format = prsc->format; 469bf215546Sopenharmony_ci blit.src.resource = pshadow; 470bf215546Sopenharmony_ci blit.src.format = pshadow->format; 471bf215546Sopenharmony_ci blit.mask = util_format_get_mask(prsc->format); 472bf215546Sopenharmony_ci blit.filter = PIPE_TEX_FILTER_NEAREST; 473bf215546Sopenharmony_ci 474bf215546Sopenharmony_ci#define set_box(field, val) \ 475bf215546Sopenharmony_ci do { \ 476bf215546Sopenharmony_ci blit.dst.field = (val); \ 477bf215546Sopenharmony_ci blit.src.field = (val); \ 478bf215546Sopenharmony_ci } while (0) 479bf215546Sopenharmony_ci 480bf215546Sopenharmony_ci /* Disable occlusion queries during shadow blits. */ 481bf215546Sopenharmony_ci bool saved_active_queries = ctx->active_queries; 482bf215546Sopenharmony_ci pctx->set_active_query_state(pctx, false); 483bf215546Sopenharmony_ci 484bf215546Sopenharmony_ci /* blit the other levels in their entirety: */ 485bf215546Sopenharmony_ci for (unsigned l = 0; l <= prsc->last_level; l++) { 486bf215546Sopenharmony_ci if (box && l == level) 487bf215546Sopenharmony_ci continue; 488bf215546Sopenharmony_ci 489bf215546Sopenharmony_ci /* just blit whole level: */ 490bf215546Sopenharmony_ci set_box(level, l); 491bf215546Sopenharmony_ci set_box(box.width, u_minify(prsc->width0, l)); 492bf215546Sopenharmony_ci set_box(box.height, u_minify(prsc->height0, l)); 493bf215546Sopenharmony_ci set_box(box.depth, u_minify(prsc->depth0, l)); 494bf215546Sopenharmony_ci 495bf215546Sopenharmony_ci for (int i = 0; i < prsc->array_size; i++) { 496bf215546Sopenharmony_ci set_box(box.z, i); 497bf215546Sopenharmony_ci do_blit(ctx, &blit, fallback); 498bf215546Sopenharmony_ci } 499bf215546Sopenharmony_ci } 500bf215546Sopenharmony_ci 501bf215546Sopenharmony_ci /* deal w/ current level specially, since we might need to split 502bf215546Sopenharmony_ci * it up into a couple blits: 503bf215546Sopenharmony_ci */ 504bf215546Sopenharmony_ci if (box && !discard_whole_level) { 505bf215546Sopenharmony_ci set_box(level, level); 506bf215546Sopenharmony_ci 507bf215546Sopenharmony_ci switch (prsc->target) { 508bf215546Sopenharmony_ci case PIPE_BUFFER: 509bf215546Sopenharmony_ci case PIPE_TEXTURE_1D: 510bf215546Sopenharmony_ci set_box(box.y, 0); 511bf215546Sopenharmony_ci set_box(box.z, 0); 512bf215546Sopenharmony_ci set_box(box.height, 1); 513bf215546Sopenharmony_ci set_box(box.depth, 1); 514bf215546Sopenharmony_ci 515bf215546Sopenharmony_ci if (box->x > 0) { 516bf215546Sopenharmony_ci set_box(box.x, 0); 517bf215546Sopenharmony_ci set_box(box.width, box->x); 518bf215546Sopenharmony_ci 519bf215546Sopenharmony_ci do_blit(ctx, &blit, fallback); 520bf215546Sopenharmony_ci } 521bf215546Sopenharmony_ci if ((box->x + box->width) < u_minify(prsc->width0, level)) { 522bf215546Sopenharmony_ci set_box(box.x, box->x + box->width); 523bf215546Sopenharmony_ci set_box(box.width, 524bf215546Sopenharmony_ci u_minify(prsc->width0, level) - (box->x + box->width)); 525bf215546Sopenharmony_ci 526bf215546Sopenharmony_ci do_blit(ctx, &blit, fallback); 527bf215546Sopenharmony_ci } 528bf215546Sopenharmony_ci break; 529bf215546Sopenharmony_ci case PIPE_TEXTURE_2D: 530bf215546Sopenharmony_ci /* TODO */ 531bf215546Sopenharmony_ci default: 532bf215546Sopenharmony_ci unreachable("TODO"); 533bf215546Sopenharmony_ci } 534bf215546Sopenharmony_ci } 535bf215546Sopenharmony_ci 536bf215546Sopenharmony_ci pctx->set_active_query_state(pctx, saved_active_queries); 537bf215546Sopenharmony_ci 538bf215546Sopenharmony_ci ctx->in_shadow = false; 539bf215546Sopenharmony_ci 540bf215546Sopenharmony_ci pipe_resource_reference(&pshadow, NULL); 541bf215546Sopenharmony_ci 542bf215546Sopenharmony_ci return true; 543bf215546Sopenharmony_ci} 544bf215546Sopenharmony_ci 545bf215546Sopenharmony_ci/** 546bf215546Sopenharmony_ci * Uncompress an UBWC compressed buffer "in place". This works basically 547bf215546Sopenharmony_ci * like resource shadowing, creating a new resource, and doing an uncompress 548bf215546Sopenharmony_ci * blit, and swapping the state between shadow and original resource so it 549bf215546Sopenharmony_ci * appears to the gallium frontends as if nothing changed. 550bf215546Sopenharmony_ci */ 551bf215546Sopenharmony_civoid 552bf215546Sopenharmony_cifd_resource_uncompress(struct fd_context *ctx, struct fd_resource *rsc, bool linear) 553bf215546Sopenharmony_ci{ 554bf215546Sopenharmony_ci tc_assert_driver_thread(ctx->tc); 555bf215546Sopenharmony_ci 556bf215546Sopenharmony_ci uint64_t modifier = linear ? DRM_FORMAT_MOD_LINEAR : FD_FORMAT_MOD_QCOM_TILED; 557bf215546Sopenharmony_ci 558bf215546Sopenharmony_ci bool success = fd_try_shadow_resource(ctx, rsc, 0, NULL, modifier); 559bf215546Sopenharmony_ci 560bf215546Sopenharmony_ci /* shadow should not fail in any cases where we need to uncompress: */ 561bf215546Sopenharmony_ci assert(success); 562bf215546Sopenharmony_ci} 563bf215546Sopenharmony_ci 564bf215546Sopenharmony_ci/** 565bf215546Sopenharmony_ci * Debug helper to hexdump a resource. 566bf215546Sopenharmony_ci */ 567bf215546Sopenharmony_civoid 568bf215546Sopenharmony_cifd_resource_dump(struct fd_resource *rsc, const char *name) 569bf215546Sopenharmony_ci{ 570bf215546Sopenharmony_ci fd_bo_cpu_prep(rsc->bo, NULL, FD_BO_PREP_READ); 571bf215546Sopenharmony_ci printf("%s: \n", name); 572bf215546Sopenharmony_ci dump_hex(fd_bo_map(rsc->bo), fd_bo_size(rsc->bo)); 573bf215546Sopenharmony_ci} 574bf215546Sopenharmony_ci 575bf215546Sopenharmony_cistatic struct fd_resource * 576bf215546Sopenharmony_cifd_alloc_staging(struct fd_context *ctx, struct fd_resource *rsc, 577bf215546Sopenharmony_ci unsigned level, const struct pipe_box *box) 578bf215546Sopenharmony_ci assert_dt 579bf215546Sopenharmony_ci{ 580bf215546Sopenharmony_ci struct pipe_context *pctx = &ctx->base; 581bf215546Sopenharmony_ci struct pipe_resource tmpl = rsc->b.b; 582bf215546Sopenharmony_ci 583bf215546Sopenharmony_ci /* We cannot currently do stencil export on earlier gens, and 584bf215546Sopenharmony_ci * u_blitter cannot do blits involving stencil otherwise: 585bf215546Sopenharmony_ci */ 586bf215546Sopenharmony_ci if ((ctx->screen->gen < 6) && !ctx->blit && 587bf215546Sopenharmony_ci (util_format_get_mask(tmpl.format) & PIPE_MASK_S)) 588bf215546Sopenharmony_ci return NULL; 589bf215546Sopenharmony_ci 590bf215546Sopenharmony_ci tmpl.width0 = box->width; 591bf215546Sopenharmony_ci tmpl.height0 = box->height; 592bf215546Sopenharmony_ci /* for array textures, box->depth is the array_size, otherwise 593bf215546Sopenharmony_ci * for 3d textures, it is the depth: 594bf215546Sopenharmony_ci */ 595bf215546Sopenharmony_ci if (tmpl.array_size > 1) { 596bf215546Sopenharmony_ci if (tmpl.target == PIPE_TEXTURE_CUBE) 597bf215546Sopenharmony_ci tmpl.target = PIPE_TEXTURE_2D_ARRAY; 598bf215546Sopenharmony_ci tmpl.array_size = box->depth; 599bf215546Sopenharmony_ci tmpl.depth0 = 1; 600bf215546Sopenharmony_ci } else { 601bf215546Sopenharmony_ci tmpl.array_size = 1; 602bf215546Sopenharmony_ci tmpl.depth0 = box->depth; 603bf215546Sopenharmony_ci } 604bf215546Sopenharmony_ci tmpl.last_level = 0; 605bf215546Sopenharmony_ci tmpl.bind |= PIPE_BIND_LINEAR; 606bf215546Sopenharmony_ci tmpl.usage = PIPE_USAGE_STAGING; 607bf215546Sopenharmony_ci 608bf215546Sopenharmony_ci struct pipe_resource *pstaging = 609bf215546Sopenharmony_ci pctx->screen->resource_create(pctx->screen, &tmpl); 610bf215546Sopenharmony_ci if (!pstaging) 611bf215546Sopenharmony_ci return NULL; 612bf215546Sopenharmony_ci 613bf215546Sopenharmony_ci return fd_resource(pstaging); 614bf215546Sopenharmony_ci} 615bf215546Sopenharmony_ci 616bf215546Sopenharmony_cistatic void 617bf215546Sopenharmony_cifd_blit_from_staging(struct fd_context *ctx, 618bf215546Sopenharmony_ci struct fd_transfer *trans) assert_dt 619bf215546Sopenharmony_ci{ 620bf215546Sopenharmony_ci DBG(""); 621bf215546Sopenharmony_ci struct pipe_resource *dst = trans->b.b.resource; 622bf215546Sopenharmony_ci struct pipe_blit_info blit = {}; 623bf215546Sopenharmony_ci 624bf215546Sopenharmony_ci blit.dst.resource = dst; 625bf215546Sopenharmony_ci blit.dst.format = dst->format; 626bf215546Sopenharmony_ci blit.dst.level = trans->b.b.level; 627bf215546Sopenharmony_ci blit.dst.box = trans->b.b.box; 628bf215546Sopenharmony_ci blit.src.resource = trans->staging_prsc; 629bf215546Sopenharmony_ci blit.src.format = trans->staging_prsc->format; 630bf215546Sopenharmony_ci blit.src.level = 0; 631bf215546Sopenharmony_ci blit.src.box = trans->staging_box; 632bf215546Sopenharmony_ci blit.mask = util_format_get_mask(trans->staging_prsc->format); 633bf215546Sopenharmony_ci blit.filter = PIPE_TEX_FILTER_NEAREST; 634bf215546Sopenharmony_ci 635bf215546Sopenharmony_ci do_blit(ctx, &blit, false); 636bf215546Sopenharmony_ci} 637bf215546Sopenharmony_ci 638bf215546Sopenharmony_cistatic void 639bf215546Sopenharmony_cifd_blit_to_staging(struct fd_context *ctx, struct fd_transfer *trans) assert_dt 640bf215546Sopenharmony_ci{ 641bf215546Sopenharmony_ci DBG(""); 642bf215546Sopenharmony_ci struct pipe_resource *src = trans->b.b.resource; 643bf215546Sopenharmony_ci struct pipe_blit_info blit = {}; 644bf215546Sopenharmony_ci 645bf215546Sopenharmony_ci blit.src.resource = src; 646bf215546Sopenharmony_ci blit.src.format = src->format; 647bf215546Sopenharmony_ci blit.src.level = trans->b.b.level; 648bf215546Sopenharmony_ci blit.src.box = trans->b.b.box; 649bf215546Sopenharmony_ci blit.dst.resource = trans->staging_prsc; 650bf215546Sopenharmony_ci blit.dst.format = trans->staging_prsc->format; 651bf215546Sopenharmony_ci blit.dst.level = 0; 652bf215546Sopenharmony_ci blit.dst.box = trans->staging_box; 653bf215546Sopenharmony_ci blit.mask = util_format_get_mask(trans->staging_prsc->format); 654bf215546Sopenharmony_ci blit.filter = PIPE_TEX_FILTER_NEAREST; 655bf215546Sopenharmony_ci 656bf215546Sopenharmony_ci do_blit(ctx, &blit, false); 657bf215546Sopenharmony_ci} 658bf215546Sopenharmony_ci 659bf215546Sopenharmony_cistatic void 660bf215546Sopenharmony_cifd_resource_transfer_flush_region(struct pipe_context *pctx, 661bf215546Sopenharmony_ci struct pipe_transfer *ptrans, 662bf215546Sopenharmony_ci const struct pipe_box *box) 663bf215546Sopenharmony_ci{ 664bf215546Sopenharmony_ci struct fd_resource *rsc = fd_resource(ptrans->resource); 665bf215546Sopenharmony_ci 666bf215546Sopenharmony_ci if (ptrans->resource->target == PIPE_BUFFER) 667bf215546Sopenharmony_ci util_range_add(&rsc->b.b, &rsc->valid_buffer_range, 668bf215546Sopenharmony_ci ptrans->box.x + box->x, 669bf215546Sopenharmony_ci ptrans->box.x + box->x + box->width); 670bf215546Sopenharmony_ci} 671bf215546Sopenharmony_ci 672bf215546Sopenharmony_cistatic void 673bf215546Sopenharmony_ciflush_resource(struct fd_context *ctx, struct fd_resource *rsc, 674bf215546Sopenharmony_ci unsigned usage) assert_dt 675bf215546Sopenharmony_ci{ 676bf215546Sopenharmony_ci if (usage & PIPE_MAP_WRITE) { 677bf215546Sopenharmony_ci fd_bc_flush_readers(ctx, rsc); 678bf215546Sopenharmony_ci } else { 679bf215546Sopenharmony_ci fd_bc_flush_writer(ctx, rsc); 680bf215546Sopenharmony_ci } 681bf215546Sopenharmony_ci} 682bf215546Sopenharmony_ci 683bf215546Sopenharmony_cistatic void 684bf215546Sopenharmony_cifd_flush_resource(struct pipe_context *pctx, struct pipe_resource *prsc) 685bf215546Sopenharmony_ci in_dt 686bf215546Sopenharmony_ci{ 687bf215546Sopenharmony_ci struct fd_context *ctx = fd_context(pctx); 688bf215546Sopenharmony_ci struct fd_resource *rsc = fd_resource(prsc); 689bf215546Sopenharmony_ci 690bf215546Sopenharmony_ci flush_resource(ctx, rsc, PIPE_MAP_READ); 691bf215546Sopenharmony_ci 692bf215546Sopenharmony_ci /* If we had to flush a batch, make sure it makes it's way all the 693bf215546Sopenharmony_ci * way to the kernel: 694bf215546Sopenharmony_ci */ 695bf215546Sopenharmony_ci fd_resource_wait(ctx, rsc, FD_BO_PREP_FLUSH); 696bf215546Sopenharmony_ci} 697bf215546Sopenharmony_ci 698bf215546Sopenharmony_cistatic void 699bf215546Sopenharmony_cifd_resource_transfer_unmap(struct pipe_context *pctx, 700bf215546Sopenharmony_ci struct pipe_transfer *ptrans) 701bf215546Sopenharmony_ci in_dt /* TODO for threaded-ctx we'll need to split out unsynchronized path */ 702bf215546Sopenharmony_ci{ 703bf215546Sopenharmony_ci struct fd_context *ctx = fd_context(pctx); 704bf215546Sopenharmony_ci struct fd_resource *rsc = fd_resource(ptrans->resource); 705bf215546Sopenharmony_ci struct fd_transfer *trans = fd_transfer(ptrans); 706bf215546Sopenharmony_ci 707bf215546Sopenharmony_ci if (trans->staging_prsc) { 708bf215546Sopenharmony_ci if (ptrans->usage & PIPE_MAP_WRITE) 709bf215546Sopenharmony_ci fd_blit_from_staging(ctx, trans); 710bf215546Sopenharmony_ci pipe_resource_reference(&trans->staging_prsc, NULL); 711bf215546Sopenharmony_ci } 712bf215546Sopenharmony_ci 713bf215546Sopenharmony_ci if (!(ptrans->usage & PIPE_MAP_UNSYNCHRONIZED)) { 714bf215546Sopenharmony_ci fd_bo_cpu_fini(rsc->bo); 715bf215546Sopenharmony_ci } 716bf215546Sopenharmony_ci 717bf215546Sopenharmony_ci util_range_add(&rsc->b.b, &rsc->valid_buffer_range, ptrans->box.x, 718bf215546Sopenharmony_ci ptrans->box.x + ptrans->box.width); 719bf215546Sopenharmony_ci 720bf215546Sopenharmony_ci pipe_resource_reference(&ptrans->resource, NULL); 721bf215546Sopenharmony_ci 722bf215546Sopenharmony_ci assert(trans->b.staging == NULL); /* for threaded context only */ 723bf215546Sopenharmony_ci 724bf215546Sopenharmony_ci /* Don't use pool_transfers_unsync. We are always in the driver 725bf215546Sopenharmony_ci * thread. Freeing an object into a different pool is allowed. 726bf215546Sopenharmony_ci */ 727bf215546Sopenharmony_ci slab_free(&ctx->transfer_pool, ptrans); 728bf215546Sopenharmony_ci} 729bf215546Sopenharmony_ci 730bf215546Sopenharmony_cistatic void 731bf215546Sopenharmony_ciinvalidate_resource(struct fd_resource *rsc, unsigned usage) assert_dt 732bf215546Sopenharmony_ci{ 733bf215546Sopenharmony_ci bool needs_flush = pending(rsc, !!(usage & PIPE_MAP_WRITE)); 734bf215546Sopenharmony_ci unsigned op = translate_usage(usage); 735bf215546Sopenharmony_ci 736bf215546Sopenharmony_ci if (needs_flush || resource_busy(rsc, op)) { 737bf215546Sopenharmony_ci rebind_resource(rsc); 738bf215546Sopenharmony_ci realloc_bo(rsc, fd_bo_size(rsc->bo)); 739bf215546Sopenharmony_ci } else { 740bf215546Sopenharmony_ci util_range_set_empty(&rsc->valid_buffer_range); 741bf215546Sopenharmony_ci } 742bf215546Sopenharmony_ci} 743bf215546Sopenharmony_ci 744bf215546Sopenharmony_cistatic void * 745bf215546Sopenharmony_ciresource_transfer_map_staging(struct pipe_context *pctx, 746bf215546Sopenharmony_ci struct pipe_resource *prsc, 747bf215546Sopenharmony_ci unsigned level, unsigned usage, 748bf215546Sopenharmony_ci const struct pipe_box *box, 749bf215546Sopenharmony_ci struct fd_transfer *trans) 750bf215546Sopenharmony_ci in_dt 751bf215546Sopenharmony_ci{ 752bf215546Sopenharmony_ci struct fd_context *ctx = fd_context(pctx); 753bf215546Sopenharmony_ci struct fd_resource *rsc = fd_resource(prsc); 754bf215546Sopenharmony_ci struct fd_resource *staging_rsc; 755bf215546Sopenharmony_ci 756bf215546Sopenharmony_ci assert(prsc->target != PIPE_BUFFER); 757bf215546Sopenharmony_ci 758bf215546Sopenharmony_ci staging_rsc = fd_alloc_staging(ctx, rsc, level, box); 759bf215546Sopenharmony_ci if (!staging_rsc) 760bf215546Sopenharmony_ci return NULL; 761bf215546Sopenharmony_ci 762bf215546Sopenharmony_ci trans->staging_prsc = &staging_rsc->b.b; 763bf215546Sopenharmony_ci trans->b.b.stride = fd_resource_pitch(staging_rsc, 0); 764bf215546Sopenharmony_ci trans->b.b.layer_stride = fd_resource_layer_stride(staging_rsc, 0); 765bf215546Sopenharmony_ci trans->staging_box = *box; 766bf215546Sopenharmony_ci trans->staging_box.x = 0; 767bf215546Sopenharmony_ci trans->staging_box.y = 0; 768bf215546Sopenharmony_ci trans->staging_box.z = 0; 769bf215546Sopenharmony_ci 770bf215546Sopenharmony_ci if (usage & PIPE_MAP_READ) { 771bf215546Sopenharmony_ci fd_blit_to_staging(ctx, trans); 772bf215546Sopenharmony_ci 773bf215546Sopenharmony_ci fd_resource_wait(ctx, staging_rsc, FD_BO_PREP_READ); 774bf215546Sopenharmony_ci } 775bf215546Sopenharmony_ci 776bf215546Sopenharmony_ci ctx->stats.staging_uploads++; 777bf215546Sopenharmony_ci 778bf215546Sopenharmony_ci return fd_bo_map(staging_rsc->bo); 779bf215546Sopenharmony_ci} 780bf215546Sopenharmony_ci 781bf215546Sopenharmony_cistatic void * 782bf215546Sopenharmony_ciresource_transfer_map_unsync(struct pipe_context *pctx, 783bf215546Sopenharmony_ci struct pipe_resource *prsc, unsigned level, 784bf215546Sopenharmony_ci unsigned usage, const struct pipe_box *box, 785bf215546Sopenharmony_ci struct fd_transfer *trans) 786bf215546Sopenharmony_ci{ 787bf215546Sopenharmony_ci struct fd_resource *rsc = fd_resource(prsc); 788bf215546Sopenharmony_ci enum pipe_format format = prsc->format; 789bf215546Sopenharmony_ci uint32_t offset; 790bf215546Sopenharmony_ci char *buf; 791bf215546Sopenharmony_ci 792bf215546Sopenharmony_ci buf = fd_bo_map(rsc->bo); 793bf215546Sopenharmony_ci 794bf215546Sopenharmony_ci /* With imported bo's allocated by something outside of mesa, when 795bf215546Sopenharmony_ci * running in a VM (using virtio_gpu kernel driver) we could end up in 796bf215546Sopenharmony_ci * a situation where we have a linear bo, but are unable to mmap it 797bf215546Sopenharmony_ci * because it was allocated without the VIRTGPU_BLOB_FLAG_USE_MAPPABLE 798bf215546Sopenharmony_ci * flag. So we need end up needing to do a staging blit instead: 799bf215546Sopenharmony_ci */ 800bf215546Sopenharmony_ci if (!buf) 801bf215546Sopenharmony_ci return resource_transfer_map_staging(pctx, prsc, level, usage, box, trans); 802bf215546Sopenharmony_ci 803bf215546Sopenharmony_ci offset = box->y / util_format_get_blockheight(format) * trans->b.b.stride + 804bf215546Sopenharmony_ci box->x / util_format_get_blockwidth(format) * rsc->layout.cpp + 805bf215546Sopenharmony_ci fd_resource_offset(rsc, level, box->z); 806bf215546Sopenharmony_ci 807bf215546Sopenharmony_ci if (usage & PIPE_MAP_WRITE) 808bf215546Sopenharmony_ci rsc->valid = true; 809bf215546Sopenharmony_ci 810bf215546Sopenharmony_ci return buf + offset; 811bf215546Sopenharmony_ci} 812bf215546Sopenharmony_ci 813bf215546Sopenharmony_ci/** 814bf215546Sopenharmony_ci * Note, with threaded_context, resource_transfer_map() is only called 815bf215546Sopenharmony_ci * in driver thread, but resource_transfer_map_unsync() can be called in 816bf215546Sopenharmony_ci * either driver or frontend thread. 817bf215546Sopenharmony_ci */ 818bf215546Sopenharmony_cistatic void * 819bf215546Sopenharmony_ciresource_transfer_map(struct pipe_context *pctx, struct pipe_resource *prsc, 820bf215546Sopenharmony_ci unsigned level, unsigned usage, 821bf215546Sopenharmony_ci const struct pipe_box *box, 822bf215546Sopenharmony_ci struct fd_transfer *trans) in_dt 823bf215546Sopenharmony_ci{ 824bf215546Sopenharmony_ci struct fd_context *ctx = fd_context(pctx); 825bf215546Sopenharmony_ci struct fd_resource *rsc = fd_resource(prsc); 826bf215546Sopenharmony_ci char *buf; 827bf215546Sopenharmony_ci int ret = 0; 828bf215546Sopenharmony_ci 829bf215546Sopenharmony_ci tc_assert_driver_thread(ctx->tc); 830bf215546Sopenharmony_ci 831bf215546Sopenharmony_ci /* Strip the read flag if the buffer has been invalidated (or is freshly 832bf215546Sopenharmony_ci * created). Avoids extra staging blits of undefined data on glTexSubImage of 833bf215546Sopenharmony_ci * a fresh DEPTH_COMPONENT or STENCIL_INDEX texture being stored as z24s8. 834bf215546Sopenharmony_ci */ 835bf215546Sopenharmony_ci if (!rsc->valid) 836bf215546Sopenharmony_ci usage &= ~PIPE_MAP_READ; 837bf215546Sopenharmony_ci 838bf215546Sopenharmony_ci /* we always need a staging texture for tiled buffers: 839bf215546Sopenharmony_ci * 840bf215546Sopenharmony_ci * TODO we might sometimes want to *also* shadow the resource to avoid 841bf215546Sopenharmony_ci * splitting a batch.. for ex, mid-frame texture uploads to a tiled 842bf215546Sopenharmony_ci * texture. 843bf215546Sopenharmony_ci */ 844bf215546Sopenharmony_ci if (rsc->layout.tile_mode) { 845bf215546Sopenharmony_ci return resource_transfer_map_staging(pctx, prsc, level, usage, box, trans); 846bf215546Sopenharmony_ci } else if ((usage & PIPE_MAP_READ) && !fd_bo_is_cached(rsc->bo)) { 847bf215546Sopenharmony_ci perf_debug_ctx(ctx, "wc readback: prsc=%p, level=%u, usage=%x, box=%dx%d+%d,%d", 848bf215546Sopenharmony_ci prsc, level, usage, box->width, box->height, box->x, box->y); 849bf215546Sopenharmony_ci } 850bf215546Sopenharmony_ci 851bf215546Sopenharmony_ci if (usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE) { 852bf215546Sopenharmony_ci invalidate_resource(rsc, usage); 853bf215546Sopenharmony_ci } else { 854bf215546Sopenharmony_ci unsigned op = translate_usage(usage); 855bf215546Sopenharmony_ci bool needs_flush = pending(rsc, !!(usage & PIPE_MAP_WRITE)); 856bf215546Sopenharmony_ci 857bf215546Sopenharmony_ci /* If the GPU is writing to the resource, or if it is reading from the 858bf215546Sopenharmony_ci * resource and we're trying to write to it, flush the renders. 859bf215546Sopenharmony_ci */ 860bf215546Sopenharmony_ci bool busy = needs_flush || resource_busy(rsc, op); 861bf215546Sopenharmony_ci 862bf215546Sopenharmony_ci /* if we need to flush/stall, see if we can make a shadow buffer 863bf215546Sopenharmony_ci * to avoid this: 864bf215546Sopenharmony_ci * 865bf215546Sopenharmony_ci * TODO we could go down this path !reorder && !busy_for_read 866bf215546Sopenharmony_ci * ie. we only *don't* want to go down this path if the blit 867bf215546Sopenharmony_ci * will trigger a flush! 868bf215546Sopenharmony_ci */ 869bf215546Sopenharmony_ci if (ctx->screen->reorder && busy && !(usage & PIPE_MAP_READ) && 870bf215546Sopenharmony_ci (usage & PIPE_MAP_DISCARD_RANGE)) { 871bf215546Sopenharmony_ci 872bf215546Sopenharmony_ci /* try shadowing only if it avoids a flush, otherwise staging would 873bf215546Sopenharmony_ci * be better: 874bf215546Sopenharmony_ci */ 875bf215546Sopenharmony_ci if (needs_flush && fd_try_shadow_resource(ctx, rsc, level, box, 876bf215546Sopenharmony_ci DRM_FORMAT_MOD_LINEAR)) { 877bf215546Sopenharmony_ci needs_flush = busy = false; 878bf215546Sopenharmony_ci ctx->stats.shadow_uploads++; 879bf215546Sopenharmony_ci } else { 880bf215546Sopenharmony_ci struct fd_resource *staging_rsc = NULL; 881bf215546Sopenharmony_ci 882bf215546Sopenharmony_ci if (needs_flush) { 883bf215546Sopenharmony_ci flush_resource(ctx, rsc, usage); 884bf215546Sopenharmony_ci needs_flush = false; 885bf215546Sopenharmony_ci } 886bf215546Sopenharmony_ci 887bf215546Sopenharmony_ci /* in this case, we don't need to shadow the whole resource, 888bf215546Sopenharmony_ci * since any draw that references the previous contents has 889bf215546Sopenharmony_ci * already had rendering flushed for all tiles. So we can 890bf215546Sopenharmony_ci * use a staging buffer to do the upload. 891bf215546Sopenharmony_ci */ 892bf215546Sopenharmony_ci if (is_renderable(prsc)) 893bf215546Sopenharmony_ci staging_rsc = fd_alloc_staging(ctx, rsc, level, box); 894bf215546Sopenharmony_ci if (staging_rsc) { 895bf215546Sopenharmony_ci trans->staging_prsc = &staging_rsc->b.b; 896bf215546Sopenharmony_ci trans->b.b.stride = fd_resource_pitch(staging_rsc, 0); 897bf215546Sopenharmony_ci trans->b.b.layer_stride = 898bf215546Sopenharmony_ci fd_resource_layer_stride(staging_rsc, 0); 899bf215546Sopenharmony_ci trans->staging_box = *box; 900bf215546Sopenharmony_ci trans->staging_box.x = 0; 901bf215546Sopenharmony_ci trans->staging_box.y = 0; 902bf215546Sopenharmony_ci trans->staging_box.z = 0; 903bf215546Sopenharmony_ci buf = fd_bo_map(staging_rsc->bo); 904bf215546Sopenharmony_ci 905bf215546Sopenharmony_ci ctx->stats.staging_uploads++; 906bf215546Sopenharmony_ci 907bf215546Sopenharmony_ci return buf; 908bf215546Sopenharmony_ci } 909bf215546Sopenharmony_ci } 910bf215546Sopenharmony_ci } 911bf215546Sopenharmony_ci 912bf215546Sopenharmony_ci if (needs_flush) { 913bf215546Sopenharmony_ci flush_resource(ctx, rsc, usage); 914bf215546Sopenharmony_ci needs_flush = false; 915bf215546Sopenharmony_ci } 916bf215546Sopenharmony_ci 917bf215546Sopenharmony_ci /* The GPU keeps track of how the various bo's are being used, and 918bf215546Sopenharmony_ci * will wait if necessary for the proper operation to have 919bf215546Sopenharmony_ci * completed. 920bf215546Sopenharmony_ci */ 921bf215546Sopenharmony_ci if (busy) { 922bf215546Sopenharmony_ci ret = fd_resource_wait(ctx, rsc, op); 923bf215546Sopenharmony_ci if (ret) 924bf215546Sopenharmony_ci return NULL; 925bf215546Sopenharmony_ci } 926bf215546Sopenharmony_ci } 927bf215546Sopenharmony_ci 928bf215546Sopenharmony_ci return resource_transfer_map_unsync(pctx, prsc, level, usage, box, trans); 929bf215546Sopenharmony_ci} 930bf215546Sopenharmony_ci 931bf215546Sopenharmony_cistatic unsigned 932bf215546Sopenharmony_ciimprove_transfer_map_usage(struct fd_context *ctx, struct fd_resource *rsc, 933bf215546Sopenharmony_ci unsigned usage, const struct pipe_box *box) 934bf215546Sopenharmony_ci /* Not *strictly* true, but the access to things that must only be in driver- 935bf215546Sopenharmony_ci * thread are protected by !(usage & TC_TRANSFER_MAP_THREADED_UNSYNC): 936bf215546Sopenharmony_ci */ 937bf215546Sopenharmony_ci in_dt 938bf215546Sopenharmony_ci{ 939bf215546Sopenharmony_ci if (usage & TC_TRANSFER_MAP_NO_INVALIDATE) { 940bf215546Sopenharmony_ci usage &= ~PIPE_MAP_DISCARD_WHOLE_RESOURCE; 941bf215546Sopenharmony_ci } 942bf215546Sopenharmony_ci 943bf215546Sopenharmony_ci if (usage & TC_TRANSFER_MAP_THREADED_UNSYNC) 944bf215546Sopenharmony_ci usage |= PIPE_MAP_UNSYNCHRONIZED; 945bf215546Sopenharmony_ci 946bf215546Sopenharmony_ci if (!(usage & 947bf215546Sopenharmony_ci (TC_TRANSFER_MAP_NO_INFER_UNSYNCHRONIZED | PIPE_MAP_UNSYNCHRONIZED))) { 948bf215546Sopenharmony_ci if (ctx->in_shadow && !(usage & PIPE_MAP_READ)) { 949bf215546Sopenharmony_ci usage |= PIPE_MAP_UNSYNCHRONIZED; 950bf215546Sopenharmony_ci } else if ((usage & PIPE_MAP_WRITE) && (rsc->b.b.target == PIPE_BUFFER) && 951bf215546Sopenharmony_ci !util_ranges_intersect(&rsc->valid_buffer_range, box->x, 952bf215546Sopenharmony_ci box->x + box->width)) { 953bf215546Sopenharmony_ci /* We are trying to write to a previously uninitialized range. No need 954bf215546Sopenharmony_ci * to synchronize. 955bf215546Sopenharmony_ci */ 956bf215546Sopenharmony_ci usage |= PIPE_MAP_UNSYNCHRONIZED; 957bf215546Sopenharmony_ci } 958bf215546Sopenharmony_ci } 959bf215546Sopenharmony_ci 960bf215546Sopenharmony_ci return usage; 961bf215546Sopenharmony_ci} 962bf215546Sopenharmony_ci 963bf215546Sopenharmony_cistatic void * 964bf215546Sopenharmony_cifd_resource_transfer_map(struct pipe_context *pctx, struct pipe_resource *prsc, 965bf215546Sopenharmony_ci unsigned level, unsigned usage, 966bf215546Sopenharmony_ci const struct pipe_box *box, 967bf215546Sopenharmony_ci struct pipe_transfer **pptrans) 968bf215546Sopenharmony_ci{ 969bf215546Sopenharmony_ci struct fd_context *ctx = fd_context(pctx); 970bf215546Sopenharmony_ci struct fd_resource *rsc = fd_resource(prsc); 971bf215546Sopenharmony_ci struct fd_transfer *trans; 972bf215546Sopenharmony_ci struct pipe_transfer *ptrans; 973bf215546Sopenharmony_ci 974bf215546Sopenharmony_ci DBG("prsc=%p, level=%u, usage=%x, box=%dx%d+%d,%d", prsc, level, usage, 975bf215546Sopenharmony_ci box->width, box->height, box->x, box->y); 976bf215546Sopenharmony_ci 977bf215546Sopenharmony_ci if ((usage & PIPE_MAP_DIRECTLY) && rsc->layout.tile_mode) { 978bf215546Sopenharmony_ci DBG("CANNOT MAP DIRECTLY!\n"); 979bf215546Sopenharmony_ci return NULL; 980bf215546Sopenharmony_ci } 981bf215546Sopenharmony_ci 982bf215546Sopenharmony_ci if (usage & TC_TRANSFER_MAP_THREADED_UNSYNC) { 983bf215546Sopenharmony_ci ptrans = slab_zalloc(&ctx->transfer_pool_unsync); 984bf215546Sopenharmony_ci } else { 985bf215546Sopenharmony_ci ptrans = slab_zalloc(&ctx->transfer_pool); 986bf215546Sopenharmony_ci } 987bf215546Sopenharmony_ci 988bf215546Sopenharmony_ci if (!ptrans) 989bf215546Sopenharmony_ci return NULL; 990bf215546Sopenharmony_ci 991bf215546Sopenharmony_ci trans = fd_transfer(ptrans); 992bf215546Sopenharmony_ci 993bf215546Sopenharmony_ci usage = improve_transfer_map_usage(ctx, rsc, usage, box); 994bf215546Sopenharmony_ci 995bf215546Sopenharmony_ci pipe_resource_reference(&ptrans->resource, prsc); 996bf215546Sopenharmony_ci ptrans->level = level; 997bf215546Sopenharmony_ci ptrans->usage = usage; 998bf215546Sopenharmony_ci ptrans->box = *box; 999bf215546Sopenharmony_ci ptrans->stride = fd_resource_pitch(rsc, level); 1000bf215546Sopenharmony_ci ptrans->layer_stride = fd_resource_layer_stride(rsc, level); 1001bf215546Sopenharmony_ci 1002bf215546Sopenharmony_ci void *ret; 1003bf215546Sopenharmony_ci if (usage & PIPE_MAP_UNSYNCHRONIZED) { 1004bf215546Sopenharmony_ci ret = resource_transfer_map_unsync(pctx, prsc, level, usage, box, trans); 1005bf215546Sopenharmony_ci } else { 1006bf215546Sopenharmony_ci ret = resource_transfer_map(pctx, prsc, level, usage, box, trans); 1007bf215546Sopenharmony_ci } 1008bf215546Sopenharmony_ci 1009bf215546Sopenharmony_ci if (ret) { 1010bf215546Sopenharmony_ci *pptrans = ptrans; 1011bf215546Sopenharmony_ci } else { 1012bf215546Sopenharmony_ci fd_resource_transfer_unmap(pctx, ptrans); 1013bf215546Sopenharmony_ci } 1014bf215546Sopenharmony_ci 1015bf215546Sopenharmony_ci return ret; 1016bf215546Sopenharmony_ci} 1017bf215546Sopenharmony_ci 1018bf215546Sopenharmony_cistatic void 1019bf215546Sopenharmony_cifd_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc) 1020bf215546Sopenharmony_ci{ 1021bf215546Sopenharmony_ci struct fd_screen *screen = fd_screen(prsc->screen); 1022bf215546Sopenharmony_ci struct fd_resource *rsc = fd_resource(prsc); 1023bf215546Sopenharmony_ci 1024bf215546Sopenharmony_ci if (!rsc->is_replacement) 1025bf215546Sopenharmony_ci fd_bc_invalidate_resource(rsc, true); 1026bf215546Sopenharmony_ci if (rsc->bo) 1027bf215546Sopenharmony_ci fd_bo_del(rsc->bo); 1028bf215546Sopenharmony_ci if (rsc->lrz) 1029bf215546Sopenharmony_ci fd_bo_del(rsc->lrz); 1030bf215546Sopenharmony_ci if (rsc->scanout) 1031bf215546Sopenharmony_ci renderonly_scanout_destroy(rsc->scanout, fd_screen(pscreen)->ro); 1032bf215546Sopenharmony_ci 1033bf215546Sopenharmony_ci if (prsc->target == PIPE_BUFFER) 1034bf215546Sopenharmony_ci util_idalloc_mt_free(&screen->buffer_ids, rsc->b.buffer_id_unique); 1035bf215546Sopenharmony_ci 1036bf215546Sopenharmony_ci threaded_resource_deinit(prsc); 1037bf215546Sopenharmony_ci 1038bf215546Sopenharmony_ci util_range_destroy(&rsc->valid_buffer_range); 1039bf215546Sopenharmony_ci simple_mtx_destroy(&rsc->lock); 1040bf215546Sopenharmony_ci fd_resource_tracking_reference(&rsc->track, NULL); 1041bf215546Sopenharmony_ci 1042bf215546Sopenharmony_ci FREE(rsc); 1043bf215546Sopenharmony_ci} 1044bf215546Sopenharmony_ci 1045bf215546Sopenharmony_cistatic uint64_t 1046bf215546Sopenharmony_cifd_resource_modifier(struct fd_resource *rsc) 1047bf215546Sopenharmony_ci{ 1048bf215546Sopenharmony_ci if (!rsc->layout.tile_mode) 1049bf215546Sopenharmony_ci return DRM_FORMAT_MOD_LINEAR; 1050bf215546Sopenharmony_ci 1051bf215546Sopenharmony_ci if (rsc->layout.ubwc_layer_size) 1052bf215546Sopenharmony_ci return DRM_FORMAT_MOD_QCOM_COMPRESSED; 1053bf215546Sopenharmony_ci 1054bf215546Sopenharmony_ci /* TODO invent a modifier for tiled but not UBWC buffers: */ 1055bf215546Sopenharmony_ci return DRM_FORMAT_MOD_INVALID; 1056bf215546Sopenharmony_ci} 1057bf215546Sopenharmony_ci 1058bf215546Sopenharmony_cistatic bool 1059bf215546Sopenharmony_cifd_resource_get_handle(struct pipe_screen *pscreen, struct pipe_context *pctx, 1060bf215546Sopenharmony_ci struct pipe_resource *prsc, struct winsys_handle *handle, 1061bf215546Sopenharmony_ci unsigned usage) 1062bf215546Sopenharmony_ci{ 1063bf215546Sopenharmony_ci struct fd_resource *rsc = fd_resource(prsc); 1064bf215546Sopenharmony_ci 1065bf215546Sopenharmony_ci rsc->b.is_shared = true; 1066bf215546Sopenharmony_ci 1067bf215546Sopenharmony_ci handle->modifier = fd_resource_modifier(rsc); 1068bf215546Sopenharmony_ci 1069bf215546Sopenharmony_ci DBG("%" PRSC_FMT ", modifier=%" PRIx64, PRSC_ARGS(prsc), handle->modifier); 1070bf215546Sopenharmony_ci 1071bf215546Sopenharmony_ci return fd_screen_bo_get_handle(pscreen, rsc->bo, rsc->scanout, 1072bf215546Sopenharmony_ci fd_resource_pitch(rsc, 0), handle); 1073bf215546Sopenharmony_ci} 1074bf215546Sopenharmony_ci 1075bf215546Sopenharmony_ci/* special case to resize query buf after allocated.. */ 1076bf215546Sopenharmony_civoid 1077bf215546Sopenharmony_cifd_resource_resize(struct pipe_resource *prsc, uint32_t sz) 1078bf215546Sopenharmony_ci{ 1079bf215546Sopenharmony_ci struct fd_resource *rsc = fd_resource(prsc); 1080bf215546Sopenharmony_ci 1081bf215546Sopenharmony_ci assert(prsc->width0 == 0); 1082bf215546Sopenharmony_ci assert(prsc->target == PIPE_BUFFER); 1083bf215546Sopenharmony_ci assert(prsc->bind == PIPE_BIND_QUERY_BUFFER); 1084bf215546Sopenharmony_ci 1085bf215546Sopenharmony_ci prsc->width0 = sz; 1086bf215546Sopenharmony_ci realloc_bo(rsc, fd_screen(prsc->screen)->setup_slices(rsc)); 1087bf215546Sopenharmony_ci} 1088bf215546Sopenharmony_ci 1089bf215546Sopenharmony_cistatic void 1090bf215546Sopenharmony_cifd_resource_layout_init(struct pipe_resource *prsc) 1091bf215546Sopenharmony_ci{ 1092bf215546Sopenharmony_ci struct fd_resource *rsc = fd_resource(prsc); 1093bf215546Sopenharmony_ci struct fdl_layout *layout = &rsc->layout; 1094bf215546Sopenharmony_ci 1095bf215546Sopenharmony_ci layout->format = prsc->format; 1096bf215546Sopenharmony_ci 1097bf215546Sopenharmony_ci layout->width0 = prsc->width0; 1098bf215546Sopenharmony_ci layout->height0 = prsc->height0; 1099bf215546Sopenharmony_ci layout->depth0 = prsc->depth0; 1100bf215546Sopenharmony_ci 1101bf215546Sopenharmony_ci layout->cpp = util_format_get_blocksize(prsc->format); 1102bf215546Sopenharmony_ci layout->cpp *= fd_resource_nr_samples(prsc); 1103bf215546Sopenharmony_ci layout->cpp_shift = ffs(layout->cpp) - 1; 1104bf215546Sopenharmony_ci} 1105bf215546Sopenharmony_ci 1106bf215546Sopenharmony_cistatic struct fd_resource * 1107bf215546Sopenharmony_cialloc_resource_struct(struct pipe_screen *pscreen, 1108bf215546Sopenharmony_ci const struct pipe_resource *tmpl) 1109bf215546Sopenharmony_ci{ 1110bf215546Sopenharmony_ci struct fd_screen *screen = fd_screen(pscreen); 1111bf215546Sopenharmony_ci struct fd_resource *rsc = CALLOC_STRUCT(fd_resource); 1112bf215546Sopenharmony_ci 1113bf215546Sopenharmony_ci if (!rsc) 1114bf215546Sopenharmony_ci return NULL; 1115bf215546Sopenharmony_ci 1116bf215546Sopenharmony_ci struct pipe_resource *prsc = &rsc->b.b; 1117bf215546Sopenharmony_ci *prsc = *tmpl; 1118bf215546Sopenharmony_ci 1119bf215546Sopenharmony_ci pipe_reference_init(&prsc->reference, 1); 1120bf215546Sopenharmony_ci prsc->screen = pscreen; 1121bf215546Sopenharmony_ci rsc->hash = _mesa_hash_pointer(rsc); 1122bf215546Sopenharmony_ci 1123bf215546Sopenharmony_ci util_range_init(&rsc->valid_buffer_range); 1124bf215546Sopenharmony_ci simple_mtx_init(&rsc->lock, mtx_plain); 1125bf215546Sopenharmony_ci 1126bf215546Sopenharmony_ci rsc->track = CALLOC_STRUCT(fd_resource_tracking); 1127bf215546Sopenharmony_ci if (!rsc->track) { 1128bf215546Sopenharmony_ci free(rsc); 1129bf215546Sopenharmony_ci return NULL; 1130bf215546Sopenharmony_ci } 1131bf215546Sopenharmony_ci 1132bf215546Sopenharmony_ci pipe_reference_init(&rsc->track->reference, 1); 1133bf215546Sopenharmony_ci 1134bf215546Sopenharmony_ci threaded_resource_init(prsc, false); 1135bf215546Sopenharmony_ci 1136bf215546Sopenharmony_ci if (tmpl->target == PIPE_BUFFER) 1137bf215546Sopenharmony_ci rsc->b.buffer_id_unique = util_idalloc_mt_alloc(&screen->buffer_ids); 1138bf215546Sopenharmony_ci 1139bf215546Sopenharmony_ci return rsc; 1140bf215546Sopenharmony_ci} 1141bf215546Sopenharmony_ci 1142bf215546Sopenharmony_cienum fd_layout_type { 1143bf215546Sopenharmony_ci ERROR, 1144bf215546Sopenharmony_ci LINEAR, 1145bf215546Sopenharmony_ci TILED, 1146bf215546Sopenharmony_ci UBWC, 1147bf215546Sopenharmony_ci}; 1148bf215546Sopenharmony_ci 1149bf215546Sopenharmony_cistatic enum fd_layout_type 1150bf215546Sopenharmony_ciget_best_layout(struct fd_screen *screen, struct pipe_resource *prsc, 1151bf215546Sopenharmony_ci const struct pipe_resource *tmpl, const uint64_t *modifiers, 1152bf215546Sopenharmony_ci int count) 1153bf215546Sopenharmony_ci{ 1154bf215546Sopenharmony_ci bool implicit_modifiers = 1155bf215546Sopenharmony_ci (count == 0 || 1156bf215546Sopenharmony_ci drm_find_modifier(DRM_FORMAT_MOD_INVALID, modifiers, count)); 1157bf215546Sopenharmony_ci 1158bf215546Sopenharmony_ci /* First, find all the conditions which would force us to linear */ 1159bf215546Sopenharmony_ci if (!screen->tile_mode) 1160bf215546Sopenharmony_ci return LINEAR; 1161bf215546Sopenharmony_ci 1162bf215546Sopenharmony_ci if (!screen->tile_mode(prsc)) 1163bf215546Sopenharmony_ci return LINEAR; 1164bf215546Sopenharmony_ci 1165bf215546Sopenharmony_ci if (tmpl->target == PIPE_BUFFER) 1166bf215546Sopenharmony_ci return LINEAR; 1167bf215546Sopenharmony_ci 1168bf215546Sopenharmony_ci if (tmpl->bind & PIPE_BIND_LINEAR) { 1169bf215546Sopenharmony_ci if (tmpl->usage != PIPE_USAGE_STAGING) 1170bf215546Sopenharmony_ci perf_debug("%" PRSC_FMT ": forcing linear: bind flags", 1171bf215546Sopenharmony_ci PRSC_ARGS(prsc)); 1172bf215546Sopenharmony_ci return LINEAR; 1173bf215546Sopenharmony_ci } 1174bf215546Sopenharmony_ci 1175bf215546Sopenharmony_ci if (FD_DBG(NOTILE)) 1176bf215546Sopenharmony_ci return LINEAR; 1177bf215546Sopenharmony_ci 1178bf215546Sopenharmony_ci /* Shared resources with implicit modifiers must always be linear */ 1179bf215546Sopenharmony_ci if (implicit_modifiers && (tmpl->bind & PIPE_BIND_SHARED)) { 1180bf215546Sopenharmony_ci perf_debug("%" PRSC_FMT 1181bf215546Sopenharmony_ci ": forcing linear: shared resource + implicit modifiers", 1182bf215546Sopenharmony_ci PRSC_ARGS(prsc)); 1183bf215546Sopenharmony_ci return LINEAR; 1184bf215546Sopenharmony_ci } 1185bf215546Sopenharmony_ci 1186bf215546Sopenharmony_ci bool ubwc_ok = is_a6xx(screen); 1187bf215546Sopenharmony_ci if (FD_DBG(NOUBWC)) 1188bf215546Sopenharmony_ci ubwc_ok = false; 1189bf215546Sopenharmony_ci 1190bf215546Sopenharmony_ci if (ubwc_ok && !implicit_modifiers && 1191bf215546Sopenharmony_ci !drm_find_modifier(DRM_FORMAT_MOD_QCOM_COMPRESSED, modifiers, count)) { 1192bf215546Sopenharmony_ci perf_debug("%" PRSC_FMT 1193bf215546Sopenharmony_ci ": not using UBWC: not in acceptable modifier set", 1194bf215546Sopenharmony_ci PRSC_ARGS(prsc)); 1195bf215546Sopenharmony_ci ubwc_ok = false; 1196bf215546Sopenharmony_ci } 1197bf215546Sopenharmony_ci 1198bf215546Sopenharmony_ci if (ubwc_ok) 1199bf215546Sopenharmony_ci return UBWC; 1200bf215546Sopenharmony_ci 1201bf215546Sopenharmony_ci /* We can't use tiled with explicit modifiers, as there is no modifier token 1202bf215546Sopenharmony_ci * defined for it. But we might internally force tiled allocation using a 1203bf215546Sopenharmony_ci * private modifier token. 1204bf215546Sopenharmony_ci * 1205bf215546Sopenharmony_ci * TODO we should probably also limit TILED in a similar way to UBWC above, 1206bf215546Sopenharmony_ci * once we have a public modifier token defined. 1207bf215546Sopenharmony_ci */ 1208bf215546Sopenharmony_ci if (implicit_modifiers || 1209bf215546Sopenharmony_ci drm_find_modifier(FD_FORMAT_MOD_QCOM_TILED, modifiers, count)) 1210bf215546Sopenharmony_ci return TILED; 1211bf215546Sopenharmony_ci 1212bf215546Sopenharmony_ci if (!drm_find_modifier(DRM_FORMAT_MOD_LINEAR, modifiers, count)) { 1213bf215546Sopenharmony_ci perf_debug("%" PRSC_FMT ": need linear but not in modifier set", 1214bf215546Sopenharmony_ci PRSC_ARGS(prsc)); 1215bf215546Sopenharmony_ci return ERROR; 1216bf215546Sopenharmony_ci } 1217bf215546Sopenharmony_ci 1218bf215546Sopenharmony_ci perf_debug("%" PRSC_FMT ": not using tiling: explicit modifiers and no UBWC", 1219bf215546Sopenharmony_ci PRSC_ARGS(prsc)); 1220bf215546Sopenharmony_ci return LINEAR; 1221bf215546Sopenharmony_ci} 1222bf215546Sopenharmony_ci 1223bf215546Sopenharmony_ci/** 1224bf215546Sopenharmony_ci * Helper that allocates a resource and resolves its layout (but doesn't 1225bf215546Sopenharmony_ci * allocate its bo). 1226bf215546Sopenharmony_ci * 1227bf215546Sopenharmony_ci * It returns a pipe_resource (as fd_resource_create_with_modifiers() 1228bf215546Sopenharmony_ci * would do), and also bo's minimum required size as an output argument. 1229bf215546Sopenharmony_ci */ 1230bf215546Sopenharmony_cistatic struct pipe_resource * 1231bf215546Sopenharmony_cifd_resource_allocate_and_resolve(struct pipe_screen *pscreen, 1232bf215546Sopenharmony_ci const struct pipe_resource *tmpl, 1233bf215546Sopenharmony_ci const uint64_t *modifiers, int count, 1234bf215546Sopenharmony_ci uint32_t *psize) 1235bf215546Sopenharmony_ci{ 1236bf215546Sopenharmony_ci struct fd_screen *screen = fd_screen(pscreen); 1237bf215546Sopenharmony_ci struct fd_resource *rsc; 1238bf215546Sopenharmony_ci struct pipe_resource *prsc; 1239bf215546Sopenharmony_ci enum pipe_format format = tmpl->format; 1240bf215546Sopenharmony_ci uint32_t size; 1241bf215546Sopenharmony_ci 1242bf215546Sopenharmony_ci rsc = alloc_resource_struct(pscreen, tmpl); 1243bf215546Sopenharmony_ci if (!rsc) 1244bf215546Sopenharmony_ci return NULL; 1245bf215546Sopenharmony_ci 1246bf215546Sopenharmony_ci prsc = &rsc->b.b; 1247bf215546Sopenharmony_ci 1248bf215546Sopenharmony_ci /* Clover creates buffers with PIPE_FORMAT_NONE: */ 1249bf215546Sopenharmony_ci if ((prsc->target == PIPE_BUFFER) && (format == PIPE_FORMAT_NONE)) 1250bf215546Sopenharmony_ci format = prsc->format = PIPE_FORMAT_R8_UNORM; 1251bf215546Sopenharmony_ci 1252bf215546Sopenharmony_ci DBG("%" PRSC_FMT, PRSC_ARGS(prsc)); 1253bf215546Sopenharmony_ci 1254bf215546Sopenharmony_ci if (tmpl->bind & PIPE_BIND_SHARED) 1255bf215546Sopenharmony_ci rsc->b.is_shared = true; 1256bf215546Sopenharmony_ci 1257bf215546Sopenharmony_ci fd_resource_layout_init(prsc); 1258bf215546Sopenharmony_ci 1259bf215546Sopenharmony_ci enum fd_layout_type layout = 1260bf215546Sopenharmony_ci get_best_layout(screen, prsc, tmpl, modifiers, count); 1261bf215546Sopenharmony_ci if (layout == ERROR) { 1262bf215546Sopenharmony_ci free(prsc); 1263bf215546Sopenharmony_ci return NULL; 1264bf215546Sopenharmony_ci } 1265bf215546Sopenharmony_ci 1266bf215546Sopenharmony_ci if (layout >= TILED) 1267bf215546Sopenharmony_ci rsc->layout.tile_mode = screen->tile_mode(prsc); 1268bf215546Sopenharmony_ci if (layout == UBWC) 1269bf215546Sopenharmony_ci rsc->layout.ubwc = true; 1270bf215546Sopenharmony_ci 1271bf215546Sopenharmony_ci rsc->internal_format = format; 1272bf215546Sopenharmony_ci 1273bf215546Sopenharmony_ci if (prsc->target == PIPE_BUFFER) { 1274bf215546Sopenharmony_ci assert(prsc->format == PIPE_FORMAT_R8_UNORM); 1275bf215546Sopenharmony_ci size = prsc->width0; 1276bf215546Sopenharmony_ci fdl_layout_buffer(&rsc->layout, size); 1277bf215546Sopenharmony_ci } else { 1278bf215546Sopenharmony_ci size = screen->setup_slices(rsc); 1279bf215546Sopenharmony_ci } 1280bf215546Sopenharmony_ci 1281bf215546Sopenharmony_ci /* special case for hw-query buffer, which we need to allocate before we 1282bf215546Sopenharmony_ci * know the size: 1283bf215546Sopenharmony_ci */ 1284bf215546Sopenharmony_ci if (size == 0) { 1285bf215546Sopenharmony_ci /* note, semi-intention == instead of & */ 1286bf215546Sopenharmony_ci assert(prsc->bind == PIPE_BIND_QUERY_BUFFER); 1287bf215546Sopenharmony_ci *psize = 0; 1288bf215546Sopenharmony_ci return prsc; 1289bf215546Sopenharmony_ci } 1290bf215546Sopenharmony_ci 1291bf215546Sopenharmony_ci /* Set the layer size if the (non-a6xx) backend hasn't done so. */ 1292bf215546Sopenharmony_ci if (rsc->layout.layer_first && !rsc->layout.layer_size) { 1293bf215546Sopenharmony_ci rsc->layout.layer_size = align(size, 4096); 1294bf215546Sopenharmony_ci size = rsc->layout.layer_size * prsc->array_size; 1295bf215546Sopenharmony_ci } 1296bf215546Sopenharmony_ci 1297bf215546Sopenharmony_ci if (FD_DBG(LAYOUT)) 1298bf215546Sopenharmony_ci fdl_dump_layout(&rsc->layout); 1299bf215546Sopenharmony_ci 1300bf215546Sopenharmony_ci /* Hand out the resolved size. */ 1301bf215546Sopenharmony_ci if (psize) 1302bf215546Sopenharmony_ci *psize = size; 1303bf215546Sopenharmony_ci 1304bf215546Sopenharmony_ci return prsc; 1305bf215546Sopenharmony_ci} 1306bf215546Sopenharmony_ci 1307bf215546Sopenharmony_ci/** 1308bf215546Sopenharmony_ci * Create a new texture object, using the given template info. 1309bf215546Sopenharmony_ci */ 1310bf215546Sopenharmony_cistatic struct pipe_resource * 1311bf215546Sopenharmony_cifd_resource_create_with_modifiers(struct pipe_screen *pscreen, 1312bf215546Sopenharmony_ci const struct pipe_resource *tmpl, 1313bf215546Sopenharmony_ci const uint64_t *modifiers, int count) 1314bf215546Sopenharmony_ci{ 1315bf215546Sopenharmony_ci struct fd_screen *screen = fd_screen(pscreen); 1316bf215546Sopenharmony_ci struct fd_resource *rsc; 1317bf215546Sopenharmony_ci struct pipe_resource *prsc; 1318bf215546Sopenharmony_ci uint32_t size; 1319bf215546Sopenharmony_ci 1320bf215546Sopenharmony_ci /* when using kmsro, scanout buffers are allocated on the display device 1321bf215546Sopenharmony_ci * create_with_modifiers() doesn't give us usage flags, so we have to 1322bf215546Sopenharmony_ci * assume that all calls with modifiers are scanout-possible 1323bf215546Sopenharmony_ci */ 1324bf215546Sopenharmony_ci if (screen->ro && 1325bf215546Sopenharmony_ci ((tmpl->bind & PIPE_BIND_SCANOUT) || 1326bf215546Sopenharmony_ci !(count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID))) { 1327bf215546Sopenharmony_ci struct pipe_resource scanout_templat = *tmpl; 1328bf215546Sopenharmony_ci struct renderonly_scanout *scanout; 1329bf215546Sopenharmony_ci struct winsys_handle handle; 1330bf215546Sopenharmony_ci 1331bf215546Sopenharmony_ci /* note: alignment is wrong for a6xx */ 1332bf215546Sopenharmony_ci scanout_templat.width0 = align(tmpl->width0, screen->info->gmem_align_w); 1333bf215546Sopenharmony_ci 1334bf215546Sopenharmony_ci scanout = 1335bf215546Sopenharmony_ci renderonly_scanout_for_resource(&scanout_templat, screen->ro, &handle); 1336bf215546Sopenharmony_ci if (!scanout) 1337bf215546Sopenharmony_ci return NULL; 1338bf215546Sopenharmony_ci 1339bf215546Sopenharmony_ci renderonly_scanout_destroy(scanout, screen->ro); 1340bf215546Sopenharmony_ci 1341bf215546Sopenharmony_ci assert(handle.type == WINSYS_HANDLE_TYPE_FD); 1342bf215546Sopenharmony_ci rsc = fd_resource(pscreen->resource_from_handle( 1343bf215546Sopenharmony_ci pscreen, tmpl, &handle, PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE)); 1344bf215546Sopenharmony_ci close(handle.handle); 1345bf215546Sopenharmony_ci if (!rsc) 1346bf215546Sopenharmony_ci return NULL; 1347bf215546Sopenharmony_ci 1348bf215546Sopenharmony_ci return &rsc->b.b; 1349bf215546Sopenharmony_ci } 1350bf215546Sopenharmony_ci 1351bf215546Sopenharmony_ci prsc = 1352bf215546Sopenharmony_ci fd_resource_allocate_and_resolve(pscreen, tmpl, modifiers, count, &size); 1353bf215546Sopenharmony_ci if (!prsc) 1354bf215546Sopenharmony_ci return NULL; 1355bf215546Sopenharmony_ci rsc = fd_resource(prsc); 1356bf215546Sopenharmony_ci 1357bf215546Sopenharmony_ci realloc_bo(rsc, size); 1358bf215546Sopenharmony_ci if (!rsc->bo) 1359bf215546Sopenharmony_ci goto fail; 1360bf215546Sopenharmony_ci 1361bf215546Sopenharmony_ci return prsc; 1362bf215546Sopenharmony_cifail: 1363bf215546Sopenharmony_ci fd_resource_destroy(pscreen, prsc); 1364bf215546Sopenharmony_ci return NULL; 1365bf215546Sopenharmony_ci} 1366bf215546Sopenharmony_ci 1367bf215546Sopenharmony_cistatic struct pipe_resource * 1368bf215546Sopenharmony_cifd_resource_create(struct pipe_screen *pscreen, 1369bf215546Sopenharmony_ci const struct pipe_resource *tmpl) 1370bf215546Sopenharmony_ci{ 1371bf215546Sopenharmony_ci const uint64_t mod = DRM_FORMAT_MOD_INVALID; 1372bf215546Sopenharmony_ci return fd_resource_create_with_modifiers(pscreen, tmpl, &mod, 1); 1373bf215546Sopenharmony_ci} 1374bf215546Sopenharmony_ci 1375bf215546Sopenharmony_ci/** 1376bf215546Sopenharmony_ci * Create a texture from a winsys_handle. The handle is often created in 1377bf215546Sopenharmony_ci * another process by first creating a pipe texture and then calling 1378bf215546Sopenharmony_ci * resource_get_handle. 1379bf215546Sopenharmony_ci */ 1380bf215546Sopenharmony_cistatic struct pipe_resource * 1381bf215546Sopenharmony_cifd_resource_from_handle(struct pipe_screen *pscreen, 1382bf215546Sopenharmony_ci const struct pipe_resource *tmpl, 1383bf215546Sopenharmony_ci struct winsys_handle *handle, unsigned usage) 1384bf215546Sopenharmony_ci{ 1385bf215546Sopenharmony_ci struct fd_screen *screen = fd_screen(pscreen); 1386bf215546Sopenharmony_ci struct fd_resource *rsc = alloc_resource_struct(pscreen, tmpl); 1387bf215546Sopenharmony_ci 1388bf215546Sopenharmony_ci if (!rsc) 1389bf215546Sopenharmony_ci return NULL; 1390bf215546Sopenharmony_ci 1391bf215546Sopenharmony_ci struct fdl_slice *slice = fd_resource_slice(rsc, 0); 1392bf215546Sopenharmony_ci struct pipe_resource *prsc = &rsc->b.b; 1393bf215546Sopenharmony_ci 1394bf215546Sopenharmony_ci DBG("%" PRSC_FMT ", modifier=%" PRIx64, PRSC_ARGS(prsc), handle->modifier); 1395bf215546Sopenharmony_ci 1396bf215546Sopenharmony_ci rsc->b.is_shared = true; 1397bf215546Sopenharmony_ci 1398bf215546Sopenharmony_ci fd_resource_layout_init(prsc); 1399bf215546Sopenharmony_ci 1400bf215546Sopenharmony_ci struct fd_bo *bo = fd_screen_bo_from_handle(pscreen, handle); 1401bf215546Sopenharmony_ci if (!bo) 1402bf215546Sopenharmony_ci goto fail; 1403bf215546Sopenharmony_ci 1404bf215546Sopenharmony_ci fd_resource_set_bo(rsc, bo); 1405bf215546Sopenharmony_ci 1406bf215546Sopenharmony_ci rsc->internal_format = tmpl->format; 1407bf215546Sopenharmony_ci rsc->layout.layer_first = true; 1408bf215546Sopenharmony_ci rsc->layout.pitch0 = handle->stride; 1409bf215546Sopenharmony_ci slice->offset = handle->offset; 1410bf215546Sopenharmony_ci slice->size0 = handle->stride * prsc->height0; 1411bf215546Sopenharmony_ci 1412bf215546Sopenharmony_ci /* use a pitchalign of gmem_align_w pixels, because GMEM resolve for 1413bf215546Sopenharmony_ci * lower alignments is not implemented (but possible for a6xx at least) 1414bf215546Sopenharmony_ci * 1415bf215546Sopenharmony_ci * for UBWC-enabled resources, layout_resource_for_modifier will further 1416bf215546Sopenharmony_ci * validate the pitch and set the right pitchalign 1417bf215546Sopenharmony_ci */ 1418bf215546Sopenharmony_ci rsc->layout.pitchalign = 1419bf215546Sopenharmony_ci fdl_cpp_shift(&rsc->layout) + util_logbase2(screen->info->gmem_align_w); 1420bf215546Sopenharmony_ci 1421bf215546Sopenharmony_ci /* apply the minimum pitchalign (note: actually 4 for a3xx but doesn't 1422bf215546Sopenharmony_ci * matter) */ 1423bf215546Sopenharmony_ci if (is_a6xx(screen) || is_a5xx(screen)) 1424bf215546Sopenharmony_ci rsc->layout.pitchalign = MAX2(rsc->layout.pitchalign, 6); 1425bf215546Sopenharmony_ci else 1426bf215546Sopenharmony_ci rsc->layout.pitchalign = MAX2(rsc->layout.pitchalign, 5); 1427bf215546Sopenharmony_ci 1428bf215546Sopenharmony_ci if (rsc->layout.pitch0 < (prsc->width0 * rsc->layout.cpp) || 1429bf215546Sopenharmony_ci fd_resource_pitch(rsc, 0) != rsc->layout.pitch0) 1430bf215546Sopenharmony_ci goto fail; 1431bf215546Sopenharmony_ci 1432bf215546Sopenharmony_ci assert(rsc->layout.cpp); 1433bf215546Sopenharmony_ci 1434bf215546Sopenharmony_ci if (screen->layout_resource_for_modifier(rsc, handle->modifier) < 0) 1435bf215546Sopenharmony_ci goto fail; 1436bf215546Sopenharmony_ci 1437bf215546Sopenharmony_ci if (screen->ro) { 1438bf215546Sopenharmony_ci rsc->scanout = 1439bf215546Sopenharmony_ci renderonly_create_gpu_import_for_resource(prsc, screen->ro, NULL); 1440bf215546Sopenharmony_ci /* failure is expected in some cases.. */ 1441bf215546Sopenharmony_ci } 1442bf215546Sopenharmony_ci 1443bf215546Sopenharmony_ci rsc->valid = true; 1444bf215546Sopenharmony_ci 1445bf215546Sopenharmony_ci return prsc; 1446bf215546Sopenharmony_ci 1447bf215546Sopenharmony_cifail: 1448bf215546Sopenharmony_ci fd_resource_destroy(pscreen, prsc); 1449bf215546Sopenharmony_ci return NULL; 1450bf215546Sopenharmony_ci} 1451bf215546Sopenharmony_ci 1452bf215546Sopenharmony_cibool 1453bf215546Sopenharmony_cifd_render_condition_check(struct pipe_context *pctx) 1454bf215546Sopenharmony_ci{ 1455bf215546Sopenharmony_ci struct fd_context *ctx = fd_context(pctx); 1456bf215546Sopenharmony_ci 1457bf215546Sopenharmony_ci if (!ctx->cond_query) 1458bf215546Sopenharmony_ci return true; 1459bf215546Sopenharmony_ci 1460bf215546Sopenharmony_ci perf_debug("Implementing conditional rendering using a CPU read instaed of HW conditional rendering."); 1461bf215546Sopenharmony_ci 1462bf215546Sopenharmony_ci union pipe_query_result res = {0}; 1463bf215546Sopenharmony_ci bool wait = ctx->cond_mode != PIPE_RENDER_COND_NO_WAIT && 1464bf215546Sopenharmony_ci ctx->cond_mode != PIPE_RENDER_COND_BY_REGION_NO_WAIT; 1465bf215546Sopenharmony_ci 1466bf215546Sopenharmony_ci if (pctx->get_query_result(pctx, ctx->cond_query, wait, &res)) 1467bf215546Sopenharmony_ci return (bool)res.u64 != ctx->cond_cond; 1468bf215546Sopenharmony_ci 1469bf215546Sopenharmony_ci return true; 1470bf215546Sopenharmony_ci} 1471bf215546Sopenharmony_ci 1472bf215546Sopenharmony_cistatic void 1473bf215546Sopenharmony_cifd_invalidate_resource(struct pipe_context *pctx, 1474bf215546Sopenharmony_ci struct pipe_resource *prsc) in_dt 1475bf215546Sopenharmony_ci{ 1476bf215546Sopenharmony_ci struct fd_context *ctx = fd_context(pctx); 1477bf215546Sopenharmony_ci struct fd_resource *rsc = fd_resource(prsc); 1478bf215546Sopenharmony_ci 1479bf215546Sopenharmony_ci if (prsc->target == PIPE_BUFFER) { 1480bf215546Sopenharmony_ci /* Handle the glInvalidateBufferData() case: 1481bf215546Sopenharmony_ci */ 1482bf215546Sopenharmony_ci invalidate_resource(rsc, PIPE_MAP_READ | PIPE_MAP_WRITE); 1483bf215546Sopenharmony_ci } else if (rsc->track->write_batch) { 1484bf215546Sopenharmony_ci /* Handle the glInvalidateFramebuffer() case, telling us that 1485bf215546Sopenharmony_ci * we can skip resolve. 1486bf215546Sopenharmony_ci */ 1487bf215546Sopenharmony_ci 1488bf215546Sopenharmony_ci struct fd_batch *batch = rsc->track->write_batch; 1489bf215546Sopenharmony_ci struct pipe_framebuffer_state *pfb = &batch->framebuffer; 1490bf215546Sopenharmony_ci 1491bf215546Sopenharmony_ci if (pfb->zsbuf && pfb->zsbuf->texture == prsc) { 1492bf215546Sopenharmony_ci batch->resolve &= ~(FD_BUFFER_DEPTH | FD_BUFFER_STENCIL); 1493bf215546Sopenharmony_ci fd_context_dirty(ctx, FD_DIRTY_ZSA); 1494bf215546Sopenharmony_ci } 1495bf215546Sopenharmony_ci 1496bf215546Sopenharmony_ci for (unsigned i = 0; i < pfb->nr_cbufs; i++) { 1497bf215546Sopenharmony_ci if (pfb->cbufs[i] && pfb->cbufs[i]->texture == prsc) { 1498bf215546Sopenharmony_ci batch->resolve &= ~(PIPE_CLEAR_COLOR0 << i); 1499bf215546Sopenharmony_ci fd_context_dirty(ctx, FD_DIRTY_FRAMEBUFFER); 1500bf215546Sopenharmony_ci } 1501bf215546Sopenharmony_ci } 1502bf215546Sopenharmony_ci } 1503bf215546Sopenharmony_ci 1504bf215546Sopenharmony_ci rsc->valid = false; 1505bf215546Sopenharmony_ci} 1506bf215546Sopenharmony_ci 1507bf215546Sopenharmony_cistatic enum pipe_format 1508bf215546Sopenharmony_cifd_resource_get_internal_format(struct pipe_resource *prsc) 1509bf215546Sopenharmony_ci{ 1510bf215546Sopenharmony_ci return fd_resource(prsc)->internal_format; 1511bf215546Sopenharmony_ci} 1512bf215546Sopenharmony_ci 1513bf215546Sopenharmony_cistatic void 1514bf215546Sopenharmony_cifd_resource_set_stencil(struct pipe_resource *prsc, 1515bf215546Sopenharmony_ci struct pipe_resource *stencil) 1516bf215546Sopenharmony_ci{ 1517bf215546Sopenharmony_ci fd_resource(prsc)->stencil = fd_resource(stencil); 1518bf215546Sopenharmony_ci} 1519bf215546Sopenharmony_ci 1520bf215546Sopenharmony_cistatic struct pipe_resource * 1521bf215546Sopenharmony_cifd_resource_get_stencil(struct pipe_resource *prsc) 1522bf215546Sopenharmony_ci{ 1523bf215546Sopenharmony_ci struct fd_resource *rsc = fd_resource(prsc); 1524bf215546Sopenharmony_ci if (rsc->stencil) 1525bf215546Sopenharmony_ci return &rsc->stencil->b.b; 1526bf215546Sopenharmony_ci return NULL; 1527bf215546Sopenharmony_ci} 1528bf215546Sopenharmony_ci 1529bf215546Sopenharmony_cistatic const struct u_transfer_vtbl transfer_vtbl = { 1530bf215546Sopenharmony_ci .resource_create = fd_resource_create, 1531bf215546Sopenharmony_ci .resource_destroy = fd_resource_destroy, 1532bf215546Sopenharmony_ci .transfer_map = fd_resource_transfer_map, 1533bf215546Sopenharmony_ci .transfer_flush_region = fd_resource_transfer_flush_region, 1534bf215546Sopenharmony_ci .transfer_unmap = fd_resource_transfer_unmap, 1535bf215546Sopenharmony_ci .get_internal_format = fd_resource_get_internal_format, 1536bf215546Sopenharmony_ci .set_stencil = fd_resource_set_stencil, 1537bf215546Sopenharmony_ci .get_stencil = fd_resource_get_stencil, 1538bf215546Sopenharmony_ci}; 1539bf215546Sopenharmony_ci 1540bf215546Sopenharmony_cistatic const uint64_t supported_modifiers[] = { 1541bf215546Sopenharmony_ci DRM_FORMAT_MOD_LINEAR, 1542bf215546Sopenharmony_ci}; 1543bf215546Sopenharmony_ci 1544bf215546Sopenharmony_cistatic int 1545bf215546Sopenharmony_cifd_layout_resource_for_modifier(struct fd_resource *rsc, uint64_t modifier) 1546bf215546Sopenharmony_ci{ 1547bf215546Sopenharmony_ci switch (modifier) { 1548bf215546Sopenharmony_ci case DRM_FORMAT_MOD_LINEAR: 1549bf215546Sopenharmony_ci /* The dri gallium frontend will pass DRM_FORMAT_MOD_INVALID to us 1550bf215546Sopenharmony_ci * when it's called through any of the non-modifier BO create entry 1551bf215546Sopenharmony_ci * points. Other drivers will determine tiling from the kernel or 1552bf215546Sopenharmony_ci * other legacy backchannels, but for freedreno it just means 1553bf215546Sopenharmony_ci * LINEAR. */ 1554bf215546Sopenharmony_ci case DRM_FORMAT_MOD_INVALID: 1555bf215546Sopenharmony_ci return 0; 1556bf215546Sopenharmony_ci default: 1557bf215546Sopenharmony_ci return -1; 1558bf215546Sopenharmony_ci } 1559bf215546Sopenharmony_ci} 1560bf215546Sopenharmony_ci 1561bf215546Sopenharmony_cistatic struct pipe_resource * 1562bf215546Sopenharmony_cifd_resource_from_memobj(struct pipe_screen *pscreen, 1563bf215546Sopenharmony_ci const struct pipe_resource *tmpl, 1564bf215546Sopenharmony_ci struct pipe_memory_object *pmemobj, uint64_t offset) 1565bf215546Sopenharmony_ci{ 1566bf215546Sopenharmony_ci struct fd_screen *screen = fd_screen(pscreen); 1567bf215546Sopenharmony_ci struct fd_memory_object *memobj = fd_memory_object(pmemobj); 1568bf215546Sopenharmony_ci struct pipe_resource *prsc; 1569bf215546Sopenharmony_ci struct fd_resource *rsc; 1570bf215546Sopenharmony_ci uint32_t size; 1571bf215546Sopenharmony_ci assert(memobj->bo); 1572bf215546Sopenharmony_ci 1573bf215546Sopenharmony_ci /* We shouldn't get a scanout buffer here. */ 1574bf215546Sopenharmony_ci assert(!(tmpl->bind & PIPE_BIND_SCANOUT)); 1575bf215546Sopenharmony_ci 1576bf215546Sopenharmony_ci uint64_t modifiers = DRM_FORMAT_MOD_INVALID; 1577bf215546Sopenharmony_ci if (tmpl->bind & PIPE_BIND_LINEAR) { 1578bf215546Sopenharmony_ci modifiers = DRM_FORMAT_MOD_LINEAR; 1579bf215546Sopenharmony_ci } else if (is_a6xx(screen) && tmpl->width0 >= FDL_MIN_UBWC_WIDTH) { 1580bf215546Sopenharmony_ci modifiers = DRM_FORMAT_MOD_QCOM_COMPRESSED; 1581bf215546Sopenharmony_ci } 1582bf215546Sopenharmony_ci 1583bf215546Sopenharmony_ci /* Allocate new pipe resource. */ 1584bf215546Sopenharmony_ci prsc = fd_resource_allocate_and_resolve(pscreen, tmpl, &modifiers, 1, &size); 1585bf215546Sopenharmony_ci if (!prsc) 1586bf215546Sopenharmony_ci return NULL; 1587bf215546Sopenharmony_ci rsc = fd_resource(prsc); 1588bf215546Sopenharmony_ci rsc->b.is_shared = true; 1589bf215546Sopenharmony_ci 1590bf215546Sopenharmony_ci /* bo's size has to be large enough, otherwise cleanup resource and fail 1591bf215546Sopenharmony_ci * gracefully. 1592bf215546Sopenharmony_ci */ 1593bf215546Sopenharmony_ci if (fd_bo_size(memobj->bo) < size) { 1594bf215546Sopenharmony_ci fd_resource_destroy(pscreen, prsc); 1595bf215546Sopenharmony_ci return NULL; 1596bf215546Sopenharmony_ci } 1597bf215546Sopenharmony_ci 1598bf215546Sopenharmony_ci /* Share the bo with the memory object. */ 1599bf215546Sopenharmony_ci fd_resource_set_bo(rsc, fd_bo_ref(memobj->bo)); 1600bf215546Sopenharmony_ci 1601bf215546Sopenharmony_ci return prsc; 1602bf215546Sopenharmony_ci} 1603bf215546Sopenharmony_ci 1604bf215546Sopenharmony_cistatic struct pipe_memory_object * 1605bf215546Sopenharmony_cifd_memobj_create_from_handle(struct pipe_screen *pscreen, 1606bf215546Sopenharmony_ci struct winsys_handle *whandle, bool dedicated) 1607bf215546Sopenharmony_ci{ 1608bf215546Sopenharmony_ci struct fd_memory_object *memobj = CALLOC_STRUCT(fd_memory_object); 1609bf215546Sopenharmony_ci if (!memobj) 1610bf215546Sopenharmony_ci return NULL; 1611bf215546Sopenharmony_ci 1612bf215546Sopenharmony_ci struct fd_bo *bo = fd_screen_bo_from_handle(pscreen, whandle); 1613bf215546Sopenharmony_ci if (!bo) { 1614bf215546Sopenharmony_ci free(memobj); 1615bf215546Sopenharmony_ci return NULL; 1616bf215546Sopenharmony_ci } 1617bf215546Sopenharmony_ci 1618bf215546Sopenharmony_ci memobj->b.dedicated = dedicated; 1619bf215546Sopenharmony_ci memobj->bo = bo; 1620bf215546Sopenharmony_ci 1621bf215546Sopenharmony_ci return &memobj->b; 1622bf215546Sopenharmony_ci} 1623bf215546Sopenharmony_ci 1624bf215546Sopenharmony_cistatic void 1625bf215546Sopenharmony_cifd_memobj_destroy(struct pipe_screen *pscreen, 1626bf215546Sopenharmony_ci struct pipe_memory_object *pmemobj) 1627bf215546Sopenharmony_ci{ 1628bf215546Sopenharmony_ci struct fd_memory_object *memobj = fd_memory_object(pmemobj); 1629bf215546Sopenharmony_ci 1630bf215546Sopenharmony_ci assert(memobj->bo); 1631bf215546Sopenharmony_ci fd_bo_del(memobj->bo); 1632bf215546Sopenharmony_ci 1633bf215546Sopenharmony_ci free(pmemobj); 1634bf215546Sopenharmony_ci} 1635bf215546Sopenharmony_ci 1636bf215546Sopenharmony_civoid 1637bf215546Sopenharmony_cifd_resource_screen_init(struct pipe_screen *pscreen) 1638bf215546Sopenharmony_ci{ 1639bf215546Sopenharmony_ci struct fd_screen *screen = fd_screen(pscreen); 1640bf215546Sopenharmony_ci bool fake_rgtc = screen->gen < 4; 1641bf215546Sopenharmony_ci 1642bf215546Sopenharmony_ci pscreen->resource_create = u_transfer_helper_resource_create; 1643bf215546Sopenharmony_ci /* NOTE: u_transfer_helper does not yet support the _with_modifiers() 1644bf215546Sopenharmony_ci * variant: 1645bf215546Sopenharmony_ci */ 1646bf215546Sopenharmony_ci pscreen->resource_create_with_modifiers = fd_resource_create_with_modifiers; 1647bf215546Sopenharmony_ci pscreen->resource_from_handle = fd_resource_from_handle; 1648bf215546Sopenharmony_ci pscreen->resource_get_handle = fd_resource_get_handle; 1649bf215546Sopenharmony_ci pscreen->resource_destroy = u_transfer_helper_resource_destroy; 1650bf215546Sopenharmony_ci 1651bf215546Sopenharmony_ci pscreen->transfer_helper = 1652bf215546Sopenharmony_ci u_transfer_helper_create(&transfer_vtbl, true, false, fake_rgtc, true, false); 1653bf215546Sopenharmony_ci 1654bf215546Sopenharmony_ci if (!screen->layout_resource_for_modifier) 1655bf215546Sopenharmony_ci screen->layout_resource_for_modifier = fd_layout_resource_for_modifier; 1656bf215546Sopenharmony_ci if (!screen->supported_modifiers) { 1657bf215546Sopenharmony_ci screen->supported_modifiers = supported_modifiers; 1658bf215546Sopenharmony_ci screen->num_supported_modifiers = ARRAY_SIZE(supported_modifiers); 1659bf215546Sopenharmony_ci } 1660bf215546Sopenharmony_ci 1661bf215546Sopenharmony_ci /* GL_EXT_memory_object */ 1662bf215546Sopenharmony_ci pscreen->memobj_create_from_handle = fd_memobj_create_from_handle; 1663bf215546Sopenharmony_ci pscreen->memobj_destroy = fd_memobj_destroy; 1664bf215546Sopenharmony_ci pscreen->resource_from_memobj = fd_resource_from_memobj; 1665bf215546Sopenharmony_ci} 1666bf215546Sopenharmony_ci 1667bf215546Sopenharmony_cistatic void 1668bf215546Sopenharmony_cifd_get_sample_position(struct pipe_context *context, unsigned sample_count, 1669bf215546Sopenharmony_ci unsigned sample_index, float *pos_out) 1670bf215546Sopenharmony_ci{ 1671bf215546Sopenharmony_ci /* The following is copied from nouveau/nv50 except for position 1672bf215546Sopenharmony_ci * values, which are taken from blob driver */ 1673bf215546Sopenharmony_ci static const uint8_t pos1[1][2] = {{0x8, 0x8}}; 1674bf215546Sopenharmony_ci static const uint8_t pos2[2][2] = {{0xc, 0xc}, {0x4, 0x4}}; 1675bf215546Sopenharmony_ci static const uint8_t pos4[4][2] = {{0x6, 0x2}, 1676bf215546Sopenharmony_ci {0xe, 0x6}, 1677bf215546Sopenharmony_ci {0x2, 0xa}, 1678bf215546Sopenharmony_ci {0xa, 0xe}}; 1679bf215546Sopenharmony_ci /* TODO needs to be verified on supported hw */ 1680bf215546Sopenharmony_ci static const uint8_t pos8[8][2] = {{0x9, 0x5}, {0x7, 0xb}, {0xd, 0x9}, 1681bf215546Sopenharmony_ci {0x5, 0x3}, {0x3, 0xd}, {0x1, 0x7}, 1682bf215546Sopenharmony_ci {0xb, 0xf}, {0xf, 0x1}}; 1683bf215546Sopenharmony_ci 1684bf215546Sopenharmony_ci const uint8_t(*ptr)[2]; 1685bf215546Sopenharmony_ci 1686bf215546Sopenharmony_ci switch (sample_count) { 1687bf215546Sopenharmony_ci case 1: 1688bf215546Sopenharmony_ci ptr = pos1; 1689bf215546Sopenharmony_ci break; 1690bf215546Sopenharmony_ci case 2: 1691bf215546Sopenharmony_ci ptr = pos2; 1692bf215546Sopenharmony_ci break; 1693bf215546Sopenharmony_ci case 4: 1694bf215546Sopenharmony_ci ptr = pos4; 1695bf215546Sopenharmony_ci break; 1696bf215546Sopenharmony_ci case 8: 1697bf215546Sopenharmony_ci ptr = pos8; 1698bf215546Sopenharmony_ci break; 1699bf215546Sopenharmony_ci default: 1700bf215546Sopenharmony_ci assert(0); 1701bf215546Sopenharmony_ci return; 1702bf215546Sopenharmony_ci } 1703bf215546Sopenharmony_ci 1704bf215546Sopenharmony_ci pos_out[0] = ptr[sample_index][0] / 16.0f; 1705bf215546Sopenharmony_ci pos_out[1] = ptr[sample_index][1] / 16.0f; 1706bf215546Sopenharmony_ci} 1707bf215546Sopenharmony_ci 1708bf215546Sopenharmony_cistatic void 1709bf215546Sopenharmony_cifd_blit_pipe(struct pipe_context *pctx, 1710bf215546Sopenharmony_ci const struct pipe_blit_info *blit_info) in_dt 1711bf215546Sopenharmony_ci{ 1712bf215546Sopenharmony_ci /* wrap fd_blit to return void */ 1713bf215546Sopenharmony_ci fd_blit(pctx, blit_info); 1714bf215546Sopenharmony_ci} 1715bf215546Sopenharmony_ci 1716bf215546Sopenharmony_civoid 1717bf215546Sopenharmony_cifd_resource_context_init(struct pipe_context *pctx) 1718bf215546Sopenharmony_ci{ 1719bf215546Sopenharmony_ci pctx->buffer_map = u_transfer_helper_transfer_map; 1720bf215546Sopenharmony_ci pctx->texture_map = u_transfer_helper_transfer_map; 1721bf215546Sopenharmony_ci pctx->transfer_flush_region = u_transfer_helper_transfer_flush_region; 1722bf215546Sopenharmony_ci pctx->buffer_unmap = u_transfer_helper_transfer_unmap; 1723bf215546Sopenharmony_ci pctx->texture_unmap = u_transfer_helper_transfer_unmap; 1724bf215546Sopenharmony_ci pctx->buffer_subdata = u_default_buffer_subdata; 1725bf215546Sopenharmony_ci pctx->texture_subdata = u_default_texture_subdata; 1726bf215546Sopenharmony_ci pctx->create_surface = fd_create_surface; 1727bf215546Sopenharmony_ci pctx->surface_destroy = fd_surface_destroy; 1728bf215546Sopenharmony_ci pctx->resource_copy_region = fd_resource_copy_region; 1729bf215546Sopenharmony_ci pctx->blit = fd_blit_pipe; 1730bf215546Sopenharmony_ci pctx->flush_resource = fd_flush_resource; 1731bf215546Sopenharmony_ci pctx->invalidate_resource = fd_invalidate_resource; 1732bf215546Sopenharmony_ci pctx->get_sample_position = fd_get_sample_position; 1733bf215546Sopenharmony_ci} 1734