diff options
author | Jonathan Gray <jsg@cvs.openbsd.org> | 2015-11-22 02:45:43 +0000 |
---|---|---|
committer | Jonathan Gray <jsg@cvs.openbsd.org> | 2015-11-22 02:45:43 +0000 |
commit | 2ba37c52131b39d6d0ec2452a95ea7a9d7ea6b8f (patch) | |
tree | 2da543a02115219d34deffe911226f3f85f443ac /lib/mesa/src/gallium/drivers/freedreno/freedreno_query_hw.c | |
parent | e7a2786346bc6e40b27248cf122036d8c701fa22 (diff) |
import Mesa 11.0.6
Diffstat (limited to 'lib/mesa/src/gallium/drivers/freedreno/freedreno_query_hw.c')
-rw-r--r-- | lib/mesa/src/gallium/drivers/freedreno/freedreno_query_hw.c | 364 |
1 files changed, 191 insertions, 173 deletions
diff --git a/lib/mesa/src/gallium/drivers/freedreno/freedreno_query_hw.c b/lib/mesa/src/gallium/drivers/freedreno/freedreno_query_hw.c index 73c369114..027fdc9de 100644 --- a/lib/mesa/src/gallium/drivers/freedreno/freedreno_query_hw.c +++ b/lib/mesa/src/gallium/drivers/freedreno/freedreno_query_hw.c @@ -32,7 +32,6 @@ #include "freedreno_query_hw.h" #include "freedreno_context.h" -#include "freedreno_resource.h" #include "freedreno_util.h" struct fd_hw_sample_period { @@ -40,36 +39,43 @@ struct fd_hw_sample_period { struct list_head list; }; +/* maps query_type to sample provider idx: */ +static int pidx(unsigned query_type) +{ + switch (query_type) { + case PIPE_QUERY_OCCLUSION_COUNTER: + return 0; + case PIPE_QUERY_OCCLUSION_PREDICATE: + return 1; + default: + return -1; + } +} + static struct fd_hw_sample * -get_sample(struct fd_batch *batch, struct fd_ringbuffer *ring, +get_sample(struct fd_context *ctx, struct fd_ringbuffer *ring, unsigned query_type) { - struct fd_context *ctx = batch->ctx; struct fd_hw_sample *samp = NULL; int idx = pidx(query_type); - assume(idx >= 0); /* query never would have been created otherwise */ - - if (!batch->sample_cache[idx]) { - struct fd_hw_sample *new_samp = - ctx->hw_sample_providers[idx]->get_sample(batch, ring); - fd_hw_sample_reference(ctx, &batch->sample_cache[idx], new_samp); - util_dynarray_append(&batch->samples, struct fd_hw_sample *, new_samp); - batch->needs_flush = true; + if (!ctx->sample_cache[idx]) { + ctx->sample_cache[idx] = + ctx->sample_providers[idx]->get_sample(ctx, ring); } - fd_hw_sample_reference(ctx, &samp, batch->sample_cache[idx]); + fd_hw_sample_reference(ctx, &samp, ctx->sample_cache[idx]); return samp; } static void -clear_sample_cache(struct fd_batch *batch) +clear_sample_cache(struct fd_context *ctx) { int i; - for (i = 0; i < ARRAY_SIZE(batch->sample_cache); i++) - fd_hw_sample_reference(batch->ctx, &batch->sample_cache[i], NULL); + for (i = 0; i < ARRAY_SIZE(ctx->sample_cache); i++) + fd_hw_sample_reference(ctx, &ctx->sample_cache[i], NULL); } static bool @@ -80,44 +86,36 @@ is_active(struct fd_hw_query *hq, enum fd_render_stage stage) static void -resume_query(struct fd_batch *batch, struct fd_hw_query *hq, +resume_query(struct fd_context *ctx, struct fd_hw_query *hq, struct fd_ringbuffer *ring) { - int idx = pidx(hq->provider->query_type); - DBG("%p", hq); - assert(idx >= 0); /* query never would have been created otherwise */ assert(!hq->period); - batch->active_providers |= (1 << idx); - hq->period = slab_alloc_st(&batch->ctx->sample_period_pool); + hq->period = util_slab_alloc(&ctx->sample_period_pool); list_inithead(&hq->period->list); - hq->period->start = get_sample(batch, ring, hq->base.type); - /* NOTE: slab_alloc_st() does not zero out the buffer: */ + hq->period->start = get_sample(ctx, ring, hq->base.type); + /* NOTE: util_slab_alloc() does not zero out the buffer: */ hq->period->end = NULL; } static void -pause_query(struct fd_batch *batch, struct fd_hw_query *hq, +pause_query(struct fd_context *ctx, struct fd_hw_query *hq, struct fd_ringbuffer *ring) { - int idx = pidx(hq->provider->query_type); - DBG("%p", hq); - assert(idx >= 0); /* query never would have been created otherwise */ assert(hq->period && !hq->period->end); - assert(batch->active_providers & (1 << idx)); - hq->period->end = get_sample(batch, ring, hq->base.type); - list_addtail(&hq->period->list, &hq->periods); + hq->period->end = get_sample(ctx, ring, hq->base.type); + list_addtail(&hq->period->list, &hq->current_periods); hq->period = NULL; } static void -destroy_periods(struct fd_context *ctx, struct fd_hw_query *hq) +destroy_periods(struct fd_context *ctx, struct list_head *list) { struct fd_hw_sample_period *period, *s; - LIST_FOR_EACH_ENTRY_SAFE(period, s, &hq->periods, list) { + LIST_FOR_EACH_ENTRY_SAFE(period, s, list, list) { fd_hw_sample_reference(ctx, &period->start, NULL); fd_hw_sample_reference(ctx, &period->end, NULL); list_del(&period->list); - slab_free_st(&ctx->sample_period_pool, period); + util_slab_free(&ctx->sample_period_pool, period); } } @@ -126,9 +124,8 @@ fd_hw_destroy_query(struct fd_context *ctx, struct fd_query *q) { struct fd_hw_query *hq = fd_hw_query(q); - DBG("%p: active=%d", q, q->active); - - destroy_periods(ctx, hq); + destroy_periods(ctx, &hq->periods); + destroy_periods(ctx, &hq->current_periods); list_del(&hq->list); free(hq); @@ -137,37 +134,36 @@ fd_hw_destroy_query(struct fd_context *ctx, struct fd_query *q) static boolean fd_hw_begin_query(struct fd_context *ctx, struct fd_query *q) { - struct fd_batch *batch = ctx->batch; struct fd_hw_query *hq = fd_hw_query(q); - - DBG("%p: active=%d", q, q->active); + if (q->active) + return false; /* begin_query() should clear previous results: */ - destroy_periods(ctx, hq); + destroy_periods(ctx, &hq->periods); - if (batch && is_active(hq, batch->stage)) - resume_query(batch, hq, batch->draw); + if (is_active(hq, ctx->stage)) + resume_query(ctx, hq, ctx->ring); - /* add to active list: */ - assert(list_empty(&hq->list)); - list_addtail(&hq->list, &ctx->hw_active_queries); + q->active = true; - return true; + /* add to active list: */ + list_del(&hq->list); + list_addtail(&hq->list, &ctx->active_queries); + return true; } static void fd_hw_end_query(struct fd_context *ctx, struct fd_query *q) { - struct fd_batch *batch = ctx->batch; struct fd_hw_query *hq = fd_hw_query(q); - - DBG("%p: active=%d", q, q->active); - - if (batch && is_active(hq, batch->stage)) - pause_query(batch, hq, batch->draw); - - /* remove from active list: */ - list_delinit(&hq->list); + if (!q->active) + return; + if (is_active(hq, ctx->stage)) + pause_query(ctx, hq, ctx->ring); + q->active = false; + /* move to current list: */ + list_del(&hq->list); + list_addtail(&hq->list, &ctx->current_queries); } /* helper to get ptr to specified sample: */ @@ -184,12 +180,30 @@ fd_hw_get_query_result(struct fd_context *ctx, struct fd_query *q, const struct fd_hw_sample_provider *p = hq->provider; struct fd_hw_sample_period *period; - DBG("%p: wait=%d, active=%d", q, wait, q->active); + if (q->active) + return false; + + /* if the app tries to read back the query result before the + * batch is submitted, that forces us to flush so that there + * are actually results to wait for: + */ + if (!LIST_IS_EMPTY(&hq->list)) { + /* if app didn't actually trigger any cmdstream, then + * we have nothing to do: + */ + if (!ctx->needs_flush) + return true; + DBG("reading query result forces flush!"); + fd_context_render(&ctx->base); + } + + util_query_clear_result(result, q->type); if (LIST_IS_EMPTY(&hq->periods)) return true; assert(LIST_IS_EMPTY(&hq->list)); + assert(LIST_IS_EMPTY(&hq->current_periods)); assert(!hq->period); /* if !wait, then check the last sample (the one most likely to @@ -201,29 +215,12 @@ fd_hw_get_query_result(struct fd_context *ctx, struct fd_query *q, period = LIST_ENTRY(struct fd_hw_sample_period, hq->periods.prev, list); - struct fd_resource *rsc = fd_resource(period->end->prsc); - - if (pending(rsc, false)) { - /* piglit spec@arb_occlusion_query@occlusion_query_conform - * test, and silly apps perhaps, get stuck in a loop trying - * to get query result forever with wait==false.. we don't - * wait to flush unnecessarily but we also don't want to - * spin forever: - */ - if (hq->no_wait_cnt++ > 5) - fd_batch_flush(rsc->write_batch, false); - return false; - } - - if (!rsc->bo) - return false; - - ret = fd_bo_cpu_prep(rsc->bo, ctx->screen->pipe, + ret = fd_bo_cpu_prep(period->end->bo, ctx->screen->pipe, DRM_FREEDRENO_PREP_READ | DRM_FREEDRENO_PREP_NOSYNC); if (ret) return false; - fd_bo_cpu_fini(rsc->bo); + fd_bo_cpu_fini(period->end->bo); } /* sum the result across all sample periods: */ @@ -233,28 +230,22 @@ fd_hw_get_query_result(struct fd_context *ctx, struct fd_query *q, unsigned i; /* start and end samples should be from same batch: */ - assert(start->prsc == end->prsc); + assert(start->bo == end->bo); assert(start->num_tiles == end->num_tiles); - struct fd_resource *rsc = fd_resource(start->prsc); - - if (rsc->write_batch) - fd_batch_flush(rsc->write_batch, true); - - /* some piglit tests at least do query with no draws, I guess: */ - if (!rsc->bo) - continue; + for (i = 0; i < start->num_tiles; i++) { + void *ptr; - fd_bo_cpu_prep(rsc->bo, ctx->screen->pipe, DRM_FREEDRENO_PREP_READ); + fd_bo_cpu_prep(start->bo, ctx->screen->pipe, + DRM_FREEDRENO_PREP_READ); - void *ptr = fd_bo_map(rsc->bo); + ptr = fd_bo_map(start->bo); - for (i = 0; i < start->num_tiles; i++) { p->accumulate_result(ctx, sampptr(period->start, i, ptr), sampptr(period->end, i, ptr), result); - } - fd_bo_cpu_fini(rsc->bo); + fd_bo_cpu_fini(start->bo); + } } return true; @@ -274,18 +265,17 @@ fd_hw_create_query(struct fd_context *ctx, unsigned query_type) struct fd_query *q; int idx = pidx(query_type); - if ((idx < 0) || !ctx->hw_sample_providers[idx]) + if ((idx < 0) || !ctx->sample_providers[idx]) return NULL; hq = CALLOC_STRUCT(fd_hw_query); if (!hq) return NULL; - DBG("%p: query_type=%u", hq, query_type); - - hq->provider = ctx->hw_sample_providers[idx]; + hq->provider = ctx->sample_providers[idx]; list_inithead(&hq->periods); + list_inithead(&hq->current_periods); list_inithead(&hq->list); q = &hq->base; @@ -296,123 +286,149 @@ fd_hw_create_query(struct fd_context *ctx, unsigned query_type) } struct fd_hw_sample * -fd_hw_sample_init(struct fd_batch *batch, uint32_t size) +fd_hw_sample_init(struct fd_context *ctx, uint32_t size) { - struct fd_hw_sample *samp = slab_alloc_st(&batch->ctx->sample_pool); + struct fd_hw_sample *samp = util_slab_alloc(&ctx->sample_pool); pipe_reference_init(&samp->reference, 1); samp->size = size; - debug_assert(util_is_power_of_two(size)); - batch->next_sample_offset = align(batch->next_sample_offset, size); - samp->offset = batch->next_sample_offset; - /* NOTE: slab_alloc_st() does not zero out the buffer: */ - samp->prsc = NULL; + samp->offset = ctx->next_sample_offset; + /* NOTE: util_slab_alloc() does not zero out the buffer: */ + samp->bo = NULL; samp->num_tiles = 0; samp->tile_stride = 0; - batch->next_sample_offset += size; - - if (!batch->query_buf) { - struct pipe_screen *pscreen = &batch->ctx->screen->base; - struct pipe_resource templ = { - .target = PIPE_BUFFER, - .format = PIPE_FORMAT_R8_UNORM, - .bind = PIPE_BIND_QUERY_BUFFER, - .width0 = 0, /* create initially zero size buffer */ - .height0 = 1, - .depth0 = 1, - .array_size = 1, - .last_level = 0, - .nr_samples = 1, - }; - batch->query_buf = pscreen->resource_create(pscreen, &templ); - } - - pipe_resource_reference(&samp->prsc, batch->query_buf); - + ctx->next_sample_offset += size; return samp; } void __fd_hw_sample_destroy(struct fd_context *ctx, struct fd_hw_sample *samp) { - pipe_resource_reference(&samp->prsc, NULL); - slab_free_st(&ctx->sample_pool, samp); + if (samp->bo) + fd_bo_del(samp->bo); + util_slab_free(&ctx->sample_pool, samp); +} + +static void +prepare_sample(struct fd_hw_sample *samp, struct fd_bo *bo, + uint32_t num_tiles, uint32_t tile_stride) +{ + if (samp->bo) { + assert(samp->bo == bo); + assert(samp->num_tiles == num_tiles); + assert(samp->tile_stride == tile_stride); + return; + } + samp->bo = bo; + samp->num_tiles = num_tiles; + samp->tile_stride = tile_stride; +} + +static void +prepare_query(struct fd_hw_query *hq, struct fd_bo *bo, + uint32_t num_tiles, uint32_t tile_stride) +{ + struct fd_hw_sample_period *period, *s; + + /* prepare all the samples in the query: */ + LIST_FOR_EACH_ENTRY_SAFE(period, s, &hq->current_periods, list) { + prepare_sample(period->start, bo, num_tiles, tile_stride); + prepare_sample(period->end, bo, num_tiles, tile_stride); + + /* move from current_periods list to periods list: */ + list_del(&period->list); + list_addtail(&period->list, &hq->periods); + } +} + +static void +prepare_queries(struct fd_context *ctx, struct fd_bo *bo, + uint32_t num_tiles, uint32_t tile_stride, + struct list_head *list, bool remove) +{ + struct fd_hw_query *hq, *s; + LIST_FOR_EACH_ENTRY_SAFE(hq, s, list, list) { + prepare_query(hq, bo, num_tiles, tile_stride); + if (remove) + list_delinit(&hq->list); + } } /* called from gmem code once total storage requirements are known (ie. * number of samples times number of tiles) */ void -fd_hw_query_prepare(struct fd_batch *batch, uint32_t num_tiles) +fd_hw_query_prepare(struct fd_context *ctx, uint32_t num_tiles) { - uint32_t tile_stride = batch->next_sample_offset; - - if (tile_stride > 0) - fd_resource_resize(batch->query_buf, tile_stride * num_tiles); + uint32_t tile_stride = ctx->next_sample_offset; + struct fd_bo *bo; + + if (ctx->query_bo) + fd_bo_del(ctx->query_bo); + + if (tile_stride > 0) { + bo = fd_bo_new(ctx->dev, tile_stride * num_tiles, + DRM_FREEDRENO_GEM_CACHE_WCOMBINE | + DRM_FREEDRENO_GEM_TYPE_KMEM); + } else { + bo = NULL; + } - batch->query_tile_stride = tile_stride; + ctx->query_bo = bo; + ctx->query_tile_stride = tile_stride; - while (batch->samples.size > 0) { - struct fd_hw_sample *samp = - util_dynarray_pop(&batch->samples, struct fd_hw_sample *); - samp->num_tiles = num_tiles; - samp->tile_stride = tile_stride; - fd_hw_sample_reference(batch->ctx, &samp, NULL); - } + prepare_queries(ctx, bo, num_tiles, tile_stride, + &ctx->active_queries, false); + prepare_queries(ctx, bo, num_tiles, tile_stride, + &ctx->current_queries, true); /* reset things for next batch: */ - batch->next_sample_offset = 0; + ctx->next_sample_offset = 0; } void -fd_hw_query_prepare_tile(struct fd_batch *batch, uint32_t n, +fd_hw_query_prepare_tile(struct fd_context *ctx, uint32_t n, struct fd_ringbuffer *ring) { - uint32_t tile_stride = batch->query_tile_stride; + uint32_t tile_stride = ctx->query_tile_stride; uint32_t offset = tile_stride * n; /* bail if no queries: */ if (tile_stride == 0) return; - fd_wfi(batch, ring); + fd_wfi(ctx, ring); OUT_PKT0 (ring, HW_QUERY_BASE_REG, 1); - OUT_RELOCW(ring, fd_resource(batch->query_buf)->bo, offset, 0, 0); + OUT_RELOCW(ring, ctx->query_bo, offset, 0, 0); } void -fd_hw_query_set_stage(struct fd_batch *batch, enum fd_render_stage stage) +fd_hw_query_set_stage(struct fd_context *ctx, struct fd_ringbuffer *ring, + enum fd_render_stage stage) { - if (stage != batch->stage) { + /* special case: internal blits (like mipmap level generation) + * go through normal draw path (via util_blitter_blit()).. but + * we need to ignore the FD_STAGE_DRAW which will be set, so we + * don't enable queries which should be paused during internal + * blits: + */ + if ((ctx->stage == FD_STAGE_BLIT) && + (stage != FD_STAGE_NULL)) + return; + + if (stage != ctx->stage) { struct fd_hw_query *hq; - LIST_FOR_EACH_ENTRY(hq, &batch->ctx->hw_active_queries, list) { - bool was_active = is_active(hq, batch->stage); + LIST_FOR_EACH_ENTRY(hq, &ctx->active_queries, list) { + bool was_active = is_active(hq, ctx->stage); bool now_active = is_active(hq, stage); if (now_active && !was_active) - resume_query(batch, hq, batch->draw); + resume_query(ctx, hq, ring); else if (was_active && !now_active) - pause_query(batch, hq, batch->draw); - } - } - clear_sample_cache(batch); -} - -/* call the provider->enable() for all the hw queries that were active - * in the current batch. This sets up perfctr selector regs statically - * for the duration of the batch. - */ -void -fd_hw_query_enable(struct fd_batch *batch, struct fd_ringbuffer *ring) -{ - struct fd_context *ctx = batch->ctx; - for (int idx = 0; idx < MAX_HW_SAMPLE_PROVIDERS; idx++) { - if (batch->active_providers & (1 << idx)) { - assert(ctx->hw_sample_providers[idx]); - if (ctx->hw_sample_providers[idx]->enable) - ctx->hw_sample_providers[idx]->enable(ctx, ring); + pause_query(ctx, hq, ring); } } - batch->active_providers = 0; /* clear it for next frame */ + clear_sample_cache(ctx); + ctx->stage = stage; } void @@ -423,9 +439,9 @@ fd_hw_query_register_provider(struct pipe_context *pctx, int idx = pidx(provider->query_type); assert((0 <= idx) && (idx < MAX_HW_SAMPLE_PROVIDERS)); - assert(!ctx->hw_sample_providers[idx]); + assert(!ctx->sample_providers[idx]); - ctx->hw_sample_providers[idx] = provider; + ctx->sample_providers[idx] = provider; } void @@ -433,10 +449,12 @@ fd_hw_query_init(struct pipe_context *pctx) { struct fd_context *ctx = fd_context(pctx); - slab_create(&ctx->sample_pool, sizeof(struct fd_hw_sample), - 16); - slab_create(&ctx->sample_period_pool, sizeof(struct fd_hw_sample_period), - 16); + util_slab_create(&ctx->sample_pool, sizeof(struct fd_hw_sample), + 16, UTIL_SLAB_SINGLETHREADED); + util_slab_create(&ctx->sample_period_pool, sizeof(struct fd_hw_sample_period), + 16, UTIL_SLAB_SINGLETHREADED); + list_inithead(&ctx->active_queries); + list_inithead(&ctx->current_queries); } void @@ -444,6 +462,6 @@ fd_hw_query_fini(struct pipe_context *pctx) { struct fd_context *ctx = fd_context(pctx); - slab_destroy(&ctx->sample_pool); - slab_destroy(&ctx->sample_period_pool); + util_slab_destroy(&ctx->sample_pool); + util_slab_destroy(&ctx->sample_period_pool); } |