2 * Copyright 2014, 2015 Red Hat.
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:
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
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.
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 #include "virgl_screen.h"
33 struct virgl_resource
*buf
;
41 #define VIRGL_QUERY_OCCLUSION_COUNTER 0
42 #define VIRGL_QUERY_OCCLUSION_PREDICATE 1
43 #define VIRGL_QUERY_TIMESTAMP 2
44 #define VIRGL_QUERY_TIMESTAMP_DISJOINT 3
45 #define VIRGL_QUERY_TIME_ELAPSED 4
46 #define VIRGL_QUERY_PRIMITIVES_GENERATED 5
47 #define VIRGL_QUERY_PRIMITIVES_EMITTED 6
48 #define VIRGL_QUERY_SO_STATISTICS 7
49 #define VIRGL_QUERY_SO_OVERFLOW_PREDICATE 8
50 #define VIRGL_QUERY_GPU_FINISHED 9
51 #define VIRGL_QUERY_PIPELINE_STATISTICS 10
52 #define VIRGL_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE 11
53 #define VIRGL_QUERY_SO_OVERFLOW_ANY_PREDICATE 12
55 static const int pquery_map
[] =
57 VIRGL_QUERY_OCCLUSION_COUNTER
,
58 VIRGL_QUERY_OCCLUSION_PREDICATE
,
59 VIRGL_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE
,
60 VIRGL_QUERY_TIMESTAMP
,
61 VIRGL_QUERY_TIMESTAMP_DISJOINT
,
62 VIRGL_QUERY_TIME_ELAPSED
,
63 VIRGL_QUERY_PRIMITIVES_GENERATED
,
64 VIRGL_QUERY_PRIMITIVES_EMITTED
,
65 VIRGL_QUERY_SO_STATISTICS
,
66 VIRGL_QUERY_SO_OVERFLOW_PREDICATE
,
67 VIRGL_QUERY_SO_OVERFLOW_ANY_PREDICATE
,
68 VIRGL_QUERY_GPU_FINISHED
,
69 VIRGL_QUERY_PIPELINE_STATISTICS
,
72 static int pipe_to_virgl_query(enum pipe_query_type ptype
)
74 return pquery_map
[ptype
];
77 static inline struct virgl_query
*virgl_query(struct pipe_query
*q
)
79 return (struct virgl_query
*)q
;
82 static void virgl_render_condition(struct pipe_context
*ctx
,
85 enum pipe_render_cond_flag mode
)
87 struct virgl_context
*vctx
= virgl_context(ctx
);
88 struct virgl_query
*query
= virgl_query(q
);
91 handle
= query
->handle
;
92 virgl_encoder_render_condition(vctx
, handle
, condition
, mode
);
95 static struct pipe_query
*virgl_create_query(struct pipe_context
*ctx
,
96 unsigned query_type
, unsigned index
)
98 struct virgl_context
*vctx
= virgl_context(ctx
);
99 struct virgl_query
*query
;
101 query
= CALLOC_STRUCT(virgl_query
);
105 query
->buf
= (struct virgl_resource
*)
106 pipe_buffer_create(ctx
->screen
, PIPE_BIND_CUSTOM
, PIPE_USAGE_STAGING
,
107 sizeof(struct virgl_host_query_state
));
113 query
->handle
= virgl_object_assign_handle();
114 query
->result_size
= (query_type
== PIPE_QUERY_TIMESTAMP
||
115 query_type
== PIPE_QUERY_TIME_ELAPSED
) ? 8 : 4;
117 util_range_add(&query
->buf
->u
.b
, &query
->buf
->valid_buffer_range
, 0,
118 sizeof(struct virgl_host_query_state
));
119 virgl_resource_dirty(query
->buf
, 0);
121 virgl_encoder_create_query(vctx
, query
->handle
,
122 pipe_to_virgl_query(query_type
), index
, query
->buf
, 0);
124 return (struct pipe_query
*)query
;
127 static void virgl_destroy_query(struct pipe_context
*ctx
,
128 struct pipe_query
*q
)
130 struct virgl_context
*vctx
= virgl_context(ctx
);
131 struct virgl_query
*query
= virgl_query(q
);
133 virgl_encode_delete_object(vctx
, query
->handle
, VIRGL_OBJECT_QUERY
);
135 pipe_resource_reference((struct pipe_resource
**)&query
->buf
, NULL
);
139 static bool virgl_begin_query(struct pipe_context
*ctx
,
140 struct pipe_query
*q
)
142 struct virgl_context
*vctx
= virgl_context(ctx
);
143 struct virgl_query
*query
= virgl_query(q
);
145 virgl_encoder_begin_query(vctx
, query
->handle
);
150 static bool virgl_end_query(struct pipe_context
*ctx
,
151 struct pipe_query
*q
)
153 struct virgl_screen
*vs
= virgl_screen(ctx
->screen
);
154 struct virgl_context
*vctx
= virgl_context(ctx
);
155 struct virgl_query
*query
= virgl_query(q
);
156 struct virgl_host_query_state
*host_state
;
158 host_state
= vs
->vws
->resource_map(vs
->vws
, query
->buf
->hw_res
);
162 host_state
->query_state
= VIRGL_QUERY_STATE_WAIT_HOST
;
163 query
->ready
= false;
165 virgl_encoder_end_query(vctx
, query
->handle
);
167 /* start polling now */
168 virgl_encoder_get_query_result(vctx
, query
->handle
, 0);
169 vs
->vws
->emit_res(vs
->vws
, vctx
->cbuf
, query
->buf
->hw_res
, false);
174 static bool virgl_get_query_result(struct pipe_context
*ctx
,
175 struct pipe_query
*q
,
177 union pipe_query_result
*result
)
179 struct virgl_query
*query
= virgl_query(q
);
182 struct virgl_screen
*vs
= virgl_screen(ctx
->screen
);
183 struct virgl_context
*vctx
= virgl_context(ctx
);
184 volatile struct virgl_host_query_state
*host_state
;
185 struct pipe_transfer
*transfer
= NULL
;
187 if (vs
->vws
->res_is_referenced(vs
->vws
, vctx
->cbuf
, query
->buf
->hw_res
))
188 ctx
->flush(ctx
, NULL
, 0);
191 vs
->vws
->resource_wait(vs
->vws
, query
->buf
->hw_res
);
192 else if (vs
->vws
->resource_is_busy(vs
->vws
, query
->buf
->hw_res
))
195 host_state
= vs
->vws
->resource_map(vs
->vws
, query
->buf
->hw_res
);
197 /* The resouce is idle and the result should be available at this point,
198 * unless we are dealing with an older host. In that case,
199 * VIRGL_CCMD_GET_QUERY_RESULT is not fenced, the buffer is not
200 * coherent, and transfers are unsynchronized. We have to repeatedly
201 * transfer until we get the result back.
203 while (host_state
->query_state
!= VIRGL_QUERY_STATE_DONE
) {
204 debug_printf("VIRGL: get_query_result is forced blocking\n");
207 pipe_buffer_unmap(ctx
, transfer
);
212 host_state
= pipe_buffer_map(ctx
, &query
->buf
->u
.b
,
213 PIPE_TRANSFER_READ
, &transfer
);
216 if (query
->result_size
== 8)
217 query
->result
= host_state
->result
;
219 query
->result
= (uint32_t) host_state
->result
;
222 pipe_buffer_unmap(ctx
, transfer
);
227 result
->u64
= query
->result
;
233 virgl_set_active_query_state(struct pipe_context
*pipe
, bool enable
)
238 virgl_get_query_result_resource(struct pipe_context
*ctx
,
239 struct pipe_query
*q
,
241 enum pipe_query_value_type result_type
,
243 struct pipe_resource
*resource
,
246 struct virgl_context
*vctx
= virgl_context(ctx
);
247 struct virgl_query
*query
= virgl_query(q
);
248 struct virgl_resource
*qbo
= (struct virgl_resource
*)resource
;
250 virgl_encode_get_query_result_qbo(vctx
, query
->handle
, qbo
, wait
, result_type
, offset
, index
);
253 void virgl_init_query_functions(struct virgl_context
*vctx
)
255 vctx
->base
.render_condition
= virgl_render_condition
;
256 vctx
->base
.create_query
= virgl_create_query
;
257 vctx
->base
.destroy_query
= virgl_destroy_query
;
258 vctx
->base
.begin_query
= virgl_begin_query
;
259 vctx
->base
.end_query
= virgl_end_query
;
260 vctx
->base
.get_query_result
= virgl_get_query_result
;
261 vctx
->base
.set_active_query_state
= virgl_set_active_query_state
;
262 vctx
->base
.get_query_result_resource
= virgl_get_query_result_resource
;