Path: blob/21.2-virgl/src/gallium/drivers/freedreno/freedreno_query_acc.c
4570 views
/*1* Copyright (C) 2017 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 "util/u_inlines.h"27#include "util/u_memory.h"2829#include "freedreno_context.h"30#include "freedreno_query_acc.h"31#include "freedreno_resource.h"32#include "freedreno_util.h"3334static void35fd_acc_destroy_query(struct fd_context *ctx, struct fd_query *q) assert_dt36{37struct fd_acc_query *aq = fd_acc_query(q);3839DBG("%p", q);4041pipe_resource_reference(&aq->prsc, NULL);42list_del(&aq->node);4344free(aq->query_data);45free(aq);46}4748static void49realloc_query_bo(struct fd_context *ctx, struct fd_acc_query *aq)50{51struct fd_resource *rsc;52void *map;5354pipe_resource_reference(&aq->prsc, NULL);5556aq->prsc =57pipe_buffer_create(&ctx->screen->base, PIPE_BIND_QUERY_BUFFER, 0, 0x1000);5859/* don't assume the buffer is zero-initialized: */60rsc = fd_resource(aq->prsc);6162fd_bo_cpu_prep(rsc->bo, ctx->pipe, FD_BO_PREP_WRITE);6364map = fd_bo_map(rsc->bo);65memset(map, 0, aq->size);66fd_bo_cpu_fini(rsc->bo);67}6869static void70fd_acc_query_pause(struct fd_acc_query *aq) assert_dt71{72const struct fd_acc_sample_provider *p = aq->provider;7374if (!aq->batch)75return;7677fd_batch_needs_flush(aq->batch);78p->pause(aq, aq->batch);79aq->batch = NULL;80}8182static void83fd_acc_query_resume(struct fd_acc_query *aq, struct fd_batch *batch) assert_dt84{85const struct fd_acc_sample_provider *p = aq->provider;8687aq->batch = batch;88fd_batch_needs_flush(aq->batch);89p->resume(aq, aq->batch);9091fd_screen_lock(batch->ctx->screen);92fd_batch_resource_write(batch, fd_resource(aq->prsc));93fd_screen_unlock(batch->ctx->screen);94}9596static void97fd_acc_begin_query(struct fd_context *ctx, struct fd_query *q) assert_dt98{99struct fd_acc_query *aq = fd_acc_query(q);100101DBG("%p", q);102103/* ->begin_query() discards previous results, so realloc bo: */104realloc_query_bo(ctx, aq);105106/* Signal that we need to update the active queries on the next draw */107ctx->update_active_queries = true;108109/* add to active list: */110assert(list_is_empty(&aq->node));111list_addtail(&aq->node, &ctx->acc_active_queries);112113/* TIMESTAMP/GPU_FINISHED and don't do normal bracketing at draw time, we114* need to just emit the capture at this moment.115*/116if (skip_begin_query(q->type)) {117struct fd_batch *batch = fd_context_batch_locked(ctx);118fd_acc_query_resume(aq, batch);119fd_batch_unlock_submit(batch);120fd_batch_reference(&batch, NULL);121}122}123124static void125fd_acc_end_query(struct fd_context *ctx, struct fd_query *q) assert_dt126{127struct fd_acc_query *aq = fd_acc_query(q);128129DBG("%p", q);130131fd_acc_query_pause(aq);132133/* remove from active list: */134list_delinit(&aq->node);135}136137static bool138fd_acc_get_query_result(struct fd_context *ctx, struct fd_query *q, bool wait,139union pipe_query_result *result)140{141struct fd_acc_query *aq = fd_acc_query(q);142const struct fd_acc_sample_provider *p = aq->provider;143struct fd_resource *rsc = fd_resource(aq->prsc);144145DBG("%p: wait=%d", q, wait);146147assert(list_is_empty(&aq->node));148149/* ARB_occlusion_query says:150*151* "Querying the state for a given occlusion query forces that152* occlusion query to complete within a finite amount of time."153*154* So, regardless of whether we are supposed to wait or not, we do need to155* flush now.156*/157if (rsc->track->write_batch) {158tc_assert_driver_thread(ctx->tc);159fd_context_access_begin(ctx);160fd_batch_flush(rsc->track->write_batch);161fd_context_access_end(ctx);162}163164if (!wait) {165int ret = fd_resource_wait(166ctx, rsc, FD_BO_PREP_READ | FD_BO_PREP_NOSYNC | FD_BO_PREP_FLUSH);167if (ret)168return false;169} else {170fd_resource_wait(ctx, rsc, FD_BO_PREP_READ);171}172173void *ptr = fd_bo_map(rsc->bo);174p->result(aq, ptr, result);175fd_bo_cpu_fini(rsc->bo);176177return true;178}179180static const struct fd_query_funcs acc_query_funcs = {181.destroy_query = fd_acc_destroy_query,182.begin_query = fd_acc_begin_query,183.end_query = fd_acc_end_query,184.get_query_result = fd_acc_get_query_result,185};186187struct fd_query *188fd_acc_create_query2(struct fd_context *ctx, unsigned query_type,189unsigned index,190const struct fd_acc_sample_provider *provider)191{192struct fd_acc_query *aq;193struct fd_query *q;194195aq = CALLOC_STRUCT(fd_acc_query);196if (!aq)197return NULL;198199DBG("%p: query_type=%u", aq, query_type);200201aq->provider = provider;202aq->size = provider->size;203204list_inithead(&aq->node);205206q = &aq->base;207q->funcs = &acc_query_funcs;208q->type = query_type;209q->index = index;210211return q;212}213214struct fd_query *215fd_acc_create_query(struct fd_context *ctx, unsigned query_type, unsigned index)216{217int idx = pidx(query_type);218219if ((idx < 0) || !ctx->acc_sample_providers[idx])220return NULL;221222return fd_acc_create_query2(ctx, query_type, index,223ctx->acc_sample_providers[idx]);224}225226/* Called at clear/draw/blit time to enable/disable the appropriate queries in227* the batch (and transfer active querying between batches in the case of228* batch reordering).229*/230void231fd_acc_query_update_batch(struct fd_batch *batch, bool disable_all)232{233struct fd_context *ctx = batch->ctx;234235if (disable_all || ctx->update_active_queries) {236struct fd_acc_query *aq;237LIST_FOR_EACH_ENTRY (aq, &ctx->acc_active_queries, node) {238bool batch_change = aq->batch != batch;239bool was_active = aq->batch != NULL;240bool now_active =241!disable_all && (ctx->active_queries || aq->provider->always);242243if (was_active && (!now_active || batch_change))244fd_acc_query_pause(aq);245if (now_active && (!was_active || batch_change))246fd_acc_query_resume(aq, batch);247}248}249250ctx->update_active_queries = false;251}252253void254fd_acc_query_register_provider(struct pipe_context *pctx,255const struct fd_acc_sample_provider *provider)256{257struct fd_context *ctx = fd_context(pctx);258int idx = pidx(provider->query_type);259260assert((0 <= idx) && (idx < MAX_HW_SAMPLE_PROVIDERS));261assert(!ctx->acc_sample_providers[idx]);262263ctx->acc_sample_providers[idx] = provider;264}265266267