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 virgl_encoder_create_query(vctx
, query
->handle
,
118 pipe_to_virgl_query(query_type
), index
, query
->buf
, 0);
120 return (struct pipe_query
*)query
;
123 static void virgl_destroy_query(struct pipe_context
*ctx
,
124 struct pipe_query
*q
)
126 struct virgl_context
*vctx
= virgl_context(ctx
);
127 struct virgl_query
*query
= virgl_query(q
);
129 virgl_encode_delete_object(vctx
, query
->handle
, VIRGL_OBJECT_QUERY
);
131 pipe_resource_reference((struct pipe_resource
**)&query
->buf
, NULL
);
135 static boolean
virgl_begin_query(struct pipe_context
*ctx
,
136 struct pipe_query
*q
)
138 struct virgl_context
*vctx
= virgl_context(ctx
);
139 struct virgl_query
*query
= virgl_query(q
);
141 virgl_encoder_begin_query(vctx
, query
->handle
);
146 static bool virgl_end_query(struct pipe_context
*ctx
,
147 struct pipe_query
*q
)
149 struct virgl_screen
*vs
= virgl_screen(ctx
->screen
);
150 struct virgl_context
*vctx
= virgl_context(ctx
);
151 struct virgl_query
*query
= virgl_query(q
);
152 struct virgl_host_query_state
*host_state
;
154 host_state
= vs
->vws
->resource_map(vs
->vws
, query
->buf
->hw_res
);
158 host_state
->query_state
= VIRGL_QUERY_STATE_WAIT_HOST
;
159 virgl_resource_dirty(query
->buf
, 0);
160 query
->ready
= false;
162 virgl_encoder_end_query(vctx
, query
->handle
);
164 /* start polling now */
165 virgl_encoder_get_query_result(vctx
, query
->handle
, 0);
166 vs
->vws
->emit_res(vs
->vws
, vctx
->cbuf
, query
->buf
->hw_res
, false);
171 static boolean
virgl_get_query_result(struct pipe_context
*ctx
,
172 struct pipe_query
*q
,
174 union pipe_query_result
*result
)
176 struct virgl_query
*query
= virgl_query(q
);
179 struct virgl_screen
*vs
= virgl_screen(ctx
->screen
);
180 struct virgl_context
*vctx
= virgl_context(ctx
);
181 volatile struct virgl_host_query_state
*host_state
;
182 struct pipe_transfer
*transfer
= NULL
;
184 if (vs
->vws
->res_is_referenced(vs
->vws
, vctx
->cbuf
, query
->buf
->hw_res
))
185 ctx
->flush(ctx
, NULL
, 0);
188 vs
->vws
->resource_wait(vs
->vws
, query
->buf
->hw_res
);
189 else if (vs
->vws
->resource_is_busy(vs
->vws
, query
->buf
->hw_res
))
192 host_state
= vs
->vws
->resource_map(vs
->vws
, query
->buf
->hw_res
);
194 /* The resouce is idle and the result should be available at this point,
195 * unless we are dealing with an older host. In that case,
196 * VIRGL_CCMD_GET_QUERY_RESULT is not fenced, the buffer is not
197 * coherent, and transfers are unsynchronized. We have to repeatedly
198 * transfer until we get the result back.
200 while (host_state
->query_state
!= VIRGL_QUERY_STATE_DONE
) {
201 debug_printf("VIRGL: get_query_result is forced blocking\n");
204 pipe_buffer_unmap(ctx
, transfer
);
209 host_state
= pipe_buffer_map(ctx
, &query
->buf
->u
.b
,
210 PIPE_TRANSFER_READ
, &transfer
);
213 if (query
->result_size
== 8)
214 query
->result
= host_state
->result
;
216 query
->result
= (uint32_t) host_state
->result
;
219 pipe_buffer_unmap(ctx
, transfer
);
224 result
->u64
= query
->result
;
230 virgl_set_active_query_state(struct pipe_context
*pipe
, boolean enable
)
235 virgl_get_query_result_resource(struct pipe_context
*ctx
,
236 struct pipe_query
*q
,
238 enum pipe_query_value_type result_type
,
240 struct pipe_resource
*resource
,
243 struct virgl_context
*vctx
= virgl_context(ctx
);
244 struct virgl_query
*query
= virgl_query(q
);
245 struct virgl_resource
*qbo
= (struct virgl_resource
*)resource
;
247 virgl_encode_get_query_result_qbo(vctx
, query
->handle
, qbo
, wait
, result_type
, offset
, index
);
250 void virgl_init_query_functions(struct virgl_context
*vctx
)
252 vctx
->base
.render_condition
= virgl_render_condition
;
253 vctx
->base
.create_query
= virgl_create_query
;
254 vctx
->base
.destroy_query
= virgl_destroy_query
;
255 vctx
->base
.begin_query
= virgl_begin_query
;
256 vctx
->base
.end_query
= virgl_end_query
;
257 vctx
->base
.get_query_result
= virgl_get_query_result
;
258 vctx
->base
.set_active_query_state
= virgl_set_active_query_state
;
259 vctx
->base
.get_query_result_resource
= virgl_get_query_result_resource
;