Path: blob/21.2-virgl/src/gallium/drivers/freedreno/freedreno_query_hw.c
4570 views
/*1* Copyright (C) 2014 Rob Clark <[email protected]>2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,19* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE20* SOFTWARE.21*22* Authors:23* Rob Clark <[email protected]>24*/2526#include "pipe/p_state.h"27#include "util/u_inlines.h"28#include "util/u_memory.h"2930#include "freedreno_context.h"31#include "freedreno_query_hw.h"32#include "freedreno_resource.h"33#include "freedreno_util.h"3435struct fd_hw_sample_period {36struct fd_hw_sample *start, *end;37struct list_head list;38};3940static struct fd_hw_sample *41get_sample(struct fd_batch *batch, struct fd_ringbuffer *ring,42unsigned query_type) assert_dt43{44struct fd_context *ctx = batch->ctx;45struct fd_hw_sample *samp = NULL;46int idx = pidx(query_type);4748assume(idx >= 0); /* query never would have been created otherwise */4950if (!batch->sample_cache[idx]) {51struct fd_hw_sample *new_samp =52ctx->hw_sample_providers[idx]->get_sample(batch, ring);53fd_hw_sample_reference(ctx, &batch->sample_cache[idx], new_samp);54util_dynarray_append(&batch->samples, struct fd_hw_sample *, new_samp);55fd_batch_needs_flush(batch);56}5758fd_hw_sample_reference(ctx, &samp, batch->sample_cache[idx]);5960return samp;61}6263static void64clear_sample_cache(struct fd_batch *batch)65{66int i;6768for (i = 0; i < ARRAY_SIZE(batch->sample_cache); i++)69fd_hw_sample_reference(batch->ctx, &batch->sample_cache[i], NULL);70}7172static bool73query_active_in_batch(struct fd_batch *batch, struct fd_hw_query *hq)74{75int idx = pidx(hq->provider->query_type);76return batch->query_providers_active & (1 << idx);77}7879static void80resume_query(struct fd_batch *batch, struct fd_hw_query *hq,81struct fd_ringbuffer *ring) assert_dt82{83int idx = pidx(hq->provider->query_type);84DBG("%p", hq);85assert(idx >= 0); /* query never would have been created otherwise */86assert(!hq->period);87batch->query_providers_used |= (1 << idx);88batch->query_providers_active |= (1 << idx);89hq->period = slab_alloc_st(&batch->ctx->sample_period_pool);90list_inithead(&hq->period->list);91hq->period->start = get_sample(batch, ring, hq->base.type);92/* NOTE: slab_alloc_st() does not zero out the buffer: */93hq->period->end = NULL;94}9596static void97pause_query(struct fd_batch *batch, struct fd_hw_query *hq,98struct fd_ringbuffer *ring) assert_dt99{100ASSERTED int idx = pidx(hq->provider->query_type);101DBG("%p", hq);102assert(idx >= 0); /* query never would have been created otherwise */103assert(hq->period && !hq->period->end);104assert(query_active_in_batch(batch, hq));105batch->query_providers_active &= ~(1 << idx);106hq->period->end = get_sample(batch, ring, hq->base.type);107list_addtail(&hq->period->list, &hq->periods);108hq->period = NULL;109}110111static void112destroy_periods(struct fd_context *ctx, struct fd_hw_query *hq)113{114struct fd_hw_sample_period *period, *s;115LIST_FOR_EACH_ENTRY_SAFE (period, s, &hq->periods, list) {116fd_hw_sample_reference(ctx, &period->start, NULL);117fd_hw_sample_reference(ctx, &period->end, NULL);118list_del(&period->list);119slab_free_st(&ctx->sample_period_pool, period);120}121}122123static void124fd_hw_destroy_query(struct fd_context *ctx, struct fd_query *q)125{126struct fd_hw_query *hq = fd_hw_query(q);127128DBG("%p", q);129130destroy_periods(ctx, hq);131list_del(&hq->list);132133free(hq);134}135136static void137fd_hw_begin_query(struct fd_context *ctx, struct fd_query *q) assert_dt138{139struct fd_batch *batch = fd_context_batch_locked(ctx);140struct fd_hw_query *hq = fd_hw_query(q);141142DBG("%p", q);143144/* begin_query() should clear previous results: */145destroy_periods(ctx, hq);146147if (batch && (ctx->active_queries || hq->provider->always))148resume_query(batch, hq, batch->draw);149150/* add to active list: */151assert(list_is_empty(&hq->list));152list_addtail(&hq->list, &ctx->hw_active_queries);153154fd_batch_unlock_submit(batch);155fd_batch_reference(&batch, NULL);156}157158static void159fd_hw_end_query(struct fd_context *ctx, struct fd_query *q) assert_dt160{161struct fd_batch *batch = fd_context_batch_locked(ctx);162struct fd_hw_query *hq = fd_hw_query(q);163164DBG("%p", q);165166if (batch && (ctx->active_queries || hq->provider->always))167pause_query(batch, hq, batch->draw);168169/* remove from active list: */170list_delinit(&hq->list);171172fd_batch_unlock_submit(batch);173fd_batch_reference(&batch, NULL);174}175176/* helper to get ptr to specified sample: */177static void *178sampptr(struct fd_hw_sample *samp, uint32_t n, void *ptr)179{180return ((char *)ptr) + (samp->tile_stride * n) + samp->offset;181}182183static bool184fd_hw_get_query_result(struct fd_context *ctx, struct fd_query *q, bool wait,185union pipe_query_result *result)186{187struct fd_hw_query *hq = fd_hw_query(q);188const struct fd_hw_sample_provider *p = hq->provider;189struct fd_hw_sample_period *period, *tmp;190191DBG("%p: wait=%d", q, wait);192193if (list_is_empty(&hq->periods))194return true;195196assert(list_is_empty(&hq->list));197assert(!hq->period);198199/* sum the result across all sample periods. Start with the last period200* so that no-wait will bail quickly.201*/202LIST_FOR_EACH_ENTRY_SAFE_REV (period, tmp, &hq->periods, list) {203struct fd_hw_sample *start = period->start;204ASSERTED struct fd_hw_sample *end = period->end;205unsigned i;206207/* start and end samples should be from same batch: */208assert(start->prsc == end->prsc);209assert(start->num_tiles == end->num_tiles);210211struct fd_resource *rsc = fd_resource(start->prsc);212213/* ARB_occlusion_query says:214*215* "Querying the state for a given occlusion query forces that216* occlusion query to complete within a finite amount of time."217*218* So, regardless of whether we are supposed to wait or not, we do need to219* flush now.220*/221if (rsc->track->write_batch) {222tc_assert_driver_thread(ctx->tc);223fd_context_access_begin(ctx);224fd_batch_flush(rsc->track->write_batch);225fd_context_access_end(ctx);226}227228/* some piglit tests at least do query with no draws, I guess: */229if (!rsc->bo)230continue;231232if (!wait) {233int ret = fd_resource_wait(234ctx, rsc, FD_BO_PREP_READ | FD_BO_PREP_NOSYNC | FD_BO_PREP_FLUSH);235if (ret)236return false;237} else {238fd_resource_wait(ctx, rsc, FD_BO_PREP_READ);239}240241void *ptr = fd_bo_map(rsc->bo);242243for (i = 0; i < start->num_tiles; i++) {244p->accumulate_result(ctx, sampptr(period->start, i, ptr),245sampptr(period->end, i, ptr), result);246}247248fd_bo_cpu_fini(rsc->bo);249}250251return true;252}253254static const struct fd_query_funcs hw_query_funcs = {255.destroy_query = fd_hw_destroy_query,256.begin_query = fd_hw_begin_query,257.end_query = fd_hw_end_query,258.get_query_result = fd_hw_get_query_result,259};260261struct fd_query *262fd_hw_create_query(struct fd_context *ctx, unsigned query_type, unsigned index)263{264struct fd_hw_query *hq;265struct fd_query *q;266int idx = pidx(query_type);267268if ((idx < 0) || !ctx->hw_sample_providers[idx])269return NULL;270271hq = CALLOC_STRUCT(fd_hw_query);272if (!hq)273return NULL;274275DBG("%p: query_type=%u", hq, query_type);276277hq->provider = ctx->hw_sample_providers[idx];278279list_inithead(&hq->periods);280list_inithead(&hq->list);281282q = &hq->base;283q->funcs = &hw_query_funcs;284q->type = query_type;285q->index = index;286287return q;288}289290struct fd_hw_sample *291fd_hw_sample_init(struct fd_batch *batch, uint32_t size)292{293struct fd_hw_sample *samp = slab_alloc_st(&batch->ctx->sample_pool);294pipe_reference_init(&samp->reference, 1);295samp->size = size;296debug_assert(util_is_power_of_two_or_zero(size));297batch->next_sample_offset = align(batch->next_sample_offset, size);298samp->offset = batch->next_sample_offset;299/* NOTE: slab_alloc_st() does not zero out the buffer: */300samp->prsc = NULL;301samp->num_tiles = 0;302samp->tile_stride = 0;303batch->next_sample_offset += size;304305if (!batch->query_buf) {306struct pipe_screen *pscreen = &batch->ctx->screen->base;307struct pipe_resource templ = {308.target = PIPE_BUFFER,309.format = PIPE_FORMAT_R8_UNORM,310.bind = PIPE_BIND_QUERY_BUFFER,311.width0 = 0, /* create initially zero size buffer */312.height0 = 1,313.depth0 = 1,314.array_size = 1,315.last_level = 0,316.nr_samples = 1,317};318batch->query_buf = pscreen->resource_create(pscreen, &templ);319}320321pipe_resource_reference(&samp->prsc, batch->query_buf);322323return samp;324}325326void327__fd_hw_sample_destroy(struct fd_context *ctx, struct fd_hw_sample *samp)328{329pipe_resource_reference(&samp->prsc, NULL);330slab_free_st(&ctx->sample_pool, samp);331}332333/* called from gmem code once total storage requirements are known (ie.334* number of samples times number of tiles)335*/336void337fd_hw_query_prepare(struct fd_batch *batch, uint32_t num_tiles)338{339uint32_t tile_stride = batch->next_sample_offset;340341if (tile_stride > 0)342fd_resource_resize(batch->query_buf, tile_stride * num_tiles);343344batch->query_tile_stride = tile_stride;345346while (batch->samples.size > 0) {347struct fd_hw_sample *samp =348util_dynarray_pop(&batch->samples, struct fd_hw_sample *);349samp->num_tiles = num_tiles;350samp->tile_stride = tile_stride;351fd_hw_sample_reference(batch->ctx, &samp, NULL);352}353354/* reset things for next batch: */355batch->next_sample_offset = 0;356}357358void359fd_hw_query_prepare_tile(struct fd_batch *batch, uint32_t n,360struct fd_ringbuffer *ring)361{362uint32_t tile_stride = batch->query_tile_stride;363uint32_t offset = tile_stride * n;364365/* bail if no queries: */366if (tile_stride == 0)367return;368369fd_wfi(batch, ring);370OUT_PKT0(ring, HW_QUERY_BASE_REG, 1);371OUT_RELOC(ring, fd_resource(batch->query_buf)->bo, offset, 0, 0);372}373374void375fd_hw_query_update_batch(struct fd_batch *batch, bool disable_all)376{377struct fd_context *ctx = batch->ctx;378379if (disable_all || ctx->update_active_queries) {380struct fd_hw_query *hq;381LIST_FOR_EACH_ENTRY (hq, &batch->ctx->hw_active_queries, list) {382bool was_active = query_active_in_batch(batch, hq);383bool now_active =384!disable_all && (ctx->active_queries || hq->provider->always);385386if (now_active && !was_active)387resume_query(batch, hq, batch->draw);388else if (was_active && !now_active)389pause_query(batch, hq, batch->draw);390}391}392clear_sample_cache(batch);393}394395/* call the provider->enable() for all the hw queries that were active396* in the current batch. This sets up perfctr selector regs statically397* for the duration of the batch.398*/399void400fd_hw_query_enable(struct fd_batch *batch, struct fd_ringbuffer *ring)401{402struct fd_context *ctx = batch->ctx;403for (int idx = 0; idx < MAX_HW_SAMPLE_PROVIDERS; idx++) {404if (batch->query_providers_used & (1 << idx)) {405assert(ctx->hw_sample_providers[idx]);406if (ctx->hw_sample_providers[idx]->enable)407ctx->hw_sample_providers[idx]->enable(ctx, ring);408}409}410}411412void413fd_hw_query_register_provider(struct pipe_context *pctx,414const struct fd_hw_sample_provider *provider)415{416struct fd_context *ctx = fd_context(pctx);417int idx = pidx(provider->query_type);418419assert((0 <= idx) && (idx < MAX_HW_SAMPLE_PROVIDERS));420assert(!ctx->hw_sample_providers[idx]);421422ctx->hw_sample_providers[idx] = provider;423}424425void426fd_hw_query_init(struct pipe_context *pctx)427{428struct fd_context *ctx = fd_context(pctx);429430slab_create(&ctx->sample_pool, sizeof(struct fd_hw_sample), 16);431slab_create(&ctx->sample_period_pool, sizeof(struct fd_hw_sample_period),43216);433}434435void436fd_hw_query_fini(struct pipe_context *pctx)437{438struct fd_context *ctx = fd_context(pctx);439440slab_destroy(&ctx->sample_pool);441slab_destroy(&ctx->sample_period_pool);442}443444445