1/* 2 * Copyright © 2014 Broadcom 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24/** 25 * Gallium query object support. 26 * 27 * The HW has native support for occlusion queries, with the query result 28 * being loaded and stored by the TLB unit. From a SW perspective, we have to 29 * be careful to make sure that the jobs that need to be tracking queries are 30 * bracketed by the start and end of counting, even across FBO transitions. 31 * 32 * For the transform feedback PRIMITIVES_GENERATED/WRITTEN queries, we have to 33 * do the calculations in software at draw time. 34 */ 35 36#include "v3d_query.h" 37 38struct v3d_query_pipe 39{ 40 struct v3d_query base; 41 42 enum pipe_query_type type; 43 struct v3d_bo *bo; 44 45 uint32_t start, end; 46}; 47 48static void 49v3d_destroy_query_pipe(struct v3d_context *v3d, struct v3d_query *query) 50{ 51 struct v3d_query_pipe *pquery = (struct v3d_query_pipe *)query; 52 53 v3d_bo_unreference(&pquery->bo); 54 free(pquery); 55} 56 57static bool 58v3d_begin_query_pipe(struct v3d_context *v3d, struct v3d_query *query) 59{ 60 struct v3d_query_pipe *pquery = (struct v3d_query_pipe *)query; 61 62 switch (pquery->type) { 63 case PIPE_QUERY_PRIMITIVES_GENERATED: 64 /* If we are using PRIMITIVE_COUNTS_FEEDBACK to retrieve 65 * primitive counts from the GPU (which we need when a GS 66 * is present), then we need to update our counters now 67 * to discard any primitives generated before this. 68 */ 69 if (v3d->prog.gs) 70 v3d_update_primitive_counters(v3d); 71 pquery->start = v3d->prims_generated; 72 v3d->n_primitives_generated_queries_in_flight++; 73 break; 74 case PIPE_QUERY_PRIMITIVES_EMITTED: 75 /* If we are inside transform feedback we need to update the 76 * primitive counts to skip primitives recorded before this. 77 */ 78 if (v3d->streamout.num_targets > 0) 79 v3d_update_primitive_counters(v3d); 80 pquery->start = v3d->tf_prims_generated; 81 break; 82 case PIPE_QUERY_OCCLUSION_COUNTER: 83 case PIPE_QUERY_OCCLUSION_PREDICATE: 84 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: 85 pquery->bo = v3d_bo_alloc(v3d->screen, 4096, "query"); 86 uint32_t *map = v3d_bo_map(pquery->bo); 87 *map = 0; 88 89 v3d->current_oq = pquery->bo; 90 v3d->dirty |= V3D_DIRTY_OQ; 91 break; 92 default: 93 unreachable("unsupported query type"); 94 } 95 96 return true; 97} 98 99static bool 100v3d_end_query_pipe(struct v3d_context *v3d, struct v3d_query *query) 101{ 102 struct v3d_query_pipe *pquery = (struct v3d_query_pipe *)query; 103 104 switch (pquery->type) { 105 case PIPE_QUERY_PRIMITIVES_GENERATED: 106 /* If we are using PRIMITIVE_COUNTS_FEEDBACK to retrieve 107 * primitive counts from the GPU (which we need when a GS 108 * is present), then we need to update our counters now. 109 */ 110 if (v3d->prog.gs) 111 v3d_update_primitive_counters(v3d); 112 pquery->end = v3d->prims_generated; 113 v3d->n_primitives_generated_queries_in_flight--; 114 break; 115 case PIPE_QUERY_PRIMITIVES_EMITTED: 116 /* If transform feedback has ended, then we have already 117 * updated the primitive counts at glEndTransformFeedback() 118 * time. Otherwise, we have to do it now. 119 */ 120 if (v3d->streamout.num_targets > 0) 121 v3d_update_primitive_counters(v3d); 122 pquery->end = v3d->tf_prims_generated; 123 break; 124 case PIPE_QUERY_OCCLUSION_COUNTER: 125 case PIPE_QUERY_OCCLUSION_PREDICATE: 126 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: 127 v3d->current_oq = NULL; 128 v3d->dirty |= V3D_DIRTY_OQ; 129 break; 130 default: 131 unreachable("unsupported query type"); 132 } 133 134 return true; 135} 136 137static bool 138v3d_get_query_result_pipe(struct v3d_context *v3d, struct v3d_query *query, 139 bool wait, union pipe_query_result *vresult) 140{ 141 struct v3d_query_pipe *pquery = (struct v3d_query_pipe *)query; 142 uint32_t result = 0; 143 144 if (pquery->bo) { 145 v3d_flush_jobs_using_bo(v3d, pquery->bo); 146 147 if (wait) { 148 if (!v3d_bo_wait(pquery->bo, ~0ull, "query")) 149 return false; 150 } else { 151 if (!v3d_bo_wait(pquery->bo, 0, "query")) 152 return false; 153 } 154 155 /* XXX: Sum up per-core values. */ 156 uint32_t *map = v3d_bo_map(pquery->bo); 157 result = *map; 158 159 v3d_bo_unreference(&pquery->bo); 160 } 161 162 switch (pquery->type) { 163 case PIPE_QUERY_OCCLUSION_COUNTER: 164 vresult->u64 = result; 165 break; 166 case PIPE_QUERY_OCCLUSION_PREDICATE: 167 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: 168 vresult->b = result != 0; 169 break; 170 case PIPE_QUERY_PRIMITIVES_GENERATED: 171 case PIPE_QUERY_PRIMITIVES_EMITTED: 172 vresult->u64 = pquery->end - pquery->start; 173 break; 174 default: 175 unreachable("unsupported query type"); 176 } 177 178 return true; 179} 180 181static const struct v3d_query_funcs pipe_query_funcs = { 182 .destroy_query = v3d_destroy_query_pipe, 183 .begin_query = v3d_begin_query_pipe, 184 .end_query = v3d_end_query_pipe, 185 .get_query_result = v3d_get_query_result_pipe, 186}; 187 188struct pipe_query * 189v3d_create_query_pipe(struct v3d_context *v3d, unsigned query_type, unsigned index) 190{ 191 if (query_type >= PIPE_QUERY_DRIVER_SPECIFIC) 192 return NULL; 193 194 struct v3d_query_pipe *pquery = calloc(1, sizeof(*pquery)); 195 struct v3d_query *query = &pquery->base; 196 197 pquery->type = query_type; 198 query->funcs = &pipe_query_funcs; 199 200 /* Note that struct pipe_query isn't actually defined anywhere. */ 201 return (struct pipe_query *)query; 202} 203