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 v3d_bo_unreference(&pquery->bo); 86 pquery->bo = v3d_bo_alloc(v3d->screen, 4096, "query"); 87 uint32_t *map = v3d_bo_map(pquery->bo); 88 *map = 0; 89 90 v3d->current_oq = pquery->bo; 91 v3d->dirty |= V3D_DIRTY_OQ; 92 break; 93 default: 94 unreachable("unsupported query type"); 95 } 96 97 return true; 98} 99 100static bool 101v3d_end_query_pipe(struct v3d_context *v3d, struct v3d_query *query) 102{ 103 struct v3d_query_pipe *pquery = (struct v3d_query_pipe *)query; 104 105 switch (pquery->type) { 106 case PIPE_QUERY_PRIMITIVES_GENERATED: 107 /* If we are using PRIMITIVE_COUNTS_FEEDBACK to retrieve 108 * primitive counts from the GPU (which we need when a GS 109 * is present), then we need to update our counters now. 110 */ 111 if (v3d->prog.gs) 112 v3d_update_primitive_counters(v3d); 113 pquery->end = v3d->prims_generated; 114 v3d->n_primitives_generated_queries_in_flight--; 115 break; 116 case PIPE_QUERY_PRIMITIVES_EMITTED: 117 /* If transform feedback has ended, then we have already 118 * updated the primitive counts at glEndTransformFeedback() 119 * time. Otherwise, we have to do it now. 120 */ 121 if (v3d->streamout.num_targets > 0) 122 v3d_update_primitive_counters(v3d); 123 pquery->end = v3d->tf_prims_generated; 124 break; 125 case PIPE_QUERY_OCCLUSION_COUNTER: 126 case PIPE_QUERY_OCCLUSION_PREDICATE: 127 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: 128 v3d->current_oq = NULL; 129 v3d->dirty |= V3D_DIRTY_OQ; 130 break; 131 default: 132 unreachable("unsupported query type"); 133 } 134 135 return true; 136} 137 138static bool 139v3d_get_query_result_pipe(struct v3d_context *v3d, struct v3d_query *query, 140 bool wait, union pipe_query_result *vresult) 141{ 142 struct v3d_query_pipe *pquery = (struct v3d_query_pipe *)query; 143 uint32_t result = 0; 144 145 if (pquery->bo) { 146 v3d_flush_jobs_using_bo(v3d, pquery->bo); 147 148 if (wait) { 149 if (!v3d_bo_wait(pquery->bo, ~0ull, "query")) 150 return false; 151 } else { 152 if (!v3d_bo_wait(pquery->bo, 0, "query")) 153 return false; 154 } 155 156 /* XXX: Sum up per-core values. */ 157 uint32_t *map = v3d_bo_map(pquery->bo); 158 result = *map; 159 160 v3d_bo_unreference(&pquery->bo); 161 } 162 163 switch (pquery->type) { 164 case PIPE_QUERY_OCCLUSION_COUNTER: 165 vresult->u64 = result; 166 break; 167 case PIPE_QUERY_OCCLUSION_PREDICATE: 168 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: 169 vresult->b = result != 0; 170 break; 171 case PIPE_QUERY_PRIMITIVES_GENERATED: 172 case PIPE_QUERY_PRIMITIVES_EMITTED: 173 vresult->u64 = pquery->end - pquery->start; 174 break; 175 default: 176 unreachable("unsupported query type"); 177 } 178 179 return true; 180} 181 182static const struct v3d_query_funcs pipe_query_funcs = { 183 .destroy_query = v3d_destroy_query_pipe, 184 .begin_query = v3d_begin_query_pipe, 185 .end_query = v3d_end_query_pipe, 186 .get_query_result = v3d_get_query_result_pipe, 187}; 188 189struct pipe_query * 190v3d_create_query_pipe(struct v3d_context *v3d, unsigned query_type, unsigned index) 191{ 192 if (query_type >= PIPE_QUERY_DRIVER_SPECIFIC) 193 return NULL; 194 195 struct v3d_query_pipe *pquery = calloc(1, sizeof(*pquery)); 196 struct v3d_query *query = &pquery->base; 197 198 pquery->type = query_type; 199 query->funcs = &pipe_query_funcs; 200 201 /* Note that struct pipe_query isn't actually defined anywhere. */ 202 return (struct pipe_query *)query; 203} 204