1af69d88dSmrg/* 2af69d88dSmrg * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org> 3af69d88dSmrg * 4af69d88dSmrg * Permission is hereby granted, free of charge, to any person obtaining a 5af69d88dSmrg * copy of this software and associated documentation files (the "Software"), 6af69d88dSmrg * to deal in the Software without restriction, including without limitation 7af69d88dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8af69d88dSmrg * and/or sell copies of the Software, and to permit persons to whom the 9af69d88dSmrg * Software is furnished to do so, subject to the following conditions: 10af69d88dSmrg * 11af69d88dSmrg * The above copyright notice and this permission notice (including the next 12af69d88dSmrg * paragraph) shall be included in all copies or substantial portions of the 13af69d88dSmrg * Software. 14af69d88dSmrg * 15af69d88dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16af69d88dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17af69d88dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19af69d88dSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20af69d88dSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21af69d88dSmrg * SOFTWARE. 22af69d88dSmrg * 23af69d88dSmrg * Authors: 24af69d88dSmrg * Rob Clark <robclark@freedesktop.org> 25af69d88dSmrg */ 26af69d88dSmrg 27af69d88dSmrg#include "freedreno_context.h" 287ec681f3Smrg#include "ir3/ir3_cache.h" 297ec681f3Smrg#include "util/u_upload_mgr.h" 3001e04c3fSmrg#include "freedreno_blitter.h" 31af69d88dSmrg#include "freedreno_draw.h" 3201e04c3fSmrg#include "freedreno_fence.h" 33af69d88dSmrg#include "freedreno_gmem.h" 347ec681f3Smrg#include "freedreno_program.h" 35af69d88dSmrg#include "freedreno_query.h" 36af69d88dSmrg#include "freedreno_query_hw.h" 377ec681f3Smrg#include "freedreno_resource.h" 387ec681f3Smrg#include "freedreno_state.h" 397ec681f3Smrg#include "freedreno_texture.h" 40af69d88dSmrg#include "freedreno_util.h" 417ec681f3Smrg#include "util/u_trace_gallium.h" 42af69d88dSmrg 4301e04c3fSmrgstatic void 4401e04c3fSmrgfd_context_flush(struct pipe_context *pctx, struct pipe_fence_handle **fencep, 457ec681f3Smrg unsigned flags) in_dt 46af69d88dSmrg{ 477ec681f3Smrg struct fd_context *ctx = fd_context(pctx); 487ec681f3Smrg struct pipe_fence_handle *fence = NULL; 497ec681f3Smrg struct fd_batch *batch = NULL; 507ec681f3Smrg 517ec681f3Smrg /* We want to lookup current batch if it exists, but not create a new 527ec681f3Smrg * one if not (unless we need a fence) 537ec681f3Smrg */ 547ec681f3Smrg fd_batch_reference(&batch, ctx->batch); 557ec681f3Smrg 567ec681f3Smrg DBG("%p: flush: flags=%x, fencep=%p", batch, flags, fencep); 577ec681f3Smrg 587ec681f3Smrg if (fencep && !batch) { 597ec681f3Smrg batch = fd_context_batch(ctx); 607ec681f3Smrg } else if (!batch) { 617ec681f3Smrg if (ctx->screen->reorder) 627ec681f3Smrg fd_bc_flush(ctx, flags & PIPE_FLUSH_DEFERRED); 637ec681f3Smrg fd_bc_dump(ctx, "%p: NULL batch, remaining:\n", ctx); 647ec681f3Smrg return; 657ec681f3Smrg } 667ec681f3Smrg 677ec681f3Smrg /* With TC_FLUSH_ASYNC, the fence will have been pre-created from 687ec681f3Smrg * the front-end thread. But not yet associated with a batch, 697ec681f3Smrg * because we cannot safely access ctx->batch outside of the driver 707ec681f3Smrg * thread. So instead, replace the existing batch->fence with the 717ec681f3Smrg * one created earlier 727ec681f3Smrg */ 737ec681f3Smrg if ((flags & TC_FLUSH_ASYNC) && fencep) { 747ec681f3Smrg /* We don't currently expect async+flush in the fence-fd 757ec681f3Smrg * case.. for that to work properly we'd need TC to tell 767ec681f3Smrg * us in the create_fence callback that it needs an fd. 777ec681f3Smrg */ 787ec681f3Smrg assert(!(flags & PIPE_FLUSH_FENCE_FD)); 797ec681f3Smrg 807ec681f3Smrg fd_fence_set_batch(*fencep, batch); 817ec681f3Smrg fd_fence_ref(&batch->fence, *fencep); 827ec681f3Smrg 837ec681f3Smrg /* If we have nothing to flush, update the pre-created unflushed 847ec681f3Smrg * fence with the current state of the last-fence: 857ec681f3Smrg */ 867ec681f3Smrg if (ctx->last_fence) { 877ec681f3Smrg fd_fence_repopulate(*fencep, ctx->last_fence); 887ec681f3Smrg fd_fence_ref(&fence, *fencep); 897ec681f3Smrg fd_bc_dump(ctx, "%p: (deferred) reuse last_fence, remaining:\n", ctx); 907ec681f3Smrg goto out; 917ec681f3Smrg } 927ec681f3Smrg 937ec681f3Smrg /* async flush is not compatible with deferred flush, since 947ec681f3Smrg * nothing triggers the batch flush which fence_flush() would 957ec681f3Smrg * be waiting for 967ec681f3Smrg */ 977ec681f3Smrg flags &= ~PIPE_FLUSH_DEFERRED; 987ec681f3Smrg } else if (!batch->fence) { 997ec681f3Smrg batch->fence = fd_fence_create(batch); 1007ec681f3Smrg } 1017ec681f3Smrg 1027ec681f3Smrg /* In some sequence of events, we can end up with a last_fence that is 1037ec681f3Smrg * not an "fd" fence, which results in eglDupNativeFenceFDANDROID() 1047ec681f3Smrg * errors. 1057ec681f3Smrg */ 1067ec681f3Smrg if ((flags & PIPE_FLUSH_FENCE_FD) && ctx->last_fence && 1077ec681f3Smrg !fd_fence_is_fd(ctx->last_fence)) 1087ec681f3Smrg fd_fence_ref(&ctx->last_fence, NULL); 1097ec681f3Smrg 1107ec681f3Smrg /* if no rendering since last flush, ie. app just decided it needed 1117ec681f3Smrg * a fence, re-use the last one: 1127ec681f3Smrg */ 1137ec681f3Smrg if (ctx->last_fence) { 1147ec681f3Smrg fd_fence_ref(&fence, ctx->last_fence); 1157ec681f3Smrg fd_bc_dump(ctx, "%p: reuse last_fence, remaining:\n", ctx); 1167ec681f3Smrg goto out; 1177ec681f3Smrg } 1187ec681f3Smrg 1197ec681f3Smrg /* Take a ref to the batch's fence (batch can be unref'd when flushed: */ 1207ec681f3Smrg fd_fence_ref(&fence, batch->fence); 1217ec681f3Smrg 1227ec681f3Smrg if (flags & PIPE_FLUSH_FENCE_FD) 1237ec681f3Smrg fence->submit_fence.use_fence_fd = true; 1247ec681f3Smrg 1257ec681f3Smrg fd_bc_dump(ctx, "%p: flushing %p<%u>, flags=0x%x, pending:\n", ctx, 1267ec681f3Smrg batch, batch->seqno, flags); 1277ec681f3Smrg 1287ec681f3Smrg /* If we get here, we need to flush for a fence, even if there is 1297ec681f3Smrg * no rendering yet: 1307ec681f3Smrg */ 1317ec681f3Smrg batch->needs_flush = true; 1327ec681f3Smrg 1337ec681f3Smrg if (!ctx->screen->reorder) { 1347ec681f3Smrg fd_batch_flush(batch); 1357ec681f3Smrg } else { 1367ec681f3Smrg fd_bc_flush(ctx, flags & PIPE_FLUSH_DEFERRED); 1377ec681f3Smrg } 1387ec681f3Smrg 1397ec681f3Smrg fd_bc_dump(ctx, "%p: remaining:\n", ctx); 140af69d88dSmrg 14101e04c3fSmrgout: 1427ec681f3Smrg if (fencep) 1437ec681f3Smrg fd_fence_ref(fencep, fence); 1447ec681f3Smrg 1457ec681f3Smrg fd_fence_ref(&ctx->last_fence, fence); 146af69d88dSmrg 1477ec681f3Smrg fd_fence_ref(&fence, NULL); 148af69d88dSmrg 1497ec681f3Smrg fd_batch_reference(&batch, NULL); 1507ec681f3Smrg 1517ec681f3Smrg u_trace_context_process(&ctx->trace_context, 1527ec681f3Smrg !!(flags & PIPE_FLUSH_END_OF_FRAME)); 15301e04c3fSmrg} 154af69d88dSmrg 15501e04c3fSmrgstatic void 1567ec681f3Smrgfd_texture_barrier(struct pipe_context *pctx, unsigned flags) in_dt 15701e04c3fSmrg{ 1587ec681f3Smrg if (flags == PIPE_TEXTURE_BARRIER_FRAMEBUFFER) { 1597ec681f3Smrg struct fd_context *ctx = fd_context(pctx); 1607ec681f3Smrg 1617ec681f3Smrg if (ctx->framebuffer_barrier) { 1627ec681f3Smrg ctx->framebuffer_barrier(ctx); 1637ec681f3Smrg return; 1647ec681f3Smrg } 1657ec681f3Smrg } 1667ec681f3Smrg 1677ec681f3Smrg /* On devices that could sample from GMEM we could possibly do better. 1687ec681f3Smrg * Or if we knew that we were doing GMEM bypass we could just emit a 1697ec681f3Smrg * cache flush, perhaps? But we don't know if future draws would cause 1707ec681f3Smrg * us to use GMEM, and a flush in bypass isn't the end of the world. 1717ec681f3Smrg */ 1727ec681f3Smrg fd_context_flush(pctx, NULL, 0); 17301e04c3fSmrg} 174af69d88dSmrg 17501e04c3fSmrgstatic void 17601e04c3fSmrgfd_memory_barrier(struct pipe_context *pctx, unsigned flags) 17701e04c3fSmrg{ 1787ec681f3Smrg if (!(flags & ~PIPE_BARRIER_UPDATE)) 1797ec681f3Smrg return; 1807ec681f3Smrg 1817ec681f3Smrg fd_context_flush(pctx, NULL, 0); 1827ec681f3Smrg 1837ec681f3Smrg /* TODO do we need to check for persistently mapped buffers and 1847ec681f3Smrg * fd_bo_cpu_prep()?? 1857ec681f3Smrg */ 1867ec681f3Smrg} 1877ec681f3Smrg 1887ec681f3Smrgstatic void 1897ec681f3Smrgemit_string_tail(struct fd_ringbuffer *ring, const char *string, int len) 1907ec681f3Smrg{ 1917ec681f3Smrg const uint32_t *buf = (const void *)string; 1927ec681f3Smrg 1937ec681f3Smrg while (len >= 4) { 1947ec681f3Smrg OUT_RING(ring, *buf); 1957ec681f3Smrg buf++; 1967ec681f3Smrg len -= 4; 1977ec681f3Smrg } 1987ec681f3Smrg 1997ec681f3Smrg /* copy remainder bytes without reading past end of input string: */ 2007ec681f3Smrg if (len > 0) { 2017ec681f3Smrg uint32_t w = 0; 2027ec681f3Smrg memcpy(&w, buf, len); 2037ec681f3Smrg OUT_RING(ring, w); 2047ec681f3Smrg } 2057ec681f3Smrg} 2067ec681f3Smrg 2077ec681f3Smrg/* for prior to a5xx: */ 2087ec681f3Smrgvoid 2097ec681f3Smrgfd_emit_string(struct fd_ringbuffer *ring, const char *string, int len) 2107ec681f3Smrg{ 2117ec681f3Smrg /* max packet size is 0x3fff+1 dwords: */ 2127ec681f3Smrg len = MIN2(len, 0x4000 * 4); 2139f464c52Smaya 2147ec681f3Smrg OUT_PKT3(ring, CP_NOP, align(len, 4) / 4); 2157ec681f3Smrg emit_string_tail(ring, string, len); 2167ec681f3Smrg} 2177ec681f3Smrg 2187ec681f3Smrg/* for a5xx+ */ 2197ec681f3Smrgvoid 2207ec681f3Smrgfd_emit_string5(struct fd_ringbuffer *ring, const char *string, int len) 2217ec681f3Smrg{ 2227ec681f3Smrg /* max packet size is 0x3fff dwords: */ 2237ec681f3Smrg len = MIN2(len, 0x3fff * 4); 2247ec681f3Smrg 2257ec681f3Smrg OUT_PKT7(ring, CP_NOP, align(len, 4) / 4); 2267ec681f3Smrg emit_string_tail(ring, string, len); 227af69d88dSmrg} 228af69d88dSmrg 22901e04c3fSmrg/** 23001e04c3fSmrg * emit marker string as payload of a no-op packet, which can be 23101e04c3fSmrg * decoded by cffdump. 232af69d88dSmrg */ 23301e04c3fSmrgstatic void 2347ec681f3Smrgfd_emit_string_marker(struct pipe_context *pctx, const char *string, 2357ec681f3Smrg int len) in_dt 2367ec681f3Smrg{ 2377ec681f3Smrg struct fd_context *ctx = fd_context(pctx); 2387ec681f3Smrg 2397ec681f3Smrg DBG("%.*s", len, string); 2407ec681f3Smrg 2417ec681f3Smrg if (!ctx->batch) 2427ec681f3Smrg return; 2437ec681f3Smrg 2447ec681f3Smrg struct fd_batch *batch = fd_context_batch_locked(ctx); 2457ec681f3Smrg 2467ec681f3Smrg fd_batch_needs_flush(batch); 2477ec681f3Smrg 2487ec681f3Smrg if (ctx->screen->gen >= 5) { 2497ec681f3Smrg fd_emit_string5(batch->draw, string, len); 2507ec681f3Smrg } else { 2517ec681f3Smrg fd_emit_string(batch->draw, string, len); 2527ec681f3Smrg } 2537ec681f3Smrg 2547ec681f3Smrg fd_batch_unlock_submit(batch); 2557ec681f3Smrg fd_batch_reference(&batch, NULL); 2567ec681f3Smrg} 2577ec681f3Smrg 2587ec681f3Smrg/** 2597ec681f3Smrg * If we have a pending fence_server_sync() (GPU side sync), flush now. 2607ec681f3Smrg * The alternative to try to track this with batch dependencies gets 2617ec681f3Smrg * hairy quickly. 2627ec681f3Smrg * 2637ec681f3Smrg * Call this before switching to a different batch, to handle this case. 2647ec681f3Smrg */ 2657ec681f3Smrgvoid 2667ec681f3Smrgfd_context_switch_from(struct fd_context *ctx) 2677ec681f3Smrg{ 2687ec681f3Smrg if (ctx->batch && (ctx->batch->in_fence_fd != -1)) 2697ec681f3Smrg fd_batch_flush(ctx->batch); 2707ec681f3Smrg} 2717ec681f3Smrg 2727ec681f3Smrg/** 2737ec681f3Smrg * If there is a pending fence-fd that we need to sync on, this will 2747ec681f3Smrg * transfer the reference to the next batch we are going to render 2757ec681f3Smrg * to. 2767ec681f3Smrg */ 2777ec681f3Smrgvoid 2787ec681f3Smrgfd_context_switch_to(struct fd_context *ctx, struct fd_batch *batch) 2797ec681f3Smrg{ 2807ec681f3Smrg if (ctx->in_fence_fd != -1) { 2817ec681f3Smrg sync_accumulate("freedreno", &batch->in_fence_fd, ctx->in_fence_fd); 2827ec681f3Smrg close(ctx->in_fence_fd); 2837ec681f3Smrg ctx->in_fence_fd = -1; 2847ec681f3Smrg } 2857ec681f3Smrg} 2867ec681f3Smrg 2877ec681f3Smrg/** 2887ec681f3Smrg * Return a reference to the current batch, caller must unref. 2897ec681f3Smrg */ 2907ec681f3Smrgstruct fd_batch * 2917ec681f3Smrgfd_context_batch(struct fd_context *ctx) 2927ec681f3Smrg{ 2937ec681f3Smrg struct fd_batch *batch = NULL; 2947ec681f3Smrg 2957ec681f3Smrg tc_assert_driver_thread(ctx->tc); 2967ec681f3Smrg 2977ec681f3Smrg fd_batch_reference(&batch, ctx->batch); 2987ec681f3Smrg 2997ec681f3Smrg if (unlikely(!batch)) { 3007ec681f3Smrg batch = 3017ec681f3Smrg fd_batch_from_fb(ctx, &ctx->framebuffer); 3027ec681f3Smrg util_copy_framebuffer_state(&batch->framebuffer, &ctx->framebuffer); 3037ec681f3Smrg fd_batch_reference(&ctx->batch, batch); 3047ec681f3Smrg fd_context_all_dirty(ctx); 3057ec681f3Smrg } 3067ec681f3Smrg fd_context_switch_to(ctx, batch); 3077ec681f3Smrg 3087ec681f3Smrg return batch; 3097ec681f3Smrg} 3107ec681f3Smrg 3117ec681f3Smrg/** 3127ec681f3Smrg * Return a locked reference to the current batch. A batch with emit 3137ec681f3Smrg * lock held is protected against flushing while the lock is held. 3147ec681f3Smrg * The emit-lock should be acquired before screen-lock. The emit-lock 3157ec681f3Smrg * should be held while emitting cmdstream. 3167ec681f3Smrg */ 3177ec681f3Smrgstruct fd_batch * 3187ec681f3Smrgfd_context_batch_locked(struct fd_context *ctx) 319af69d88dSmrg{ 3207ec681f3Smrg struct fd_batch *batch = NULL; 3217ec681f3Smrg 3227ec681f3Smrg while (!batch) { 3237ec681f3Smrg batch = fd_context_batch(ctx); 3247ec681f3Smrg if (!fd_batch_lock_submit(batch)) { 3257ec681f3Smrg fd_batch_reference(&batch, NULL); 3267ec681f3Smrg } 3277ec681f3Smrg } 3287ec681f3Smrg 3297ec681f3Smrg return batch; 330af69d88dSmrg} 331af69d88dSmrg 332af69d88dSmrgvoid 333af69d88dSmrgfd_context_destroy(struct pipe_context *pctx) 334af69d88dSmrg{ 3357ec681f3Smrg struct fd_context *ctx = fd_context(pctx); 3367ec681f3Smrg unsigned i; 3377ec681f3Smrg 3387ec681f3Smrg DBG(""); 3397ec681f3Smrg 3407ec681f3Smrg fd_screen_lock(ctx->screen); 3417ec681f3Smrg list_del(&ctx->node); 3427ec681f3Smrg fd_screen_unlock(ctx->screen); 3437ec681f3Smrg 3447ec681f3Smrg fd_fence_ref(&ctx->last_fence, NULL); 3457ec681f3Smrg 3467ec681f3Smrg if (ctx->in_fence_fd != -1) 3477ec681f3Smrg close(ctx->in_fence_fd); 348af69d88dSmrg 3497ec681f3Smrg for (i = 0; i < ARRAY_SIZE(ctx->pvtmem); i++) { 3507ec681f3Smrg if (ctx->pvtmem[i].bo) 3517ec681f3Smrg fd_bo_del(ctx->pvtmem[i].bo); 3527ec681f3Smrg } 353af69d88dSmrg 3547ec681f3Smrg util_copy_framebuffer_state(&ctx->framebuffer, NULL); 3557ec681f3Smrg fd_batch_reference(&ctx->batch, NULL); /* unref current batch */ 35601e04c3fSmrg 3577ec681f3Smrg /* Make sure nothing in the batch cache references our context any more. */ 3587ec681f3Smrg fd_bc_flush(ctx, false); 359af69d88dSmrg 3607ec681f3Smrg fd_prog_fini(pctx); 36101e04c3fSmrg 3627ec681f3Smrg if (ctx->blitter) 3637ec681f3Smrg util_blitter_destroy(ctx->blitter); 364af69d88dSmrg 3657ec681f3Smrg if (pctx->stream_uploader) 3667ec681f3Smrg u_upload_destroy(pctx->stream_uploader); 367af69d88dSmrg 3687ec681f3Smrg for (i = 0; i < ARRAY_SIZE(ctx->clear_rs_state); i++) 3697ec681f3Smrg if (ctx->clear_rs_state[i]) 3707ec681f3Smrg pctx->delete_rasterizer_state(pctx, ctx->clear_rs_state[i]); 371af69d88dSmrg 3727ec681f3Smrg slab_destroy_child(&ctx->transfer_pool); 3737ec681f3Smrg slab_destroy_child(&ctx->transfer_pool_unsync); 374af69d88dSmrg 3757ec681f3Smrg for (i = 0; i < ARRAY_SIZE(ctx->vsc_pipe_bo); i++) { 3767ec681f3Smrg if (!ctx->vsc_pipe_bo[i]) 3777ec681f3Smrg break; 3787ec681f3Smrg fd_bo_del(ctx->vsc_pipe_bo[i]); 3797ec681f3Smrg } 380af69d88dSmrg 3817ec681f3Smrg fd_device_del(ctx->dev); 3827ec681f3Smrg fd_pipe_purge(ctx->pipe); 3837ec681f3Smrg fd_pipe_del(ctx->pipe); 384af69d88dSmrg 3857ec681f3Smrg simple_mtx_destroy(&ctx->gmem_lock); 386af69d88dSmrg 3877ec681f3Smrg u_trace_context_fini(&ctx->trace_context); 38801e04c3fSmrg 3897ec681f3Smrg fd_autotune_fini(&ctx->autotune); 3907ec681f3Smrg 3917ec681f3Smrg ir3_cache_destroy(ctx->shader_cache); 3927ec681f3Smrg 3937ec681f3Smrg if (FD_DBG(BSTAT) || FD_DBG(MSGS)) { 3947ec681f3Smrg mesa_logi( 3957ec681f3Smrg "batch_total=%u, batch_sysmem=%u, batch_gmem=%u, batch_nondraw=%u, " 3967ec681f3Smrg "batch_restore=%u\n", 3977ec681f3Smrg (uint32_t)ctx->stats.batch_total, (uint32_t)ctx->stats.batch_sysmem, 3987ec681f3Smrg (uint32_t)ctx->stats.batch_gmem, (uint32_t)ctx->stats.batch_nondraw, 3997ec681f3Smrg (uint32_t)ctx->stats.batch_restore); 4007ec681f3Smrg } 40101e04c3fSmrg} 40201e04c3fSmrg 40301e04c3fSmrgstatic void 40401e04c3fSmrgfd_set_debug_callback(struct pipe_context *pctx, 4057ec681f3Smrg const struct pipe_debug_callback *cb) 40601e04c3fSmrg{ 4077ec681f3Smrg struct fd_context *ctx = fd_context(pctx); 40801e04c3fSmrg 4097ec681f3Smrg if (cb) 4107ec681f3Smrg ctx->debug = *cb; 4117ec681f3Smrg else 4127ec681f3Smrg memset(&ctx->debug, 0, sizeof(ctx->debug)); 41301e04c3fSmrg} 41401e04c3fSmrg 4159f464c52Smayastatic uint32_t 4169f464c52Smayafd_get_reset_count(struct fd_context *ctx, bool per_context) 4179f464c52Smaya{ 4187ec681f3Smrg uint64_t val; 4197ec681f3Smrg enum fd_param_id param = per_context ? FD_CTX_FAULTS : FD_GLOBAL_FAULTS; 4207ec681f3Smrg int ret = fd_pipe_get_param(ctx->pipe, param, &val); 4217ec681f3Smrg debug_assert(!ret); 4227ec681f3Smrg return val; 4239f464c52Smaya} 4249f464c52Smaya 4259f464c52Smayastatic enum pipe_reset_status 4269f464c52Smayafd_get_device_reset_status(struct pipe_context *pctx) 4279f464c52Smaya{ 4287ec681f3Smrg struct fd_context *ctx = fd_context(pctx); 4297ec681f3Smrg int context_faults = fd_get_reset_count(ctx, true); 4307ec681f3Smrg int global_faults = fd_get_reset_count(ctx, false); 4317ec681f3Smrg enum pipe_reset_status status; 4327ec681f3Smrg 4337ec681f3Smrg if (context_faults != ctx->context_reset_count) { 4347ec681f3Smrg status = PIPE_GUILTY_CONTEXT_RESET; 4357ec681f3Smrg } else if (global_faults != ctx->global_reset_count) { 4367ec681f3Smrg status = PIPE_INNOCENT_CONTEXT_RESET; 4377ec681f3Smrg } else { 4387ec681f3Smrg status = PIPE_NO_RESET; 4397ec681f3Smrg } 4407ec681f3Smrg 4417ec681f3Smrg ctx->context_reset_count = context_faults; 4427ec681f3Smrg ctx->global_reset_count = global_faults; 4437ec681f3Smrg 4447ec681f3Smrg return status; 4457ec681f3Smrg} 4467ec681f3Smrg 4477ec681f3Smrgstatic void 4487ec681f3Smrgfd_trace_record_ts(struct u_trace *ut, void *cs, void *timestamps, 4497ec681f3Smrg unsigned idx) 4507ec681f3Smrg{ 4517ec681f3Smrg struct fd_batch *batch = container_of(ut, struct fd_batch, trace); 4527ec681f3Smrg struct fd_ringbuffer *ring = cs; 4537ec681f3Smrg struct pipe_resource *buffer = timestamps; 4547ec681f3Smrg 4557ec681f3Smrg if (ring->cur == batch->last_timestamp_cmd) { 4567ec681f3Smrg uint64_t *ts = fd_bo_map(fd_resource(buffer)->bo); 4577ec681f3Smrg ts[idx] = U_TRACE_NO_TIMESTAMP; 4587ec681f3Smrg return; 4597ec681f3Smrg } 4607ec681f3Smrg 4617ec681f3Smrg unsigned ts_offset = idx * sizeof(uint64_t); 4627ec681f3Smrg batch->ctx->record_timestamp(ring, fd_resource(buffer)->bo, ts_offset); 4637ec681f3Smrg batch->last_timestamp_cmd = ring->cur; 4647ec681f3Smrg} 4657ec681f3Smrg 4667ec681f3Smrgstatic uint64_t 4677ec681f3Smrgfd_trace_read_ts(struct u_trace_context *utctx, 4687ec681f3Smrg void *timestamps, unsigned idx, void *flush_data) 4697ec681f3Smrg{ 4707ec681f3Smrg struct fd_context *ctx = 4717ec681f3Smrg container_of(utctx, struct fd_context, trace_context); 4727ec681f3Smrg struct pipe_resource *buffer = timestamps; 4737ec681f3Smrg struct fd_bo *ts_bo = fd_resource(buffer)->bo; 4747ec681f3Smrg 4757ec681f3Smrg /* Only need to stall on results for the first entry: */ 4767ec681f3Smrg if (idx == 0) { 4777ec681f3Smrg /* Avoid triggering deferred submits from flushing, since that 4787ec681f3Smrg * changes the behavior of what we are trying to measure: 4797ec681f3Smrg */ 4807ec681f3Smrg while (fd_bo_cpu_prep(ts_bo, ctx->pipe, FD_BO_PREP_NOSYNC)) 4817ec681f3Smrg usleep(10000); 4827ec681f3Smrg int ret = fd_bo_cpu_prep(ts_bo, ctx->pipe, FD_BO_PREP_READ); 4837ec681f3Smrg if (ret) 4847ec681f3Smrg return U_TRACE_NO_TIMESTAMP; 4857ec681f3Smrg } 4867ec681f3Smrg 4877ec681f3Smrg uint64_t *ts = fd_bo_map(ts_bo); 4887ec681f3Smrg 4897ec681f3Smrg /* Don't translate the no-timestamp marker: */ 4907ec681f3Smrg if (ts[idx] == U_TRACE_NO_TIMESTAMP) 4917ec681f3Smrg return U_TRACE_NO_TIMESTAMP; 4927ec681f3Smrg 4937ec681f3Smrg return ctx->ts_to_ns(ts[idx]); 4947ec681f3Smrg} 4957ec681f3Smrg 4967ec681f3Smrgstatic void 4977ec681f3Smrgfd_trace_delete_flush_data(struct u_trace_context *utctx, void *flush_data) 4987ec681f3Smrg{ 4997ec681f3Smrg /* We don't use flush_data at the moment. */ 5009f464c52Smaya} 5019f464c52Smaya 50201e04c3fSmrg/* TODO we could combine a few of these small buffers (solid_vbuf, 50301e04c3fSmrg * blit_texcoord_vbuf, and vsc_size_mem, into a single buffer and 50401e04c3fSmrg * save a tiny bit of memory 50501e04c3fSmrg */ 50601e04c3fSmrg 50701e04c3fSmrgstatic struct pipe_resource * 50801e04c3fSmrgcreate_solid_vertexbuf(struct pipe_context *pctx) 50901e04c3fSmrg{ 5107ec681f3Smrg static const float init_shader_const[] = { 5117ec681f3Smrg -1.000000, +1.000000, +1.000000, +1.000000, -1.000000, +1.000000, 5127ec681f3Smrg }; 5137ec681f3Smrg struct pipe_resource *prsc = 5147ec681f3Smrg pipe_buffer_create(pctx->screen, PIPE_BIND_CUSTOM, PIPE_USAGE_IMMUTABLE, 5157ec681f3Smrg sizeof(init_shader_const)); 5167ec681f3Smrg pipe_buffer_write(pctx, prsc, 0, sizeof(init_shader_const), 5177ec681f3Smrg init_shader_const); 5187ec681f3Smrg return prsc; 51901e04c3fSmrg} 52001e04c3fSmrg 52101e04c3fSmrgstatic struct pipe_resource * 52201e04c3fSmrgcreate_blit_texcoord_vertexbuf(struct pipe_context *pctx) 52301e04c3fSmrg{ 5247ec681f3Smrg struct pipe_resource *prsc = pipe_buffer_create( 5257ec681f3Smrg pctx->screen, PIPE_BIND_CUSTOM, PIPE_USAGE_DYNAMIC, 16); 5267ec681f3Smrg return prsc; 52701e04c3fSmrg} 52801e04c3fSmrg 52901e04c3fSmrgvoid 53001e04c3fSmrgfd_context_setup_common_vbos(struct fd_context *ctx) 53101e04c3fSmrg{ 5327ec681f3Smrg struct pipe_context *pctx = &ctx->base; 5337ec681f3Smrg 5347ec681f3Smrg ctx->solid_vbuf = create_solid_vertexbuf(pctx); 5357ec681f3Smrg ctx->blit_texcoord_vbuf = create_blit_texcoord_vertexbuf(pctx); 5367ec681f3Smrg 5377ec681f3Smrg /* setup solid_vbuf_state: */ 5387ec681f3Smrg ctx->solid_vbuf_state.vtx = pctx->create_vertex_elements_state( 5397ec681f3Smrg pctx, 1, 5407ec681f3Smrg (struct pipe_vertex_element[]){{ 5417ec681f3Smrg .vertex_buffer_index = 0, 5427ec681f3Smrg .src_offset = 0, 5437ec681f3Smrg .src_format = PIPE_FORMAT_R32G32B32_FLOAT, 5447ec681f3Smrg }}); 5457ec681f3Smrg ctx->solid_vbuf_state.vertexbuf.count = 1; 5467ec681f3Smrg ctx->solid_vbuf_state.vertexbuf.vb[0].stride = 12; 5477ec681f3Smrg ctx->solid_vbuf_state.vertexbuf.vb[0].buffer.resource = ctx->solid_vbuf; 5487ec681f3Smrg 5497ec681f3Smrg /* setup blit_vbuf_state: */ 5507ec681f3Smrg ctx->blit_vbuf_state.vtx = pctx->create_vertex_elements_state( 5517ec681f3Smrg pctx, 2, 5527ec681f3Smrg (struct pipe_vertex_element[]){ 5537ec681f3Smrg { 5547ec681f3Smrg .vertex_buffer_index = 0, 5557ec681f3Smrg .src_offset = 0, 5567ec681f3Smrg .src_format = PIPE_FORMAT_R32G32_FLOAT, 5577ec681f3Smrg }, 5587ec681f3Smrg { 5597ec681f3Smrg .vertex_buffer_index = 1, 5607ec681f3Smrg .src_offset = 0, 5617ec681f3Smrg .src_format = PIPE_FORMAT_R32G32B32_FLOAT, 5627ec681f3Smrg }}); 5637ec681f3Smrg ctx->blit_vbuf_state.vertexbuf.count = 2; 5647ec681f3Smrg ctx->blit_vbuf_state.vertexbuf.vb[0].stride = 8; 5657ec681f3Smrg ctx->blit_vbuf_state.vertexbuf.vb[0].buffer.resource = 5667ec681f3Smrg ctx->blit_texcoord_vbuf; 5677ec681f3Smrg ctx->blit_vbuf_state.vertexbuf.vb[1].stride = 12; 5687ec681f3Smrg ctx->blit_vbuf_state.vertexbuf.vb[1].buffer.resource = ctx->solid_vbuf; 56901e04c3fSmrg} 570af69d88dSmrg 57101e04c3fSmrgvoid 57201e04c3fSmrgfd_context_cleanup_common_vbos(struct fd_context *ctx) 57301e04c3fSmrg{ 5747ec681f3Smrg struct pipe_context *pctx = &ctx->base; 57501e04c3fSmrg 5767ec681f3Smrg pctx->delete_vertex_elements_state(pctx, ctx->solid_vbuf_state.vtx); 5777ec681f3Smrg pctx->delete_vertex_elements_state(pctx, ctx->blit_vbuf_state.vtx); 57801e04c3fSmrg 5797ec681f3Smrg pipe_resource_reference(&ctx->solid_vbuf, NULL); 5807ec681f3Smrg pipe_resource_reference(&ctx->blit_texcoord_vbuf, NULL); 581af69d88dSmrg} 582af69d88dSmrg 583af69d88dSmrgstruct pipe_context * 584af69d88dSmrgfd_context_init(struct fd_context *ctx, struct pipe_screen *pscreen, 5857ec681f3Smrg void *priv, unsigned flags) 5867ec681f3Smrg disable_thread_safety_analysis 587af69d88dSmrg{ 5887ec681f3Smrg struct fd_screen *screen = fd_screen(pscreen); 5897ec681f3Smrg struct pipe_context *pctx; 5907ec681f3Smrg unsigned prio = 1; 5917ec681f3Smrg 5927ec681f3Smrg /* lower numerical value == higher priority: */ 5937ec681f3Smrg if (FD_DBG(HIPRIO)) 5947ec681f3Smrg prio = 0; 5957ec681f3Smrg else if (flags & PIPE_CONTEXT_HIGH_PRIORITY) 5967ec681f3Smrg prio = 0; 5977ec681f3Smrg else if (flags & PIPE_CONTEXT_LOW_PRIORITY) 5987ec681f3Smrg prio = 2; 5997ec681f3Smrg 6007ec681f3Smrg /* Some of the stats will get printed out at context destroy, so 6017ec681f3Smrg * make sure they are collected: 6027ec681f3Smrg */ 6037ec681f3Smrg if (FD_DBG(BSTAT) || FD_DBG(MSGS)) 6047ec681f3Smrg ctx->stats_users++; 6057ec681f3Smrg 6067ec681f3Smrg ctx->screen = screen; 6077ec681f3Smrg ctx->pipe = fd_pipe_new2(screen->dev, FD_PIPE_3D, prio); 6087ec681f3Smrg 6097ec681f3Smrg ctx->in_fence_fd = -1; 6107ec681f3Smrg 6117ec681f3Smrg if (fd_device_version(screen->dev) >= FD_VERSION_ROBUSTNESS) { 6127ec681f3Smrg ctx->context_reset_count = fd_get_reset_count(ctx, true); 6137ec681f3Smrg ctx->global_reset_count = fd_get_reset_count(ctx, false); 6147ec681f3Smrg } 6157ec681f3Smrg 6167ec681f3Smrg simple_mtx_init(&ctx->gmem_lock, mtx_plain); 6177ec681f3Smrg 6187ec681f3Smrg /* need some sane default in case gallium frontends don't 6197ec681f3Smrg * set some state: 6207ec681f3Smrg */ 6217ec681f3Smrg ctx->sample_mask = 0xffff; 6227ec681f3Smrg ctx->active_queries = true; 6237ec681f3Smrg 6247ec681f3Smrg pctx = &ctx->base; 6257ec681f3Smrg pctx->screen = pscreen; 6267ec681f3Smrg pctx->priv = priv; 6277ec681f3Smrg pctx->flush = fd_context_flush; 6287ec681f3Smrg pctx->emit_string_marker = fd_emit_string_marker; 6297ec681f3Smrg pctx->set_debug_callback = fd_set_debug_callback; 6307ec681f3Smrg pctx->get_device_reset_status = fd_get_device_reset_status; 6317ec681f3Smrg pctx->create_fence_fd = fd_create_fence_fd; 6327ec681f3Smrg pctx->fence_server_sync = fd_fence_server_sync; 6337ec681f3Smrg pctx->fence_server_signal = fd_fence_server_signal; 6347ec681f3Smrg pctx->texture_barrier = fd_texture_barrier; 6357ec681f3Smrg pctx->memory_barrier = fd_memory_barrier; 6367ec681f3Smrg 6377ec681f3Smrg pctx->stream_uploader = u_upload_create_default(pctx); 6387ec681f3Smrg if (!pctx->stream_uploader) 6397ec681f3Smrg goto fail; 6407ec681f3Smrg pctx->const_uploader = pctx->stream_uploader; 6417ec681f3Smrg 6427ec681f3Smrg slab_create_child(&ctx->transfer_pool, &screen->transfer_pool); 6437ec681f3Smrg slab_create_child(&ctx->transfer_pool_unsync, &screen->transfer_pool); 6447ec681f3Smrg 6457ec681f3Smrg fd_draw_init(pctx); 6467ec681f3Smrg fd_resource_context_init(pctx); 6477ec681f3Smrg fd_query_context_init(pctx); 6487ec681f3Smrg fd_texture_init(pctx); 6497ec681f3Smrg fd_state_init(pctx); 6507ec681f3Smrg 6517ec681f3Smrg ctx->blitter = util_blitter_create(pctx); 6527ec681f3Smrg if (!ctx->blitter) 6537ec681f3Smrg goto fail; 6547ec681f3Smrg 6557ec681f3Smrg list_inithead(&ctx->hw_active_queries); 6567ec681f3Smrg list_inithead(&ctx->acc_active_queries); 6577ec681f3Smrg 6587ec681f3Smrg fd_screen_lock(ctx->screen); 6597ec681f3Smrg ctx->seqno = ++screen->ctx_seqno; 6607ec681f3Smrg list_add(&ctx->node, &ctx->screen->context_list); 6617ec681f3Smrg fd_screen_unlock(ctx->screen); 6627ec681f3Smrg 6637ec681f3Smrg ctx->current_scissor = &ctx->disabled_scissor; 6647ec681f3Smrg 6657ec681f3Smrg u_trace_pipe_context_init(&ctx->trace_context, pctx, 6667ec681f3Smrg fd_trace_record_ts, 6677ec681f3Smrg fd_trace_read_ts, 6687ec681f3Smrg fd_trace_delete_flush_data); 6697ec681f3Smrg 6707ec681f3Smrg fd_autotune_init(&ctx->autotune, screen->dev); 6717ec681f3Smrg 6727ec681f3Smrg return pctx; 673af69d88dSmrg 674af69d88dSmrgfail: 6757ec681f3Smrg pctx->destroy(pctx); 6767ec681f3Smrg return NULL; 6777ec681f3Smrg} 6787ec681f3Smrg 6797ec681f3Smrgstruct pipe_context * 6807ec681f3Smrgfd_context_init_tc(struct pipe_context *pctx, unsigned flags) 6817ec681f3Smrg{ 6827ec681f3Smrg struct fd_context *ctx = fd_context(pctx); 6837ec681f3Smrg 6847ec681f3Smrg if (!(flags & PIPE_CONTEXT_PREFER_THREADED)) 6857ec681f3Smrg return pctx; 6867ec681f3Smrg 6877ec681f3Smrg /* Clover (compute-only) is unsupported. */ 6887ec681f3Smrg if (flags & PIPE_CONTEXT_COMPUTE_ONLY) 6897ec681f3Smrg return pctx; 6907ec681f3Smrg 6917ec681f3Smrg struct pipe_context *tc = threaded_context_create( 6927ec681f3Smrg pctx, &ctx->screen->transfer_pool, 6937ec681f3Smrg fd_replace_buffer_storage, 6947ec681f3Smrg &(struct threaded_context_options){ 6957ec681f3Smrg .create_fence = fd_fence_create_unflushed, 6967ec681f3Smrg .is_resource_busy = fd_resource_busy, 6977ec681f3Smrg .unsynchronized_get_device_reset_status = true, 6987ec681f3Smrg }, 6997ec681f3Smrg &ctx->tc); 7007ec681f3Smrg 7017ec681f3Smrg if (tc && tc != pctx) 7027ec681f3Smrg threaded_context_init_bytes_mapped_limit((struct threaded_context *)tc, 16); 7037ec681f3Smrg 7047ec681f3Smrg return tc; 705af69d88dSmrg} 706