1/* 2 * Copyright 2014, 2015 Red Hat. 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 * on the rights to use, copy, modify, merge, publish, distribute, sub 8 * license, and/or sell copies of the Software, and to permit persons to whom 9 * the 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 NON-INFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21 * USE OR OTHER DEALINGS IN THE SOFTWARE. 22 */ 23 24#include "util/u_memory.h" 25#include "util/u_inlines.h" 26#include "virgl_context.h" 27#include "virgl_encode.h" 28#include "virgl_protocol.h" 29#include "virgl_resource.h" 30 31struct virgl_query { 32 uint32_t handle; 33 struct virgl_resource *buf; 34 35 unsigned index; 36 unsigned type; 37 unsigned result_size; 38 unsigned result_gotten_sent; 39}; 40#define VIRGL_QUERY_OCCLUSION_COUNTER 0 41#define VIRGL_QUERY_OCCLUSION_PREDICATE 1 42#define VIRGL_QUERY_TIMESTAMP 2 43#define VIRGL_QUERY_TIMESTAMP_DISJOINT 3 44#define VIRGL_QUERY_TIME_ELAPSED 4 45#define VIRGL_QUERY_PRIMITIVES_GENERATED 5 46#define VIRGL_QUERY_PRIMITIVES_EMITTED 6 47#define VIRGL_QUERY_SO_STATISTICS 7 48#define VIRGL_QUERY_SO_OVERFLOW_PREDICATE 8 49#define VIRGL_QUERY_GPU_FINISHED 9 50#define VIRGL_QUERY_PIPELINE_STATISTICS 10 51#define VIRGL_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE 11 52#define VIRGL_QUERY_SO_OVERFLOW_ANY_PREDICATE 12 53 54static const int pquery_map[] = 55{ 56 VIRGL_QUERY_OCCLUSION_COUNTER, 57 VIRGL_QUERY_OCCLUSION_PREDICATE, 58 VIRGL_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE, 59 VIRGL_QUERY_TIMESTAMP, 60 VIRGL_QUERY_TIMESTAMP_DISJOINT, 61 VIRGL_QUERY_TIME_ELAPSED, 62 VIRGL_QUERY_PRIMITIVES_GENERATED, 63 VIRGL_QUERY_PRIMITIVES_EMITTED, 64 VIRGL_QUERY_SO_STATISTICS, 65 VIRGL_QUERY_SO_OVERFLOW_PREDICATE, 66 VIRGL_QUERY_SO_OVERFLOW_ANY_PREDICATE, 67 VIRGL_QUERY_GPU_FINISHED, 68 VIRGL_QUERY_PIPELINE_STATISTICS, 69}; 70 71static int pipe_to_virgl_query(enum pipe_query_type ptype) 72{ 73 return pquery_map[ptype]; 74} 75 76static inline struct virgl_query *virgl_query(struct pipe_query *q) 77{ 78 return (struct virgl_query *)q; 79} 80 81static void virgl_render_condition(struct pipe_context *ctx, 82 struct pipe_query *q, 83 boolean condition, 84 enum pipe_render_cond_flag mode) 85{ 86 struct virgl_context *vctx = virgl_context(ctx); 87 struct virgl_query *query = virgl_query(q); 88 uint32_t handle = 0; 89 if (q) 90 handle = query->handle; 91 virgl_encoder_render_condition(vctx, handle, condition, mode); 92} 93 94static struct pipe_query *virgl_create_query(struct pipe_context *ctx, 95 unsigned query_type, unsigned index) 96{ 97 struct virgl_context *vctx = virgl_context(ctx); 98 struct virgl_query *query; 99 uint32_t handle; 100 101 query = CALLOC_STRUCT(virgl_query); 102 if (!query) 103 return NULL; 104 105 query->buf = (struct virgl_resource *)pipe_buffer_create(ctx->screen, PIPE_BIND_CUSTOM, 106 PIPE_USAGE_STAGING, sizeof(struct virgl_host_query_state)); 107 if (!query->buf) { 108 FREE(query); 109 return NULL; 110 } 111 112 handle = virgl_object_assign_handle(); 113 query->type = pipe_to_virgl_query(query_type); 114 query->index = index; 115 query->handle = handle; 116 query->buf->clean_mask &= ~1; 117 virgl_encoder_create_query(vctx, handle, query->type, index, query->buf, 0); 118 119 return (struct pipe_query *)query; 120} 121 122static void virgl_destroy_query(struct pipe_context *ctx, 123 struct pipe_query *q) 124{ 125 struct virgl_context *vctx = virgl_context(ctx); 126 struct virgl_query *query = virgl_query(q); 127 128 virgl_encode_delete_object(vctx, query->handle, VIRGL_OBJECT_QUERY); 129 130 pipe_resource_reference((struct pipe_resource **)&query->buf, NULL); 131 FREE(query); 132} 133 134static boolean virgl_begin_query(struct pipe_context *ctx, 135 struct pipe_query *q) 136{ 137 struct virgl_context *vctx = virgl_context(ctx); 138 struct virgl_query *query = virgl_query(q); 139 140 virgl_resource_dirty(query->buf, 0); 141 virgl_encoder_begin_query(vctx, query->handle); 142 return true; 143} 144 145static bool virgl_end_query(struct pipe_context *ctx, 146 struct pipe_query *q) 147{ 148 struct virgl_context *vctx = virgl_context(ctx); 149 struct virgl_query *query = virgl_query(q); 150 struct pipe_box box; 151 152 uint32_t qs = VIRGL_QUERY_STATE_WAIT_HOST; 153 u_box_1d(0, 4, &box); 154 virgl_transfer_inline_write(ctx, &query->buf->u.b, 0, PIPE_TRANSFER_WRITE, 155 &box, &qs, 0, 0); 156 157 158 virgl_encoder_end_query(vctx, query->handle); 159 return true; 160} 161 162static boolean virgl_get_query_result(struct pipe_context *ctx, 163 struct pipe_query *q, 164 boolean wait, 165 union pipe_query_result *result) 166{ 167 struct virgl_context *vctx = virgl_context(ctx); 168 struct virgl_query *query = virgl_query(q); 169 struct pipe_transfer *transfer; 170 struct virgl_host_query_state *host_state; 171 172 /* ask host for query result */ 173 if (!query->result_gotten_sent) { 174 query->result_gotten_sent = 1; 175 virgl_encoder_get_query_result(vctx, query->handle, 0); 176 ctx->flush(ctx, NULL, 0); 177 } 178 179 /* do we have to flush? */ 180 /* now we can do the transfer to get the result back? */ 181 remap: 182 host_state = pipe_buffer_map(ctx, &query->buf->u.b, 183 PIPE_TRANSFER_READ, &transfer); 184 185 if (host_state->query_state != VIRGL_QUERY_STATE_DONE) { 186 pipe_buffer_unmap(ctx, transfer); 187 if (wait) 188 goto remap; 189 else 190 return FALSE; 191 } 192 193 if (query->type == PIPE_QUERY_TIMESTAMP || query->type == PIPE_QUERY_TIME_ELAPSED) 194 result->u64 = host_state->result; 195 else 196 result->u64 = (uint32_t)host_state->result; 197 198 pipe_buffer_unmap(ctx, transfer); 199 query->result_gotten_sent = 0; 200 return TRUE; 201} 202 203static void 204virgl_set_active_query_state(struct pipe_context *pipe, boolean enable) 205{ 206} 207 208static void 209virgl_get_query_result_resource(struct pipe_context *ctx, 210 struct pipe_query *q, 211 boolean wait, 212 enum pipe_query_value_type result_type, 213 int index, 214 struct pipe_resource *resource, 215 unsigned offset) 216{ 217 struct virgl_context *vctx = virgl_context(ctx); 218 struct virgl_query *query = virgl_query(q); 219 struct virgl_resource *qbo = (struct virgl_resource *)resource; 220 221 virgl_encode_get_query_result_qbo(vctx, query->handle, qbo, wait, result_type, offset, index); 222} 223 224void virgl_init_query_functions(struct virgl_context *vctx) 225{ 226 vctx->base.render_condition = virgl_render_condition; 227 vctx->base.create_query = virgl_create_query; 228 vctx->base.destroy_query = virgl_destroy_query; 229 vctx->base.begin_query = virgl_begin_query; 230 vctx->base.end_query = virgl_end_query; 231 vctx->base.get_query_result = virgl_get_query_result; 232 vctx->base.set_active_query_state = virgl_set_active_query_state; 233 vctx->base.get_query_result_resource = virgl_get_query_result_resource; 234} 235