Path: blob/21.2-virgl/src/gallium/drivers/llvmpipe/lp_query.c
4570 views
/**************************************************************************1*2* Copyright 2007 VMware, Inc.3* Copyright 2010 VMware, Inc.4* All Rights Reserved.5*6* Permission is hereby granted, free of charge, to any person obtaining a7* copy of this software and associated documentation files (the8* "Software"), to deal in the Software without restriction, including9* without limitation the rights to use, copy, modify, merge, publish,10* distribute, sub license, and/or sell copies of the Software, and to11* permit persons to whom the Software is furnished to do so, subject to12* the following conditions:13*14* The above copyright notice and this permission notice (including the15* next paragraph) shall be included in all copies or substantial portions16* of the Software.17*18* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS19* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF20* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.21* IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR22* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,23* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE24* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.25*26**************************************************************************/2728/* Authors:29* Keith Whitwell, Qicheng Christopher Li, Brian Paul30*/3132#include "draw/draw_context.h"33#include "pipe/p_defines.h"34#include "util/u_memory.h"35#include "util/os_time.h"36#include "lp_context.h"37#include "lp_flush.h"38#include "lp_fence.h"39#include "lp_query.h"40#include "lp_screen.h"41#include "lp_state.h"42#include "lp_rast.h"434445static struct llvmpipe_query *llvmpipe_query( struct pipe_query *p )46{47return (struct llvmpipe_query *)p;48}4950static struct pipe_query *51llvmpipe_create_query(struct pipe_context *pipe,52unsigned type,53unsigned index)54{55struct llvmpipe_query *pq;5657assert(type < PIPE_QUERY_TYPES);5859pq = CALLOC_STRUCT( llvmpipe_query );6061if (pq) {62pq->type = type;63pq->index = index;64}6566return (struct pipe_query *) pq;67}686970static void71llvmpipe_destroy_query(struct pipe_context *pipe, struct pipe_query *q)72{73struct llvmpipe_query *pq = llvmpipe_query(q);7475/* Ideally we would refcount queries & not get destroyed until the76* last scene had finished with us.77*/78if (pq->fence) {79if (!lp_fence_issued(pq->fence))80llvmpipe_flush(pipe, NULL, __FUNCTION__);8182if (!lp_fence_signalled(pq->fence))83lp_fence_wait(pq->fence);8485lp_fence_reference(&pq->fence, NULL);86}8788FREE(pq);89}909192static bool93llvmpipe_get_query_result(struct pipe_context *pipe,94struct pipe_query *q,95bool wait,96union pipe_query_result *vresult)97{98struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen);99unsigned num_threads = MAX2(1, screen->num_threads);100struct llvmpipe_query *pq = llvmpipe_query(q);101uint64_t *result = (uint64_t *)vresult;102int i;103104if (pq->fence) {105/* only have a fence if there was a scene */106if (!lp_fence_signalled(pq->fence)) {107if (!lp_fence_issued(pq->fence))108llvmpipe_flush(pipe, NULL, __FUNCTION__);109110if (!wait)111return false;112113lp_fence_wait(pq->fence);114}115}116117/* Sum the results from each of the threads:118*/119*result = 0;120121switch (pq->type) {122case PIPE_QUERY_OCCLUSION_COUNTER:123for (i = 0; i < num_threads; i++) {124*result += pq->end[i];125}126break;127case PIPE_QUERY_OCCLUSION_PREDICATE:128case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:129for (i = 0; i < num_threads; i++) {130/* safer (still not guaranteed) when there's an overflow */131vresult->b = vresult->b || pq->end[i];132}133break;134case PIPE_QUERY_TIMESTAMP:135for (i = 0; i < num_threads; i++) {136if (pq->end[i] > *result) {137*result = pq->end[i];138}139}140break;141case PIPE_QUERY_TIME_ELAPSED: {142uint64_t start = (uint64_t)-1, end = 0;143for (i = 0; i < num_threads; i++) {144if (pq->start[i] && pq->start[i] < start)145start = pq->start[i];146if (pq->end[i] && pq->end[i] > end)147end = pq->end[i];148}149*result = end - start;150break;151}152case PIPE_QUERY_TIMESTAMP_DISJOINT: {153struct pipe_query_data_timestamp_disjoint *td =154(struct pipe_query_data_timestamp_disjoint *)vresult;155/* os_get_time_nano return nanoseconds */156td->frequency = UINT64_C(1000000000);157td->disjoint = false;158}159break;160case PIPE_QUERY_GPU_FINISHED:161vresult->b = true;162break;163case PIPE_QUERY_PRIMITIVES_GENERATED:164*result = pq->num_primitives_generated[0];165break;166case PIPE_QUERY_PRIMITIVES_EMITTED:167*result = pq->num_primitives_written[0];168break;169case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:170vresult->b = false;171for (unsigned s = 0; s < PIPE_MAX_VERTEX_STREAMS; s++)172vresult->b |= pq->num_primitives_generated[s] > pq->num_primitives_written[s];173break;174case PIPE_QUERY_SO_OVERFLOW_PREDICATE:175vresult->b = pq->num_primitives_generated[0] > pq->num_primitives_written[0];176break;177case PIPE_QUERY_SO_STATISTICS: {178struct pipe_query_data_so_statistics *stats =179(struct pipe_query_data_so_statistics *)vresult;180stats->num_primitives_written = pq->num_primitives_written[0];181stats->primitives_storage_needed = pq->num_primitives_generated[0];182}183break;184case PIPE_QUERY_PIPELINE_STATISTICS: {185struct pipe_query_data_pipeline_statistics *stats =186(struct pipe_query_data_pipeline_statistics *)vresult;187/* only ps_invocations come from binned query */188for (i = 0; i < num_threads; i++) {189pq->stats.ps_invocations += pq->end[i];190}191pq->stats.ps_invocations *= LP_RASTER_BLOCK_SIZE * LP_RASTER_BLOCK_SIZE;192*stats = pq->stats;193}194break;195default:196assert(0);197break;198}199200return true;201}202203static void204llvmpipe_get_query_result_resource(struct pipe_context *pipe,205struct pipe_query *q,206bool wait,207enum pipe_query_value_type result_type,208int index,209struct pipe_resource *resource,210unsigned offset)211{212struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen);213unsigned num_threads = MAX2(1, screen->num_threads);214struct llvmpipe_query *pq = llvmpipe_query(q);215struct llvmpipe_resource *lpr = llvmpipe_resource(resource);216bool unflushed = false;217bool unsignalled = false;218if (pq->fence) {219/* only have a fence if there was a scene */220if (!lp_fence_signalled(pq->fence)) {221unsignalled = true;222if (!lp_fence_issued(pq->fence))223unflushed = true;224}225}226227228uint64_t value = 0, value2 = 0;229unsigned num_values = 1;230if (index == -1)231if (unsignalled)232value = 0;233else234value = 1;235else {236unsigned i;237238if (unflushed) {239llvmpipe_flush(pipe, NULL, __FUNCTION__);240241if (!wait)242return;243244lp_fence_wait(pq->fence);245}246247switch (pq->type) {248case PIPE_QUERY_OCCLUSION_COUNTER:249for (i = 0; i < num_threads; i++) {250value += pq->end[i];251}252break;253case PIPE_QUERY_OCCLUSION_PREDICATE:254case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:255for (i = 0; i < num_threads; i++) {256/* safer (still not guaranteed) when there's an overflow */257value = value || pq->end[i];258}259break;260case PIPE_QUERY_PRIMITIVES_GENERATED:261value = pq->num_primitives_generated[0];262break;263case PIPE_QUERY_PRIMITIVES_EMITTED:264value = pq->num_primitives_written[0];265break;266case PIPE_QUERY_TIMESTAMP:267for (i = 0; i < num_threads; i++) {268if (pq->end[i] > value) {269value = pq->end[i];270}271}272break;273case PIPE_QUERY_TIME_ELAPSED: {274uint64_t start = (uint64_t)-1, end = 0;275for (i = 0; i < num_threads; i++) {276if (pq->start[i] && pq->start[i] < start)277start = pq->start[i];278if (pq->end[i] && pq->end[i] > end)279end = pq->end[i];280}281value = end - start;282break;283}284case PIPE_QUERY_SO_STATISTICS:285value = pq->num_primitives_written[0];286value2 = pq->num_primitives_generated[0];287num_values = 2;288break;289case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:290value = 0;291for (unsigned s = 0; s < PIPE_MAX_VERTEX_STREAMS; s++)292value |= !!(pq->num_primitives_generated[s] > pq->num_primitives_written[s]);293break;294case PIPE_QUERY_SO_OVERFLOW_PREDICATE:295value = !!(pq->num_primitives_generated[0] > pq->num_primitives_written[0]);296break;297case PIPE_QUERY_PIPELINE_STATISTICS:298switch ((enum pipe_statistics_query_index)index) {299case PIPE_STAT_QUERY_IA_VERTICES:300value = pq->stats.ia_vertices;301break;302case PIPE_STAT_QUERY_IA_PRIMITIVES:303value = pq->stats.ia_primitives;304break;305case PIPE_STAT_QUERY_VS_INVOCATIONS:306value = pq->stats.vs_invocations;307break;308case PIPE_STAT_QUERY_GS_INVOCATIONS:309value = pq->stats.gs_invocations;310break;311case PIPE_STAT_QUERY_GS_PRIMITIVES:312value = pq->stats.gs_primitives;313break;314case PIPE_STAT_QUERY_C_INVOCATIONS:315value = pq->stats.c_invocations;316break;317case PIPE_STAT_QUERY_C_PRIMITIVES:318value = pq->stats.c_primitives;319break;320case PIPE_STAT_QUERY_PS_INVOCATIONS:321value = 0;322for (i = 0; i < num_threads; i++) {323value += pq->end[i];324}325value *= LP_RASTER_BLOCK_SIZE * LP_RASTER_BLOCK_SIZE;326break;327case PIPE_STAT_QUERY_HS_INVOCATIONS:328value = pq->stats.hs_invocations;329break;330case PIPE_STAT_QUERY_DS_INVOCATIONS:331value = pq->stats.ds_invocations;332break;333case PIPE_STAT_QUERY_CS_INVOCATIONS:334value = pq->stats.cs_invocations;335break;336}337break;338default:339fprintf(stderr, "Unknown query type %d\n", pq->type);340break;341}342}343344void *dst = (uint8_t *)lpr->data + offset;345346for (unsigned i = 0; i < num_values; i++) {347348if (i == 1) {349value = value2;350dst = (char *)dst + ((result_type == PIPE_QUERY_TYPE_I64 ||351result_type == PIPE_QUERY_TYPE_U64) ? 8 : 4);352}353switch (result_type) {354case PIPE_QUERY_TYPE_I32: {355int32_t *iptr = (int32_t *)dst;356if (value > 0x7fffffff)357*iptr = 0x7fffffff;358else359*iptr = (int32_t)value;360break;361}362case PIPE_QUERY_TYPE_U32: {363uint32_t *uptr = (uint32_t *)dst;364if (value > 0xffffffff)365*uptr = 0xffffffff;366else367*uptr = (uint32_t)value;368break;369}370case PIPE_QUERY_TYPE_I64: {371int64_t *iptr = (int64_t *)dst;372*iptr = (int64_t)value;373break;374}375case PIPE_QUERY_TYPE_U64: {376uint64_t *uptr = (uint64_t *)dst;377*uptr = (uint64_t)value;378break;379}380}381}382}383384static bool385llvmpipe_begin_query(struct pipe_context *pipe, struct pipe_query *q)386{387struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );388struct llvmpipe_query *pq = llvmpipe_query(q);389390/* Check if the query is already in the scene. If so, we need to391* flush the scene now. Real apps shouldn't re-use a query in a392* frame of rendering.393*/394if (pq->fence && !lp_fence_issued(pq->fence)) {395llvmpipe_finish(pipe, __FUNCTION__);396}397398399memset(pq->start, 0, sizeof(pq->start));400memset(pq->end, 0, sizeof(pq->end));401lp_setup_begin_query(llvmpipe->setup, pq);402403switch (pq->type) {404case PIPE_QUERY_PRIMITIVES_EMITTED:405pq->num_primitives_written[0] = llvmpipe->so_stats[pq->index].num_primitives_written;406break;407case PIPE_QUERY_PRIMITIVES_GENERATED:408pq->num_primitives_generated[0] = llvmpipe->so_stats[pq->index].primitives_storage_needed;409llvmpipe->active_primgen_queries++;410break;411case PIPE_QUERY_SO_STATISTICS:412pq->num_primitives_written[0] = llvmpipe->so_stats[pq->index].num_primitives_written;413pq->num_primitives_generated[0] = llvmpipe->so_stats[pq->index].primitives_storage_needed;414break;415case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:416for (unsigned s = 0; s < PIPE_MAX_VERTEX_STREAMS; s++) {417pq->num_primitives_written[s] = llvmpipe->so_stats[s].num_primitives_written;418pq->num_primitives_generated[s] = llvmpipe->so_stats[s].primitives_storage_needed;419}420break;421case PIPE_QUERY_SO_OVERFLOW_PREDICATE:422pq->num_primitives_written[0] = llvmpipe->so_stats[pq->index].num_primitives_written;423pq->num_primitives_generated[0] = llvmpipe->so_stats[pq->index].primitives_storage_needed;424break;425case PIPE_QUERY_PIPELINE_STATISTICS:426/* reset our cache */427if (llvmpipe->active_statistics_queries == 0) {428memset(&llvmpipe->pipeline_statistics, 0,429sizeof(llvmpipe->pipeline_statistics));430}431memcpy(&pq->stats, &llvmpipe->pipeline_statistics, sizeof(pq->stats));432llvmpipe->active_statistics_queries++;433break;434case PIPE_QUERY_OCCLUSION_COUNTER:435case PIPE_QUERY_OCCLUSION_PREDICATE:436case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:437llvmpipe->active_occlusion_queries++;438llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY;439break;440default:441break;442}443return true;444}445446447static bool448llvmpipe_end_query(struct pipe_context *pipe, struct pipe_query *q)449{450struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );451struct llvmpipe_query *pq = llvmpipe_query(q);452453lp_setup_end_query(llvmpipe->setup, pq);454455switch (pq->type) {456457case PIPE_QUERY_PRIMITIVES_EMITTED:458pq->num_primitives_written[0] =459llvmpipe->so_stats[pq->index].num_primitives_written - pq->num_primitives_written[0];460break;461case PIPE_QUERY_PRIMITIVES_GENERATED:462assert(llvmpipe->active_primgen_queries);463llvmpipe->active_primgen_queries--;464pq->num_primitives_generated[0] =465llvmpipe->so_stats[pq->index].primitives_storage_needed - pq->num_primitives_generated[0];466break;467case PIPE_QUERY_SO_STATISTICS:468pq->num_primitives_written[0] =469llvmpipe->so_stats[pq->index].num_primitives_written - pq->num_primitives_written[0];470pq->num_primitives_generated[0] =471llvmpipe->so_stats[pq->index].primitives_storage_needed - pq->num_primitives_generated[0];472break;473case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:474for (unsigned s = 0; s < PIPE_MAX_VERTEX_STREAMS; s++) {475pq->num_primitives_written[s] =476llvmpipe->so_stats[s].num_primitives_written - pq->num_primitives_written[s];477pq->num_primitives_generated[s] =478llvmpipe->so_stats[s].primitives_storage_needed - pq->num_primitives_generated[s];479}480break;481case PIPE_QUERY_SO_OVERFLOW_PREDICATE:482pq->num_primitives_written[0] =483llvmpipe->so_stats[pq->index].num_primitives_written - pq->num_primitives_written[0];484pq->num_primitives_generated[0] =485llvmpipe->so_stats[pq->index].primitives_storage_needed - pq->num_primitives_generated[0];486break;487case PIPE_QUERY_PIPELINE_STATISTICS:488pq->stats.ia_vertices =489llvmpipe->pipeline_statistics.ia_vertices - pq->stats.ia_vertices;490pq->stats.ia_primitives =491llvmpipe->pipeline_statistics.ia_primitives - pq->stats.ia_primitives;492pq->stats.vs_invocations =493llvmpipe->pipeline_statistics.vs_invocations - pq->stats.vs_invocations;494pq->stats.gs_invocations =495llvmpipe->pipeline_statistics.gs_invocations - pq->stats.gs_invocations;496pq->stats.gs_primitives =497llvmpipe->pipeline_statistics.gs_primitives - pq->stats.gs_primitives;498pq->stats.c_invocations =499llvmpipe->pipeline_statistics.c_invocations - pq->stats.c_invocations;500pq->stats.c_primitives =501llvmpipe->pipeline_statistics.c_primitives - pq->stats.c_primitives;502pq->stats.ps_invocations =503llvmpipe->pipeline_statistics.ps_invocations - pq->stats.ps_invocations;504pq->stats.cs_invocations =505llvmpipe->pipeline_statistics.cs_invocations - pq->stats.cs_invocations;506pq->stats.hs_invocations =507llvmpipe->pipeline_statistics.hs_invocations - pq->stats.hs_invocations;508pq->stats.ds_invocations =509llvmpipe->pipeline_statistics.ds_invocations - pq->stats.ds_invocations;510llvmpipe->active_statistics_queries--;511break;512case PIPE_QUERY_OCCLUSION_COUNTER:513case PIPE_QUERY_OCCLUSION_PREDICATE:514case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:515assert(llvmpipe->active_occlusion_queries);516llvmpipe->active_occlusion_queries--;517llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY;518break;519default:520break;521}522523return true;524}525526boolean527llvmpipe_check_render_cond(struct llvmpipe_context *lp)528{529struct pipe_context *pipe = &lp->pipe;530boolean b, wait;531uint64_t result;532533if (lp->render_cond_buffer) {534uint32_t data = *(uint32_t *)((char *)lp->render_cond_buffer->data + lp->render_cond_offset);535return (!data) == lp->render_cond_cond;536}537if (!lp->render_cond_query)538return TRUE; /* no query predicate, draw normally */539540wait = (lp->render_cond_mode == PIPE_RENDER_COND_WAIT ||541lp->render_cond_mode == PIPE_RENDER_COND_BY_REGION_WAIT);542543b = pipe->get_query_result(pipe, lp->render_cond_query, wait, (void*)&result);544if (b)545return ((!result) == lp->render_cond_cond);546else547return TRUE;548}549550static void551llvmpipe_set_active_query_state(struct pipe_context *pipe, bool enable)552{553struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);554555llvmpipe->queries_disabled = !enable;556/* for OQs we need to regenerate the fragment shader */557llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY;558}559560void llvmpipe_init_query_funcs(struct llvmpipe_context *llvmpipe )561{562llvmpipe->pipe.create_query = llvmpipe_create_query;563llvmpipe->pipe.destroy_query = llvmpipe_destroy_query;564llvmpipe->pipe.begin_query = llvmpipe_begin_query;565llvmpipe->pipe.end_query = llvmpipe_end_query;566llvmpipe->pipe.get_query_result = llvmpipe_get_query_result;567llvmpipe->pipe.get_query_result_resource = llvmpipe_get_query_result_resource;568llvmpipe->pipe.set_active_query_state = llvmpipe_set_active_query_state;569}570571572573574