1/* 2 * Copyright (c) 2017 Etnaviv Project 3 * Copyright (C) 2017 Zodiac Inflight Innovations 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sub license, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the 13 * next paragraph) shall be included in all copies or substantial portions 14 * of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * DEALINGS IN THE SOFTWARE. 23 * 24 * Authors: 25 * Rob Clark <robclark@freedesktop.org> 26 * Christian Gmeiner <christian.gmeiner@gmail.com> 27 */ 28 29#include "util/u_inlines.h" 30#include "util/u_memory.h" 31 32#include "etnaviv_context.h" 33#include "etnaviv_debug.h" 34#include "etnaviv_emit.h" 35#include "etnaviv_query_acc.h" 36#include "etnaviv_screen.h" 37 38 39extern const struct etna_acc_sample_provider occlusion_provider; 40extern const struct etna_acc_sample_provider perfmon_provider; 41 42static const struct etna_acc_sample_provider *acc_sample_provider[] = 43{ 44 &occlusion_provider, 45 &perfmon_provider, 46}; 47 48static void 49etna_acc_destroy_query(struct etna_context *ctx, struct etna_query *q) 50{ 51 struct etna_acc_query *aq = etna_acc_query(q); 52 53 pipe_resource_reference(&aq->prsc, NULL); 54 list_del(&aq->node); 55 56 FREE(aq); 57} 58 59static void 60realloc_query_bo(struct etna_context *ctx, struct etna_acc_query *aq) 61{ 62 struct etna_resource *rsc; 63 void *map; 64 65 pipe_resource_reference(&aq->prsc, NULL); 66 67 /* allocate resource with space for 64 * 64bit values */ 68 aq->prsc = pipe_buffer_create(&ctx->screen->base, PIPE_BIND_QUERY_BUFFER, 69 0, 0x1000); 70 71 /* don't assume the buffer is zero-initialized */ 72 rsc = etna_resource(aq->prsc); 73 74 etna_bo_cpu_prep(rsc->bo, DRM_ETNA_PREP_WRITE); 75 76 map = etna_bo_map(rsc->bo); 77 memset(map, 0, 0x1000); 78 etna_bo_cpu_fini(rsc->bo); 79} 80 81static void 82etna_acc_begin_query(struct etna_context *ctx, struct etna_query *q) 83{ 84 struct etna_acc_query *aq = etna_acc_query(q); 85 const struct etna_acc_sample_provider *p = aq->provider; 86 87 /* ->begin_query() discards previous results, so realloc bo */ 88 realloc_query_bo(ctx, aq); 89 90 p->resume(aq, ctx); 91 aq->samples++; 92 93 /* add to active list */ 94 assert(list_is_empty(&aq->node)); 95 list_addtail(&aq->node, &ctx->active_acc_queries); 96} 97 98static void 99etna_acc_end_query(struct etna_context *ctx, struct etna_query *q) 100{ 101 struct etna_acc_query *aq = etna_acc_query(q); 102 const struct etna_acc_sample_provider *p = aq->provider; 103 104 p->suspend(aq, ctx); 105 aq->samples++; 106 107 /* remove from active list */ 108 list_delinit(&aq->node); 109} 110 111static bool 112etna_acc_get_query_result(struct etna_context *ctx, struct etna_query *q, 113 bool wait, union pipe_query_result *result) 114{ 115 struct etna_acc_query *aq = etna_acc_query(q); 116 struct etna_resource *rsc = etna_resource(aq->prsc); 117 const struct etna_acc_sample_provider *p = aq->provider; 118 119 assert(list_is_empty(&aq->node)); 120 121 if (rsc->status & ETNA_PENDING_WRITE) { 122 if (!wait) { 123 /* piglit spec@arb_occlusion_query@occlusion_query_conform 124 * test, and silly apps perhaps, get stuck in a loop trying 125 * to get query result forever with wait==false.. we don't 126 * wait to flush unnecessarily but we also don't want to 127 * spin forever. 128 */ 129 if (aq->no_wait_cnt++ > 5) { 130 ctx->base.flush(&ctx->base, NULL, 0); 131 aq->no_wait_cnt = 0; 132 } 133 134 return false; 135 } else { 136 /* flush that GPU executes all query related actions */ 137 ctx->base.flush(&ctx->base, NULL, 0); 138 } 139 } 140 141 /* get the result */ 142 int ret = etna_bo_cpu_prep(rsc->bo, DRM_ETNA_PREP_READ); 143 if (ret) 144 return false; 145 146 void *ptr = etna_bo_map(rsc->bo); 147 bool success = p->result(aq, ptr, result); 148 149 if (success) 150 aq->samples = 0; 151 152 etna_bo_cpu_fini(rsc->bo); 153 154 return success; 155} 156 157static const struct etna_query_funcs acc_query_funcs = { 158 .destroy_query = etna_acc_destroy_query, 159 .begin_query = etna_acc_begin_query, 160 .end_query = etna_acc_end_query, 161 .get_query_result = etna_acc_get_query_result, 162}; 163 164struct etna_query * 165etna_acc_create_query(struct etna_context *ctx, unsigned query_type) 166{ 167 const struct etna_acc_sample_provider *p = NULL; 168 struct etna_acc_query *aq; 169 struct etna_query *q; 170 171 /* find a sample provide for the requested query type */ 172 for (unsigned i = 0; i < ARRAY_SIZE(acc_sample_provider); i++) { 173 p = acc_sample_provider[i]; 174 175 if (p->supports(query_type)) 176 break; 177 else 178 p = NULL; 179 } 180 181 if (!p) 182 return NULL; 183 184 aq = p->allocate(ctx, query_type); 185 if (!aq) 186 return NULL; 187 188 aq->provider = p; 189 190 list_inithead(&aq->node); 191 192 q = &aq->base; 193 q->funcs = &acc_query_funcs; 194 q->type = query_type; 195 196 return q; 197} 198