2 * Mesa 3-D graphics library
4 * Copyright (C) 2012-2013 LunarG, Inc.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
25 * Chia-I Wu <olv@lunarg.com>
28 #include "intel_winsys.h"
30 #include "ilo_3d_pipeline.h"
31 #include "ilo_context.h"
33 #include "ilo_query.h"
34 #include "ilo_shader.h"
35 #include "ilo_state.h"
42 ilo_3d_begin_query(struct ilo_context
*ilo
, struct ilo_query
*q
)
44 struct ilo_3d
*hw3d
= ilo
->hw3d
;
46 ilo_cp_set_ring(hw3d
->cp
, ILO_CP_RING_RENDER
);
49 case PIPE_QUERY_OCCLUSION_COUNTER
:
50 /* reserve some space for pausing the query */
51 q
->reg_cmd_size
= ilo_3d_pipeline_estimate_size(hw3d
->pipeline
,
52 ILO_3D_PIPELINE_WRITE_DEPTH_COUNT
, NULL
);
53 ilo_cp_reserve_for_pre_flush(hw3d
->cp
, q
->reg_cmd_size
);
57 if (ilo_query_alloc_bo(q
, 2, -1, hw3d
->cp
->winsys
)) {
58 /* XXX we should check the aperture size */
59 ilo_3d_pipeline_emit_write_depth_count(hw3d
->pipeline
,
60 q
->bo
, q
->reg_read
++);
62 list_add(&q
->list
, &hw3d
->occlusion_queries
);
65 case PIPE_QUERY_TIMESTAMP
:
68 case PIPE_QUERY_TIME_ELAPSED
:
69 /* reserve some space for pausing the query */
70 q
->reg_cmd_size
= ilo_3d_pipeline_estimate_size(hw3d
->pipeline
,
71 ILO_3D_PIPELINE_WRITE_TIMESTAMP
, NULL
);
72 ilo_cp_reserve_for_pre_flush(hw3d
->cp
, q
->reg_cmd_size
);
76 if (ilo_query_alloc_bo(q
, 2, -1, hw3d
->cp
->winsys
)) {
77 /* XXX we should check the aperture size */
78 ilo_3d_pipeline_emit_write_timestamp(hw3d
->pipeline
,
79 q
->bo
, q
->reg_read
++);
81 list_add(&q
->list
, &hw3d
->time_elapsed_queries
);
84 case PIPE_QUERY_PRIMITIVES_GENERATED
:
86 list_add(&q
->list
, &hw3d
->prim_generated_queries
);
88 case PIPE_QUERY_PRIMITIVES_EMITTED
:
90 list_add(&q
->list
, &hw3d
->prim_emitted_queries
);
93 assert(!"unknown query type");
102 ilo_3d_end_query(struct ilo_context
*ilo
, struct ilo_query
*q
)
104 struct ilo_3d
*hw3d
= ilo
->hw3d
;
106 ilo_cp_set_ring(hw3d
->cp
, ILO_CP_RING_RENDER
);
109 case PIPE_QUERY_OCCLUSION_COUNTER
:
112 assert(q
->reg_read
< q
->reg_total
);
113 ilo_cp_reserve_for_pre_flush(hw3d
->cp
, -q
->reg_cmd_size
);
114 ilo_3d_pipeline_emit_write_depth_count(hw3d
->pipeline
,
115 q
->bo
, q
->reg_read
++);
117 case PIPE_QUERY_TIMESTAMP
:
120 if (ilo_query_alloc_bo(q
, 1, 1, hw3d
->cp
->winsys
)) {
121 ilo_3d_pipeline_emit_write_timestamp(hw3d
->pipeline
,
122 q
->bo
, q
->reg_read
++);
125 case PIPE_QUERY_TIME_ELAPSED
:
128 assert(q
->reg_read
< q
->reg_total
);
129 ilo_cp_reserve_for_pre_flush(hw3d
->cp
, -q
->reg_cmd_size
);
130 ilo_3d_pipeline_emit_write_timestamp(hw3d
->pipeline
,
131 q
->bo
, q
->reg_read
++);
133 case PIPE_QUERY_PRIMITIVES_GENERATED
:
134 case PIPE_QUERY_PRIMITIVES_EMITTED
:
138 assert(!"unknown query type");
144 process_query_for_occlusion_counter(struct ilo_3d
*hw3d
,
147 uint64_t *vals
, depth_count
= 0;
151 assert(q
->reg_read
% 2 == 0);
153 q
->bo
->map(q
->bo
, false);
154 vals
= q
->bo
->get_virtual(q
->bo
);
155 for (i
= 1; i
< q
->reg_read
; i
+= 2)
156 depth_count
+= vals
[i
] - vals
[i
- 1];
159 /* accumulate so that the query can be resumed if wanted */
160 q
->data
.u64
+= depth_count
;
165 timestamp_to_ns(uint64_t timestamp
)
167 /* see ilo_get_timestamp() */
168 return (timestamp
& 0xffffffff) * 80;
172 process_query_for_timestamp(struct ilo_3d
*hw3d
, struct ilo_query
*q
)
174 uint64_t *vals
, timestamp
;
176 assert(q
->reg_read
== 1);
178 q
->bo
->map(q
->bo
, false);
179 vals
= q
->bo
->get_virtual(q
->bo
);
183 q
->data
.u64
= timestamp_to_ns(timestamp
);
188 process_query_for_time_elapsed(struct ilo_3d
*hw3d
, struct ilo_query
*q
)
190 uint64_t *vals
, elapsed
= 0;
194 assert(q
->reg_read
% 2 == 0);
196 q
->bo
->map(q
->bo
, false);
197 vals
= q
->bo
->get_virtual(q
->bo
);
199 for (i
= 1; i
< q
->reg_read
; i
+= 2)
200 elapsed
+= vals
[i
] - vals
[i
- 1];
204 /* accumulate so that the query can be resumed if wanted */
205 q
->data
.u64
+= timestamp_to_ns(elapsed
);
210 * Process the raw query data.
213 ilo_3d_process_query(struct ilo_context
*ilo
, struct ilo_query
*q
)
215 struct ilo_3d
*hw3d
= ilo
->hw3d
;
218 case PIPE_QUERY_OCCLUSION_COUNTER
:
220 process_query_for_occlusion_counter(hw3d
, q
);
222 case PIPE_QUERY_TIMESTAMP
:
224 process_query_for_timestamp(hw3d
, q
);
226 case PIPE_QUERY_TIME_ELAPSED
:
228 process_query_for_time_elapsed(hw3d
, q
);
230 case PIPE_QUERY_PRIMITIVES_GENERATED
:
231 case PIPE_QUERY_PRIMITIVES_EMITTED
:
234 assert(!"unknown query type");
240 * Hook for CP new-batch.
243 ilo_3d_new_cp_batch(struct ilo_3d
*hw3d
)
247 hw3d
->new_batch
= true;
249 /* invalidate the pipeline */
250 ilo_3d_pipeline_invalidate(hw3d
->pipeline
,
251 ILO_3D_PIPELINE_INVALIDATE_BATCH_BO
|
252 ILO_3D_PIPELINE_INVALIDATE_STATE_BO
);
253 if (!hw3d
->cp
->hw_ctx
) {
254 ilo_3d_pipeline_invalidate(hw3d
->pipeline
,
255 ILO_3D_PIPELINE_INVALIDATE_HW
);
258 /* resume occlusion queries */
259 LIST_FOR_EACH_ENTRY(q
, &hw3d
->occlusion_queries
, list
) {
260 /* accumulate the result if the bo is alreay full */
261 if (q
->reg_read
>= q
->reg_total
)
262 process_query_for_occlusion_counter(hw3d
, q
);
264 ilo_3d_pipeline_emit_write_depth_count(hw3d
->pipeline
,
265 q
->bo
, q
->reg_read
++);
268 /* resume timer queries */
269 LIST_FOR_EACH_ENTRY(q
, &hw3d
->time_elapsed_queries
, list
) {
270 /* accumulate the result if the bo is alreay full */
271 if (q
->reg_read
>= q
->reg_total
)
272 process_query_for_time_elapsed(hw3d
, q
);
274 ilo_3d_pipeline_emit_write_timestamp(hw3d
->pipeline
,
275 q
->bo
, q
->reg_read
++);
280 * Hook for CP pre-flush.
283 ilo_3d_pre_cp_flush(struct ilo_3d
*hw3d
)
287 /* pause occlusion queries */
288 LIST_FOR_EACH_ENTRY(q
, &hw3d
->occlusion_queries
, list
) {
289 assert(q
->reg_read
< q
->reg_total
);
290 ilo_3d_pipeline_emit_write_depth_count(hw3d
->pipeline
,
291 q
->bo
, q
->reg_read
++);
294 /* pause timer queries */
295 LIST_FOR_EACH_ENTRY(q
, &hw3d
->time_elapsed_queries
, list
) {
296 assert(q
->reg_read
< q
->reg_total
);
297 ilo_3d_pipeline_emit_write_timestamp(hw3d
->pipeline
,
298 q
->bo
, q
->reg_read
++);
303 * Hook for CP post-flush
306 ilo_3d_post_cp_flush(struct ilo_3d
*hw3d
)
308 if (ilo_debug
& ILO_DEBUG_3D
)
309 ilo_3d_pipeline_dump(hw3d
->pipeline
);
313 * Create a 3D context.
316 ilo_3d_create(struct ilo_cp
*cp
, int gen
, int gt
)
320 hw3d
= CALLOC_STRUCT(ilo_3d
);
325 hw3d
->new_batch
= true;
327 list_inithead(&hw3d
->occlusion_queries
);
328 list_inithead(&hw3d
->time_elapsed_queries
);
329 list_inithead(&hw3d
->prim_generated_queries
);
330 list_inithead(&hw3d
->prim_emitted_queries
);
332 hw3d
->pipeline
= ilo_3d_pipeline_create(cp
, gen
, gt
);
333 if (!hw3d
->pipeline
) {
342 * Destroy a 3D context.
345 ilo_3d_destroy(struct ilo_3d
*hw3d
)
347 ilo_3d_pipeline_destroy(hw3d
->pipeline
);
352 draw_vbo(struct ilo_3d
*hw3d
, const struct ilo_context
*ilo
,
353 const struct pipe_draw_info
*info
,
354 int *prim_generated
, int *prim_emitted
)
359 ilo_cp_set_ring(hw3d
->cp
, ILO_CP_RING_RENDER
);
362 * Without a better tracking mechanism, when the framebuffer changes, we
363 * have to assume that the old framebuffer may be sampled from. If that
364 * happens in the middle of a batch buffer, we need to insert manual
367 need_flush
= (!hw3d
->new_batch
&& (ilo
->dirty
& ILO_DIRTY_FRAMEBUFFER
));
369 /* make sure there is enough room first */
370 max_len
= ilo_3d_pipeline_estimate_size(hw3d
->pipeline
,
371 ILO_3D_PIPELINE_DRAW
, ilo
);
373 max_len
+= ilo_3d_pipeline_estimate_size(hw3d
->pipeline
,
374 ILO_3D_PIPELINE_FLUSH
, NULL
);
377 if (max_len
> ilo_cp_space(hw3d
->cp
)) {
378 ilo_cp_flush(hw3d
->cp
);
380 assert(max_len
<= ilo_cp_space(hw3d
->cp
));
384 ilo_3d_pipeline_emit_flush(hw3d
->pipeline
);
386 return ilo_3d_pipeline_emit_draw(hw3d
->pipeline
, ilo
, info
,
387 prim_generated
, prim_emitted
);
391 update_prim_count(struct ilo_3d
*hw3d
, int generated
, int emitted
)
395 LIST_FOR_EACH_ENTRY(q
, &hw3d
->prim_generated_queries
, list
)
396 q
->data
.u64
+= generated
;
398 LIST_FOR_EACH_ENTRY(q
, &hw3d
->prim_emitted_queries
, list
)
399 q
->data
.u64
+= emitted
;
403 pass_render_condition(struct ilo_3d
*hw3d
, struct pipe_context
*pipe
)
408 if (!hw3d
->render_condition
.query
)
411 switch (hw3d
->render_condition
.mode
) {
412 case PIPE_RENDER_COND_WAIT
:
413 case PIPE_RENDER_COND_BY_REGION_WAIT
:
416 case PIPE_RENDER_COND_NO_WAIT
:
417 case PIPE_RENDER_COND_BY_REGION_NO_WAIT
:
423 if (pipe
->get_query_result(pipe
, hw3d
->render_condition
.query
,
424 wait
, (union pipe_query_result
*) &result
)) {
433 ilo_draw_vbo(struct pipe_context
*pipe
, const struct pipe_draw_info
*info
)
435 struct ilo_context
*ilo
= ilo_context(pipe
);
436 struct ilo_3d
*hw3d
= ilo
->hw3d
;
437 int prim_generated
, prim_emitted
;
439 if (!pass_render_condition(hw3d
, pipe
))
442 /* assume the cache is still in use by the previous batch */
444 ilo_shader_cache_mark_busy(ilo
->shader_cache
);
446 ilo_finalize_states(ilo
);
448 /* the shaders may be uploaded to a new shader cache */
449 if (hw3d
->shader_cache_seqno
!= ilo
->shader_cache
->seqno
) {
450 ilo_3d_pipeline_invalidate(hw3d
->pipeline
,
451 ILO_3D_PIPELINE_INVALIDATE_KERNEL_BO
);
455 * The VBs and/or IB may have different BOs due to being mapped with
456 * PIPE_TRANSFER_DISCARD_x. We should track that instead of setting the
457 * dirty flags for the performance reason.
459 ilo
->dirty
|= ILO_DIRTY_VERTEX_BUFFERS
| ILO_DIRTY_INDEX_BUFFER
;
461 if (!draw_vbo(hw3d
, ilo
, info
, &prim_generated
, &prim_emitted
))
464 /* clear dirty status */
466 hw3d
->new_batch
= false;
467 hw3d
->shader_cache_seqno
= ilo
->shader_cache
->seqno
;
469 update_prim_count(hw3d
, prim_generated
, prim_emitted
);
471 if (ilo_debug
& ILO_DEBUG_NOCACHE
)
472 ilo_3d_pipeline_emit_flush(hw3d
->pipeline
);
476 ilo_render_condition(struct pipe_context
*pipe
,
477 struct pipe_query
*query
,
480 struct ilo_context
*ilo
= ilo_context(pipe
);
481 struct ilo_3d
*hw3d
= ilo
->hw3d
;
483 /* reference count? */
484 hw3d
->render_condition
.query
= query
;
485 hw3d
->render_condition
.mode
= mode
;
489 ilo_texture_barrier(struct pipe_context
*pipe
)
491 struct ilo_context
*ilo
= ilo_context(pipe
);
492 struct ilo_3d
*hw3d
= ilo
->hw3d
;
494 if (ilo
->cp
->ring
!= ILO_CP_RING_RENDER
)
497 ilo_3d_pipeline_emit_flush(hw3d
->pipeline
);
500 if (ilo
->gen
>= ILO_GEN(7))
501 ilo_cp_flush(hw3d
->cp
);
505 ilo_get_sample_position(struct pipe_context
*pipe
,
506 unsigned sample_count
,
507 unsigned sample_index
,
510 struct ilo_context
*ilo
= ilo_context(pipe
);
511 struct ilo_3d
*hw3d
= ilo
->hw3d
;
513 ilo_3d_pipeline_get_sample_position(hw3d
->pipeline
,
514 sample_count
, sample_index
,
515 &out_value
[0], &out_value
[1]);
519 * Initialize 3D-related functions.
522 ilo_init_3d_functions(struct ilo_context
*ilo
)
524 ilo
->base
.draw_vbo
= ilo_draw_vbo
;
525 ilo
->base
.render_condition
= ilo_render_condition
;
526 ilo
->base
.texture_barrier
= ilo_texture_barrier
;
527 ilo
->base
.get_sample_position
= ilo_get_sample_position
;