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