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_context.h" 37#include "broadcom/cle/v3d_packet_v33_pack.h" 38 39struct v3d_query 40{ 41 enum pipe_query_type type; 42 struct v3d_bo *bo; 43 44 uint32_t start, end; 45}; 46 47static struct pipe_query * 48v3d_create_query(struct pipe_context *pctx, unsigned query_type, unsigned index) 49{ 50 struct v3d_query *q = calloc(1, sizeof(*q)); 51 52 q->type = query_type; 53 54 /* Note that struct pipe_query isn't actually defined anywhere. */ 55 return (struct pipe_query *)q; 56} 57 58static void 59v3d_destroy_query(struct pipe_context *pctx, struct pipe_query *query) 60{ 61 struct v3d_query *q = (struct v3d_query *)query; 62 63 v3d_bo_unreference(&q->bo); 64 free(q); 65} 66 67static boolean 68v3d_begin_query(struct pipe_context *pctx, struct pipe_query *query) 69{ 70 struct v3d_context *v3d = v3d_context(pctx); 71 struct v3d_query *q = (struct v3d_query *)query; 72 73 switch (q->type) { 74 case PIPE_QUERY_PRIMITIVES_GENERATED: 75 q->start = v3d->prims_generated; 76 break; 77 case PIPE_QUERY_PRIMITIVES_EMITTED: 78 q->start = v3d->tf_prims_generated; 79 break; 80 default: 81 q->bo = v3d_bo_alloc(v3d->screen, 4096, "query"); 82 83 uint32_t *map = v3d_bo_map(q->bo); 84 *map = 0; 85 v3d->current_oq = q->bo; 86 v3d->dirty |= VC5_DIRTY_OQ; 87 break; 88 } 89 90 return true; 91} 92 93static bool 94v3d_end_query(struct pipe_context *pctx, struct pipe_query *query) 95{ 96 struct v3d_context *v3d = v3d_context(pctx); 97 struct v3d_query *q = (struct v3d_query *)query; 98 99 switch (q->type) { 100 case PIPE_QUERY_PRIMITIVES_GENERATED: 101 q->end = v3d->prims_generated; 102 break; 103 case PIPE_QUERY_PRIMITIVES_EMITTED: 104 q->end = v3d->tf_prims_generated; 105 break; 106 default: 107 v3d->current_oq = NULL; 108 v3d->dirty |= VC5_DIRTY_OQ; 109 break; 110 } 111 112 return true; 113} 114 115static boolean 116v3d_get_query_result(struct pipe_context *pctx, struct pipe_query *query, 117 boolean wait, union pipe_query_result *vresult) 118{ 119 struct v3d_query *q = (struct v3d_query *)query; 120 uint32_t result = 0; 121 122 if (q->bo) { 123 /* XXX: Only flush the jobs using this BO. */ 124 v3d_flush(pctx); 125 126 if (wait) { 127 if (!v3d_bo_wait(q->bo, 0, "query")) 128 return false; 129 } else { 130 if (!v3d_bo_wait(q->bo, ~0ull, "query")) 131 return false; 132 } 133 134 /* XXX: Sum up per-core values. */ 135 uint32_t *map = v3d_bo_map(q->bo); 136 result = *map; 137 138 v3d_bo_unreference(&q->bo); 139 } 140 141 switch (q->type) { 142 case PIPE_QUERY_OCCLUSION_COUNTER: 143 vresult->u64 = result; 144 break; 145 case PIPE_QUERY_OCCLUSION_PREDICATE: 146 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: 147 vresult->b = result != 0; 148 break; 149 case PIPE_QUERY_PRIMITIVES_GENERATED: 150 case PIPE_QUERY_PRIMITIVES_EMITTED: 151 vresult->u64 = q->end - q->start; 152 break; 153 default: 154 unreachable("unsupported query type"); 155 } 156 157 return true; 158} 159 160static void 161v3d_set_active_query_state(struct pipe_context *pctx, boolean enable) 162{ 163 struct v3d_context *v3d = v3d_context(pctx); 164 165 v3d->active_queries = enable; 166 v3d->dirty |= VC5_DIRTY_OQ; 167 v3d->dirty |= VC5_DIRTY_STREAMOUT; 168} 169 170void 171v3d_query_init(struct pipe_context *pctx) 172{ 173 pctx->create_query = v3d_create_query; 174 pctx->destroy_query = v3d_destroy_query; 175 pctx->begin_query = v3d_begin_query; 176 pctx->end_query = v3d_end_query; 177 pctx->get_query_result = v3d_get_query_result; 178 pctx->set_active_query_state = v3d_set_active_query_state; 179} 180 181