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