X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fdrivers%2Ffreedreno%2Ffreedreno_context.c;h=a69a194379bbcd810804d68829baf92f4c69d29f;hb=00f9d4b1fdbfd9bf00c4eb2160ae85057369e8a1;hp=1cf366b0c6a62e219b440af2594e6fd756e52e67;hpb=8fc9702a1b7027d266121713771eafd2aa1a93b6;p=mesa.git diff --git a/src/gallium/drivers/freedreno/freedreno_context.c b/src/gallium/drivers/freedreno/freedreno_context.c index 1cf366b0c6a..a69a194379b 100644 --- a/src/gallium/drivers/freedreno/freedreno_context.c +++ b/src/gallium/drivers/freedreno/freedreno_context.c @@ -1,5 +1,3 @@ -/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ - /* * Copyright (C) 2012 Rob Clark * @@ -27,8 +25,10 @@ */ #include "freedreno_context.h" +#include "freedreno_blitter.h" #include "freedreno_draw.h" #include "freedreno_fence.h" +#include "freedreno_log.h" #include "freedreno_program.h" #include "freedreno_resource.h" #include "freedreno_texture.h" @@ -39,57 +39,110 @@ #include "freedreno_util.h" #include "util/u_upload_mgr.h" +#if DETECT_OS_ANDROID +#include "util/u_process.h" +#include +#include +#endif + static void -fd_context_flush(struct pipe_context *pctx, struct pipe_fence_handle **fence, +fd_context_flush(struct pipe_context *pctx, struct pipe_fence_handle **fencep, unsigned flags) { struct fd_context *ctx = fd_context(pctx); + struct pipe_fence_handle *fence = NULL; + // TODO we want to lookup batch if it exists, but not create one if not. + struct fd_batch *batch = fd_context_batch(ctx); + + DBG("%p: flush: flags=%x\n", ctx->batch, flags); + + /* In some sequence of events, we can end up with a last_fence that is + * not an "fd" fence, which results in eglDupNativeFenceFDANDROID() + * errors. + */ + if (flags & PIPE_FLUSH_FENCE_FD) + fd_fence_ref(&ctx->last_fence, NULL); + + /* if no rendering since last flush, ie. app just decided it needed + * a fence, re-use the last one: + */ + if (ctx->last_fence) { + fd_fence_ref(&fence, ctx->last_fence); + fd_bc_dump(ctx->screen, "%p: reuse last_fence, remaining:\n", ctx); + goto out; + } + + if (!batch) { + fd_bc_dump(ctx->screen, "%p: NULL batch, remaining:\n", ctx); + return; + } + + /* Take a ref to the batch's fence (batch can be unref'd when flushed: */ + fd_fence_ref(&fence, batch->fence); if (flags & PIPE_FLUSH_FENCE_FD) - ctx->batch->needs_out_fence_fd = true; + batch->needs_out_fence_fd = true; + + fd_bc_dump(ctx->screen, "%p: flushing %p<%u>, flags=0x%x, pending:\n", + ctx, batch, batch->seqno, flags); if (!ctx->screen->reorder) { - fd_batch_flush(ctx->batch, true); + fd_batch_flush(batch); + } else if (flags & PIPE_FLUSH_DEFERRED) { + fd_bc_flush_deferred(&ctx->screen->batch_cache, ctx); } else { fd_bc_flush(&ctx->screen->batch_cache, ctx); } - if (fence) { - /* if there hasn't been any rendering submitted yet, we might not - * have actually created a fence - */ - if (!ctx->last_fence || ctx->batch->needs_out_fence_fd) { - ctx->batch->needs_flush = true; - fd_gmem_render_noop(ctx->batch); - fd_batch_reset(ctx->batch); + fd_bc_dump(ctx->screen, "%p: remaining:\n", ctx); + +out: + if (fencep) + fd_fence_ref(fencep, fence); + + fd_fence_ref(&ctx->last_fence, fence); + + fd_fence_ref(&fence, NULL); + + if (flags & PIPE_FLUSH_END_OF_FRAME) + fd_log_eof(ctx); +} + +static void +fd_texture_barrier(struct pipe_context *pctx, unsigned flags) +{ + if (flags == PIPE_TEXTURE_BARRIER_FRAMEBUFFER) { + struct fd_context *ctx = fd_context(pctx); + + if (ctx->framebuffer_barrier) { + ctx->framebuffer_barrier(ctx); + return; } - fd_fence_ref(pctx->screen, fence, ctx->last_fence); } + + /* On devices that could sample from GMEM we could possibly do better. + * Or if we knew that we were doing GMEM bypass we could just emit a + * cache flush, perhaps? But we don't know if future draws would cause + * us to use GMEM, and a flush in bypass isn't the end of the world. + */ + fd_context_flush(pctx, NULL, 0); } -/** - * emit marker string as payload of a no-op packet, which can be - * decoded by cffdump. - */ static void -fd_emit_string_marker(struct pipe_context *pctx, const char *string, int len) +fd_memory_barrier(struct pipe_context *pctx, unsigned flags) { - struct fd_context *ctx = fd_context(pctx); - struct fd_ringbuffer *ring; - const uint32_t *buf = (const void *)string; - - if (!ctx->batch) + if (!(flags & ~PIPE_BARRIER_UPDATE)) return; - ring = ctx->batch->draw; + fd_context_flush(pctx, NULL, 0); + /* TODO do we need to check for persistently mapped buffers and fd_bo_cpu_prep()?? */ +} - /* max packet size is 0x3fff dwords: */ - len = MIN2(len, 0x3fff * 4); +static void +emit_string_tail(struct fd_ringbuffer *ring, const char *string, int len) +{ + const uint32_t *buf = (const void *)string; - if (ctx->screen->gpu_id >= 500) - OUT_PKT7(ring, CP_NOP, align(len, 4) / 4); - else - OUT_PKT3(ring, CP_NOP, align(len, 4) / 4); while (len >= 4) { OUT_RING(ring, *buf); buf++; @@ -104,6 +157,51 @@ fd_emit_string_marker(struct pipe_context *pctx, const char *string, int len) } } +/* for prior to a5xx: */ +void +fd_emit_string(struct fd_ringbuffer *ring, + const char *string, int len) +{ + /* max packet size is 0x3fff+1 dwords: */ + len = MIN2(len, 0x4000 * 4); + + OUT_PKT3(ring, CP_NOP, align(len, 4) / 4); + emit_string_tail(ring, string, len); +} + +/* for a5xx+ */ +void +fd_emit_string5(struct fd_ringbuffer *ring, + const char *string, int len) +{ + /* max packet size is 0x3fff dwords: */ + len = MIN2(len, 0x3fff * 4); + + OUT_PKT7(ring, CP_NOP, align(len, 4) / 4); + emit_string_tail(ring, string, len); +} + +/** + * emit marker string as payload of a no-op packet, which can be + * decoded by cffdump. + */ +static void +fd_emit_string_marker(struct pipe_context *pctx, const char *string, int len) +{ + struct fd_context *ctx = fd_context(pctx); + + if (!ctx->batch) + return; + + ctx->batch->needs_flush = true; + + if (ctx->screen->gpu_id >= 500) { + fd_emit_string5(ctx->batch->draw, string, len); + } else { + fd_emit_string(ctx->batch->draw, string, len); + } +} + void fd_context_destroy(struct pipe_context *pctx) { @@ -112,14 +210,19 @@ fd_context_destroy(struct pipe_context *pctx) DBG(""); - if (ctx->screen->reorder && util_queue_is_initialized(&ctx->flush_queue)) - util_queue_destroy(&ctx->flush_queue); + fd_screen_lock(ctx->screen); + list_del(&ctx->node); + fd_screen_unlock(ctx->screen); + + fd_log_process(ctx, true); + assert(list_is_empty(&ctx->log_chunks)); + + fd_fence_ref(&ctx->last_fence, NULL); + util_copy_framebuffer_state(&ctx->framebuffer, NULL); fd_batch_reference(&ctx->batch, NULL); /* unref current batch */ fd_bc_invalidate_context(ctx); - fd_fence_ref(pctx->screen, &ctx->last_fence, NULL); - fd_prog_fini(pctx); if (ctx->blitter) @@ -136,22 +239,23 @@ fd_context_destroy(struct pipe_context *pctx) slab_destroy_child(&ctx->transfer_pool); - for (i = 0; i < ARRAY_SIZE(ctx->pipe); i++) { - struct fd_vsc_pipe *pipe = &ctx->pipe[i]; - if (!pipe->bo) + for (i = 0; i < ARRAY_SIZE(ctx->vsc_pipe_bo); i++) { + if (!ctx->vsc_pipe_bo[i]) break; - fd_bo_del(pipe->bo); + fd_bo_del(ctx->vsc_pipe_bo[i]); } fd_device_del(ctx->dev); + fd_pipe_del(ctx->pipe); + + mtx_destroy(&ctx->gmem_lock); if (fd_mesa_debug & (FD_DBG_BSTAT | FD_DBG_MSGS)) { - printf("batch_total=%u, batch_sysmem=%u, batch_gmem=%u, batch_restore=%u\n", + printf("batch_total=%u, batch_sysmem=%u, batch_gmem=%u, batch_nondraw=%u, batch_restore=%u\n", (uint32_t)ctx->stats.batch_total, (uint32_t)ctx->stats.batch_sysmem, - (uint32_t)ctx->stats.batch_gmem, (uint32_t)ctx->stats.batch_restore); + (uint32_t)ctx->stats.batch_gmem, (uint32_t)ctx->stats.batch_nondraw, + (uint32_t)ctx->stats.batch_restore); } - - FREE(ctx); } static void @@ -166,6 +270,39 @@ fd_set_debug_callback(struct pipe_context *pctx, memset(&ctx->debug, 0, sizeof(ctx->debug)); } +static uint32_t +fd_get_reset_count(struct fd_context *ctx, bool per_context) +{ + uint64_t val; + enum fd_param_id param = + per_context ? FD_CTX_FAULTS : FD_GLOBAL_FAULTS; + int ret = fd_pipe_get_param(ctx->pipe, param, &val); + debug_assert(!ret); + return val; +} + +static enum pipe_reset_status +fd_get_device_reset_status(struct pipe_context *pctx) +{ + struct fd_context *ctx = fd_context(pctx); + int context_faults = fd_get_reset_count(ctx, true); + int global_faults = fd_get_reset_count(ctx, false); + enum pipe_reset_status status; + + if (context_faults != ctx->context_reset_count) { + status = PIPE_GUILTY_CONTEXT_RESET; + } else if (global_faults != ctx->global_reset_count) { + status = PIPE_INNOCENT_CONTEXT_RESET; + } else { + status = PIPE_NO_RESET; + } + + ctx->context_reset_count = context_faults; + ctx->global_reset_count = global_faults; + + return status; +} + /* TODO we could combine a few of these small buffers (solid_vbuf, * blit_texcoord_vbuf, and vsc_size_mem, into a single buffer and * save a tiny bit of memory @@ -244,13 +381,28 @@ fd_context_cleanup_common_vbos(struct fd_context *ctx) struct pipe_context * fd_context_init(struct fd_context *ctx, struct pipe_screen *pscreen, - const uint8_t *primtypes, void *priv) + const uint8_t *primtypes, void *priv, unsigned flags) { struct fd_screen *screen = fd_screen(pscreen); struct pipe_context *pctx; + unsigned prio = 1; int i; + /* lower numerical value == higher priority: */ + if (fd_mesa_debug & FD_DBG_HIPRIO) + prio = 0; + else if (flags & PIPE_CONTEXT_HIGH_PRIORITY) + prio = 0; + else if (flags & PIPE_CONTEXT_LOW_PRIORITY) + prio = 2; + ctx->screen = screen; + ctx->pipe = fd_pipe_new2(screen->dev, FD_PIPE_3D, prio); + + if (fd_device_version(screen->dev) >= FD_VERSION_ROBUSTNESS) { + ctx->context_reset_count = fd_get_reset_count(ctx, true); + ctx->global_reset_count = fd_get_reset_count(ctx, false); + } ctx->primtypes = primtypes; ctx->primtype_mask = 0; @@ -258,10 +410,13 @@ fd_context_init(struct fd_context *ctx, struct pipe_screen *pscreen, if (primtypes[i]) ctx->primtype_mask |= (1 << i); - /* need some sane default in case state tracker doesn't + (void) mtx_init(&ctx->gmem_lock, mtx_plain); + + /* need some sane default in case gallium frontends don't * set some state: */ ctx->sample_mask = 0xffff; + ctx->active_queries = true; pctx = &ctx->base; pctx->screen = pscreen; @@ -269,16 +424,17 @@ fd_context_init(struct fd_context *ctx, struct pipe_screen *pscreen, pctx->flush = fd_context_flush; pctx->emit_string_marker = fd_emit_string_marker; pctx->set_debug_callback = fd_set_debug_callback; + pctx->get_device_reset_status = fd_get_device_reset_status; pctx->create_fence_fd = fd_create_fence_fd; pctx->fence_server_sync = fd_fence_server_sync; + pctx->texture_barrier = fd_texture_barrier; + pctx->memory_barrier = fd_memory_barrier; pctx->stream_uploader = u_upload_create_default(pctx); if (!pctx->stream_uploader) goto fail; pctx->const_uploader = pctx->stream_uploader; - ctx->batch = fd_bc_alloc_batch(&screen->batch_cache, ctx); - slab_create_child(&ctx->transfer_pool, &screen->transfer_pool); fd_draw_init(pctx); @@ -297,6 +453,33 @@ fd_context_init(struct fd_context *ctx, struct pipe_screen *pscreen, list_inithead(&ctx->hw_active_queries); list_inithead(&ctx->acc_active_queries); + list_inithead(&ctx->log_chunks); + + fd_screen_lock(ctx->screen); + list_add(&ctx->node, &ctx->screen->context_list); + fd_screen_unlock(ctx->screen); + + ctx->current_scissor = &ctx->disabled_scissor; + + ctx->log_out = stdout; + + if ((fd_mesa_debug & FD_DBG_LOG) && + !(ctx->record_timestamp && ctx->ts_to_ns)) { + printf("logging not supported!\n"); + fd_mesa_debug &= ~FD_DBG_LOG; + } + +#if DETECT_OS_ANDROID + if (fd_mesa_debug & FD_DBG_LOG) { + static unsigned idx = 0; + char *p; + asprintf(&p, "/data/fdlog/%s-%d.log", util_get_process_name(), idx++); + + FILE *f = fopen(p, "w"); + if (f) + ctx->log_out = f; + } +#endif return pctx;