ilo: clarify cp owning/releasing
[mesa.git] / src / gallium / drivers / ilo / ilo_3d.c
1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2012-2013 LunarG, Inc.
5 *
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:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
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.
23 *
24 * Authors:
25 * Chia-I Wu <olv@lunarg.com>
26 */
27
28 #include "util/u_prim.h"
29 #include "intel_winsys.h"
30
31 #include "ilo_3d_pipeline.h"
32 #include "ilo_blit.h"
33 #include "ilo_context.h"
34 #include "ilo_cp.h"
35 #include "ilo_query.h"
36 #include "ilo_shader.h"
37 #include "ilo_state.h"
38 #include "ilo_3d.h"
39
40 static void
41 process_query_for_occlusion_counter(struct ilo_3d *hw3d,
42 struct ilo_query *q)
43 {
44 uint64_t *vals, depth_count = 0;
45 int i;
46
47 /* in pairs */
48 assert(q->reg_read % 2 == 0);
49
50 vals = intel_bo_map(q->bo, false);
51 for (i = 1; i < q->reg_read; i += 2)
52 depth_count += vals[i] - vals[i - 1];
53 intel_bo_unmap(q->bo);
54
55 /* accumulate so that the query can be resumed if wanted */
56 q->data.u64 += depth_count;
57 q->reg_read = 0;
58 }
59
60 static uint64_t
61 timestamp_to_ns(uint64_t timestamp)
62 {
63 /* see ilo_get_timestamp() */
64 return (timestamp & 0xffffffff) * 80;
65 }
66
67 static void
68 process_query_for_timestamp(struct ilo_3d *hw3d, struct ilo_query *q)
69 {
70 uint64_t *vals, timestamp;
71
72 assert(q->reg_read == 1);
73
74 vals = intel_bo_map(q->bo, false);
75 timestamp = vals[0];
76 intel_bo_unmap(q->bo);
77
78 q->data.u64 = timestamp_to_ns(timestamp);
79 q->reg_read = 0;
80 }
81
82 static void
83 process_query_for_time_elapsed(struct ilo_3d *hw3d, struct ilo_query *q)
84 {
85 uint64_t *vals, elapsed = 0;
86 int i;
87
88 /* in pairs */
89 assert(q->reg_read % 2 == 0);
90
91 vals = intel_bo_map(q->bo, false);
92
93 for (i = 1; i < q->reg_read; i += 2)
94 elapsed += vals[i] - vals[i - 1];
95
96 intel_bo_unmap(q->bo);
97
98 /* accumulate so that the query can be resumed if wanted */
99 q->data.u64 += timestamp_to_ns(elapsed);
100 q->reg_read = 0;
101 }
102
103 static void
104 process_query_for_pipeline_statistics(struct ilo_3d *hw3d,
105 struct ilo_query *q)
106 {
107 const uint64_t *vals;
108 int i;
109
110 assert(q->reg_read % 22 == 0);
111
112 vals = intel_bo_map(q->bo, false);
113
114 for (i = 0; i < q->reg_read; i += 22) {
115 struct pipe_query_data_pipeline_statistics *stats =
116 &q->data.pipeline_statistics;
117 const uint64_t *begin = vals + i;
118 const uint64_t *end = begin + 11;
119
120 stats->ia_vertices += end[0] - begin[0];
121 stats->ia_primitives += end[1] - begin[1];
122 stats->vs_invocations += end[2] - begin[2];
123 stats->gs_invocations += end[3] - begin[3];
124 stats->gs_primitives += end[4] - begin[4];
125 stats->c_invocations += end[5] - begin[5];
126 stats->c_primitives += end[6] - begin[6];
127 stats->ps_invocations += end[7] - begin[7];
128 stats->hs_invocations += end[8] - begin[8];
129 stats->ds_invocations += end[9] - begin[9];
130 stats->cs_invocations += end[10] - begin[10];
131 }
132
133 intel_bo_unmap(q->bo);
134
135 q->reg_read = 0;
136 }
137
138 static void
139 ilo_3d_resume_queries(struct ilo_3d *hw3d)
140 {
141 struct ilo_query *q;
142
143 /* resume occlusion queries */
144 LIST_FOR_EACH_ENTRY(q, &hw3d->occlusion_queries, list) {
145 /* accumulate the result if the bo is alreay full */
146 if (q->reg_read >= q->reg_total)
147 process_query_for_occlusion_counter(hw3d, q);
148
149 ilo_3d_pipeline_emit_write_depth_count(hw3d->pipeline,
150 q->bo, q->reg_read++);
151 }
152
153 /* resume timer queries */
154 LIST_FOR_EACH_ENTRY(q, &hw3d->time_elapsed_queries, list) {
155 /* accumulate the result if the bo is alreay full */
156 if (q->reg_read >= q->reg_total)
157 process_query_for_time_elapsed(hw3d, q);
158
159 ilo_3d_pipeline_emit_write_timestamp(hw3d->pipeline,
160 q->bo, q->reg_read++);
161 }
162
163 /* resume pipeline statistics queries */
164 LIST_FOR_EACH_ENTRY(q, &hw3d->pipeline_statistics_queries, list) {
165 /* accumulate the result if the bo is alreay full */
166 if (q->reg_read >= q->reg_total)
167 process_query_for_pipeline_statistics(hw3d, q);
168
169 ilo_3d_pipeline_emit_write_statistics(hw3d->pipeline,
170 q->bo, q->reg_read);
171 q->reg_read += 11;
172 }
173 }
174
175 static void
176 ilo_3d_pause_queries(struct ilo_3d *hw3d)
177 {
178 struct ilo_query *q;
179
180 /* pause occlusion queries */
181 LIST_FOR_EACH_ENTRY(q, &hw3d->occlusion_queries, list) {
182 assert(q->reg_read < q->reg_total);
183 ilo_3d_pipeline_emit_write_depth_count(hw3d->pipeline,
184 q->bo, q->reg_read++);
185 }
186
187 /* pause timer queries */
188 LIST_FOR_EACH_ENTRY(q, &hw3d->time_elapsed_queries, list) {
189 assert(q->reg_read < q->reg_total);
190 ilo_3d_pipeline_emit_write_timestamp(hw3d->pipeline,
191 q->bo, q->reg_read++);
192 }
193
194 /* pause pipeline statistics queries */
195 LIST_FOR_EACH_ENTRY(q, &hw3d->pipeline_statistics_queries, list) {
196 assert(q->reg_read < q->reg_total);
197 ilo_3d_pipeline_emit_write_statistics(hw3d->pipeline,
198 q->bo, q->reg_read);
199 q->reg_read += 11;
200 }
201 }
202
203 static void
204 ilo_3d_own_render_ring(struct ilo_3d *hw3d)
205 {
206 ilo_cp_set_owner(hw3d->cp, INTEL_RING_RENDER, &hw3d->owner);
207 }
208
209 static void
210 ilo_3d_reserve_for_query(struct ilo_3d *hw3d, struct ilo_query *q,
211 enum ilo_3d_pipeline_action act)
212 {
213 q->reg_cmd_size = ilo_3d_pipeline_estimate_size(hw3d->pipeline, act, NULL);
214
215 /* XXX we should check the aperture size */
216 if (ilo_cp_space(hw3d->cp) < q->reg_cmd_size * 2) {
217 ilo_cp_submit(hw3d->cp, "out of space");
218 assert(ilo_cp_space(hw3d->cp) >= q->reg_cmd_size * 2);
219 }
220
221 /* reserve space for pausing the query */
222 hw3d->owner.reserve += q->reg_cmd_size;
223 }
224
225 /**
226 * Begin a query.
227 */
228 void
229 ilo_3d_begin_query(struct ilo_context *ilo, struct ilo_query *q)
230 {
231 struct ilo_3d *hw3d = ilo->hw3d;
232
233 ilo_3d_own_render_ring(hw3d);
234
235 switch (q->type) {
236 case PIPE_QUERY_OCCLUSION_COUNTER:
237 ilo_3d_reserve_for_query(hw3d, q, ILO_3D_PIPELINE_WRITE_DEPTH_COUNT);
238 q->data.u64 = 0;
239
240 if (ilo_query_alloc_bo(q, 2, -1, hw3d->cp->winsys)) {
241 ilo_3d_pipeline_emit_write_depth_count(hw3d->pipeline,
242 q->bo, q->reg_read++);
243
244 list_add(&q->list, &hw3d->occlusion_queries);
245 }
246 break;
247 case PIPE_QUERY_TIMESTAMP:
248 /* nop */
249 break;
250 case PIPE_QUERY_TIME_ELAPSED:
251 ilo_3d_reserve_for_query(hw3d, q, ILO_3D_PIPELINE_WRITE_TIMESTAMP);
252 q->data.u64 = 0;
253
254 if (ilo_query_alloc_bo(q, 2, -1, hw3d->cp->winsys)) {
255 ilo_3d_pipeline_emit_write_timestamp(hw3d->pipeline,
256 q->bo, q->reg_read++);
257
258 list_add(&q->list, &hw3d->time_elapsed_queries);
259 }
260 break;
261 case PIPE_QUERY_PRIMITIVES_GENERATED:
262 q->data.u64 = 0;
263 list_add(&q->list, &hw3d->prim_generated_queries);
264 break;
265 case PIPE_QUERY_PRIMITIVES_EMITTED:
266 q->data.u64 = 0;
267 list_add(&q->list, &hw3d->prim_emitted_queries);
268 break;
269 case PIPE_QUERY_PIPELINE_STATISTICS:
270 ilo_3d_reserve_for_query(hw3d, q, ILO_3D_PIPELINE_WRITE_STATISTICS);
271 memset(&q->data.pipeline_statistics, 0,
272 sizeof(q->data.pipeline_statistics));
273
274 if (ilo_query_alloc_bo(q, 11 * 2, -1, hw3d->cp->winsys)) {
275 ilo_3d_pipeline_emit_write_statistics(hw3d->pipeline,
276 q->bo, q->reg_read);
277 q->reg_read += 11;
278
279 list_add(&q->list, &hw3d->pipeline_statistics_queries);
280 }
281 break;
282 default:
283 assert(!"unknown query type");
284 break;
285 }
286 }
287
288 /**
289 * End a query.
290 */
291 void
292 ilo_3d_end_query(struct ilo_context *ilo, struct ilo_query *q)
293 {
294 struct ilo_3d *hw3d = ilo->hw3d;
295
296 ilo_3d_own_render_ring(hw3d);
297
298 switch (q->type) {
299 case PIPE_QUERY_OCCLUSION_COUNTER:
300 list_del(&q->list);
301
302 assert(q->reg_read < q->reg_total);
303 assert(hw3d->owner.reserve >= q->reg_cmd_size);
304 hw3d->owner.reserve -= q->reg_cmd_size;
305
306 ilo_3d_pipeline_emit_write_depth_count(hw3d->pipeline,
307 q->bo, q->reg_read++);
308 break;
309 case PIPE_QUERY_TIMESTAMP:
310 q->data.u64 = 0;
311
312 if (ilo_query_alloc_bo(q, 1, 1, hw3d->cp->winsys)) {
313 ilo_3d_pipeline_emit_write_timestamp(hw3d->pipeline,
314 q->bo, q->reg_read++);
315 }
316 break;
317 case PIPE_QUERY_TIME_ELAPSED:
318 list_del(&q->list);
319
320 assert(q->reg_read < q->reg_total);
321 assert(hw3d->owner.reserve >= q->reg_cmd_size);
322 hw3d->owner.reserve -= q->reg_cmd_size;
323
324 ilo_3d_pipeline_emit_write_timestamp(hw3d->pipeline,
325 q->bo, q->reg_read++);
326 break;
327 case PIPE_QUERY_PRIMITIVES_GENERATED:
328 case PIPE_QUERY_PRIMITIVES_EMITTED:
329 list_del(&q->list);
330 break;
331 case PIPE_QUERY_PIPELINE_STATISTICS:
332 list_del(&q->list);
333
334 assert(q->reg_read + 11 <= q->reg_total);
335 assert(hw3d->owner.reserve >= q->reg_cmd_size);
336 hw3d->owner.reserve -= q->reg_cmd_size;
337
338 ilo_3d_pipeline_emit_write_statistics(hw3d->pipeline,
339 q->bo, q->reg_read);
340 q->reg_read += 11;
341 break;
342 default:
343 assert(!"unknown query type");
344 break;
345 }
346 }
347
348 /**
349 * Process the raw query data.
350 */
351 void
352 ilo_3d_process_query(struct ilo_context *ilo, struct ilo_query *q)
353 {
354 struct ilo_3d *hw3d = ilo->hw3d;
355
356 switch (q->type) {
357 case PIPE_QUERY_OCCLUSION_COUNTER:
358 if (q->bo)
359 process_query_for_occlusion_counter(hw3d, q);
360 break;
361 case PIPE_QUERY_TIMESTAMP:
362 if (q->bo)
363 process_query_for_timestamp(hw3d, q);
364 break;
365 case PIPE_QUERY_TIME_ELAPSED:
366 if (q->bo)
367 process_query_for_time_elapsed(hw3d, q);
368 break;
369 case PIPE_QUERY_PRIMITIVES_GENERATED:
370 case PIPE_QUERY_PRIMITIVES_EMITTED:
371 break;
372 case PIPE_QUERY_PIPELINE_STATISTICS:
373 if (q->bo)
374 process_query_for_pipeline_statistics(hw3d, q);
375 break;
376 default:
377 assert(!"unknown query type");
378 break;
379 }
380 }
381
382 /**
383 * Hook for CP new-batch.
384 */
385 void
386 ilo_3d_cp_submitted(struct ilo_3d *hw3d)
387 {
388 /* invalidate the pipeline */
389 ilo_3d_pipeline_invalidate(hw3d->pipeline,
390 ILO_3D_PIPELINE_INVALIDATE_BATCH_BO |
391 ILO_3D_PIPELINE_INVALIDATE_STATE_BO |
392 ILO_3D_PIPELINE_INVALIDATE_KERNEL_BO);
393
394 hw3d->new_batch = true;
395 }
396
397 static void
398 ilo_3d_own_cp(struct ilo_cp *cp, void *data)
399 {
400 struct ilo_3d *hw3d = data;
401
402 /* multiply by 2 for both resuming and pausing */
403 if (ilo_cp_space(hw3d->cp) < hw3d->owner.reserve * 2) {
404 ilo_cp_submit(hw3d->cp, "out of space");
405 assert(ilo_cp_space(hw3d->cp) >= hw3d->owner.reserve * 2);
406 }
407
408 ilo_3d_resume_queries(hw3d);
409
410 assert(ilo_cp_space(hw3d->cp) >= hw3d->owner.reserve);
411 }
412
413 static void
414 ilo_3d_release_cp(struct ilo_cp *cp, void *data)
415 {
416 struct ilo_3d *hw3d = data;
417
418 ilo_3d_pause_queries(hw3d);
419 }
420
421 /**
422 * Create a 3D context.
423 */
424 struct ilo_3d *
425 ilo_3d_create(struct ilo_cp *cp, const struct ilo_dev_info *dev)
426 {
427 struct ilo_3d *hw3d;
428
429 hw3d = CALLOC_STRUCT(ilo_3d);
430 if (!hw3d)
431 return NULL;
432
433 hw3d->cp = cp;
434 hw3d->owner.own = ilo_3d_own_cp;
435 hw3d->owner.release = ilo_3d_release_cp;
436 hw3d->owner.data = hw3d;
437 hw3d->owner.reserve = 0;
438
439 hw3d->new_batch = true;
440
441 list_inithead(&hw3d->occlusion_queries);
442 list_inithead(&hw3d->time_elapsed_queries);
443 list_inithead(&hw3d->prim_generated_queries);
444 list_inithead(&hw3d->prim_emitted_queries);
445 list_inithead(&hw3d->pipeline_statistics_queries);
446
447 hw3d->pipeline = ilo_3d_pipeline_create(cp, dev);
448 if (!hw3d->pipeline) {
449 FREE(hw3d);
450 return NULL;
451 }
452
453 return hw3d;
454 }
455
456 /**
457 * Destroy a 3D context.
458 */
459 void
460 ilo_3d_destroy(struct ilo_3d *hw3d)
461 {
462 ilo_3d_pipeline_destroy(hw3d->pipeline);
463 FREE(hw3d);
464 }
465
466 static bool
467 draw_vbo(struct ilo_3d *hw3d, const struct ilo_state_vector *vec,
468 int *prim_generated, int *prim_emitted)
469 {
470 bool need_flush = false;
471 int max_len;
472
473 ilo_3d_own_render_ring(hw3d);
474
475 if (!hw3d->new_batch) {
476 /*
477 * Without a better tracking mechanism, when the framebuffer changes, we
478 * have to assume that the old framebuffer may be sampled from. If that
479 * happens in the middle of a batch buffer, we need to insert manual
480 * flushes.
481 */
482 need_flush = (vec->dirty & ILO_DIRTY_FB);
483
484 /* same to SO target changes */
485 need_flush |= (vec->dirty & ILO_DIRTY_SO);
486 }
487
488 /* make sure there is enough room first */
489 max_len = ilo_3d_pipeline_estimate_size(hw3d->pipeline,
490 ILO_3D_PIPELINE_DRAW, vec);
491 if (need_flush) {
492 max_len += ilo_3d_pipeline_estimate_size(hw3d->pipeline,
493 ILO_3D_PIPELINE_FLUSH, NULL);
494 }
495
496 if (max_len > ilo_cp_space(hw3d->cp)) {
497 ilo_cp_submit(hw3d->cp, "out of space");
498 need_flush = false;
499 assert(max_len <= ilo_cp_space(hw3d->cp));
500 }
501
502 if (need_flush)
503 ilo_3d_pipeline_emit_flush(hw3d->pipeline);
504
505 return ilo_3d_pipeline_emit_draw(hw3d->pipeline, vec,
506 prim_generated, prim_emitted);
507 }
508
509 static void
510 update_prim_count(struct ilo_3d *hw3d, int generated, int emitted)
511 {
512 struct ilo_query *q;
513
514 LIST_FOR_EACH_ENTRY(q, &hw3d->prim_generated_queries, list)
515 q->data.u64 += generated;
516
517 LIST_FOR_EACH_ENTRY(q, &hw3d->prim_emitted_queries, list)
518 q->data.u64 += emitted;
519 }
520
521 bool
522 ilo_3d_pass_render_condition(struct ilo_context *ilo)
523 {
524 struct ilo_3d *hw3d = ilo->hw3d;
525 uint64_t result;
526 bool wait;
527
528 if (!hw3d->render_condition.query)
529 return true;
530
531 switch (hw3d->render_condition.mode) {
532 case PIPE_RENDER_COND_WAIT:
533 case PIPE_RENDER_COND_BY_REGION_WAIT:
534 wait = true;
535 break;
536 case PIPE_RENDER_COND_NO_WAIT:
537 case PIPE_RENDER_COND_BY_REGION_NO_WAIT:
538 default:
539 wait = false;
540 break;
541 }
542
543 if (ilo->base.get_query_result(&ilo->base, hw3d->render_condition.query,
544 wait, (union pipe_query_result *) &result))
545 return (!result == hw3d->render_condition.cond);
546 else
547 return true;
548 }
549
550 void
551 ilo_3d_draw_rectlist(struct ilo_3d *hw3d, const struct ilo_blitter *blitter)
552 {
553 ilo_3d_own_render_ring(hw3d);
554
555 /*
556 * From the Sandy Bridge PRM, volume 2 part 1, page 313:
557 *
558 * "If other rendering operations have preceded this clear, a
559 * PIPE_CONTROL with write cache flush enabled and Z-inhibit
560 * disabled must be issued before the rectangle primitive used for
561 * the depth buffer clear operation."
562 *
563 * From the Sandy Bridge PRM, volume 2 part 1, page 314:
564 *
565 * "Depth buffer clear pass must be followed by a PIPE_CONTROL
566 * command with DEPTH_STALL bit set and Then followed by Depth
567 * FLUSH"
568 *
569 * But the pipeline has to be flushed both before and after not only
570 * because of these workarounds. We need them for reasons such as
571 *
572 * - we may sample from a texture that was rendered to
573 * - we may sample from the fb shortly after
574 *
575 * Skip checking blitter->op and do the flushes.
576 *
577 * XXX need space check
578 */
579 if (!hw3d->new_batch)
580 ilo_3d_pipeline_emit_flush(hw3d->pipeline);
581
582 ilo_3d_pipeline_emit_rectlist(hw3d->pipeline, blitter);
583
584 ilo_3d_pipeline_emit_flush(hw3d->pipeline);
585
586 hw3d->new_batch = false;
587 }
588
589 #define UPDATE_MIN2(a, b) (a) = MIN2((a), (b))
590 #define UPDATE_MAX2(a, b) (a) = MAX2((a), (b))
591
592 /**
593 * \see find_sub_primitives() from core mesa
594 */
595 static int
596 ilo_find_sub_primitives(const void *elements, unsigned element_size,
597 const struct pipe_draw_info *orig_info,
598 struct pipe_draw_info *info)
599 {
600 const unsigned max_prims = orig_info->count - orig_info->start;
601 unsigned i, cur_start, cur_count;
602 int scan_index;
603 unsigned scan_num;
604
605 cur_start = orig_info->start;
606 cur_count = 0;
607 scan_num = 0;
608
609 #define IB_INDEX_READ(TYPE, INDEX) (((const TYPE *) elements)[INDEX])
610
611 #define SCAN_ELEMENTS(TYPE) \
612 info[scan_num] = *orig_info; \
613 info[scan_num].primitive_restart = false; \
614 for (i = orig_info->start; i < orig_info->count; i++) { \
615 scan_index = IB_INDEX_READ(TYPE, i); \
616 if (scan_index == orig_info->restart_index) { \
617 if (cur_count > 0) { \
618 assert(scan_num < max_prims); \
619 info[scan_num].start = cur_start; \
620 info[scan_num].count = cur_count; \
621 scan_num++; \
622 info[scan_num] = *orig_info; \
623 info[scan_num].primitive_restart = false; \
624 } \
625 cur_start = i + 1; \
626 cur_count = 0; \
627 } \
628 else { \
629 UPDATE_MIN2(info[scan_num].min_index, scan_index); \
630 UPDATE_MAX2(info[scan_num].max_index, scan_index); \
631 cur_count++; \
632 } \
633 } \
634 if (cur_count > 0) { \
635 assert(scan_num < max_prims); \
636 info[scan_num].start = cur_start; \
637 info[scan_num].count = cur_count; \
638 scan_num++; \
639 }
640
641 switch (element_size) {
642 case 1:
643 SCAN_ELEMENTS(uint8_t);
644 break;
645 case 2:
646 SCAN_ELEMENTS(uint16_t);
647 break;
648 case 4:
649 SCAN_ELEMENTS(uint32_t);
650 break;
651 default:
652 assert(0 && "bad index_size in find_sub_primitives()");
653 }
654
655 #undef SCAN_ELEMENTS
656
657 return scan_num;
658 }
659
660 static inline bool
661 ilo_check_restart_index(const struct ilo_context *ilo, unsigned restart_index)
662 {
663 /*
664 * Haswell (GEN(7.5)) supports an arbitrary cut index, check everything
665 * older.
666 */
667 if (ilo_dev_gen(ilo->dev) >= ILO_GEN(7.5))
668 return true;
669
670 /* Note: indices must be unsigned byte, unsigned short or unsigned int */
671 switch (ilo->state_vector.ib.index_size) {
672 case 1:
673 return ((restart_index & 0xff) == 0xff);
674 break;
675 case 2:
676 return ((restart_index & 0xffff) == 0xffff);
677 break;
678 case 4:
679 return (restart_index == 0xffffffff);
680 break;
681 }
682 return false;
683 }
684
685 static inline bool
686 ilo_check_restart_prim_type(const struct ilo_context *ilo, unsigned prim)
687 {
688 switch (prim) {
689 case PIPE_PRIM_POINTS:
690 case PIPE_PRIM_LINES:
691 case PIPE_PRIM_LINE_STRIP:
692 case PIPE_PRIM_TRIANGLES:
693 case PIPE_PRIM_TRIANGLE_STRIP:
694 /* All 965 GEN graphics support a cut index for these primitive types */
695 return true;
696 break;
697
698 case PIPE_PRIM_LINE_LOOP:
699 case PIPE_PRIM_POLYGON:
700 case PIPE_PRIM_QUAD_STRIP:
701 case PIPE_PRIM_QUADS:
702 case PIPE_PRIM_TRIANGLE_FAN:
703 if (ilo_dev_gen(ilo->dev) >= ILO_GEN(7.5)) {
704 /* Haswell and newer parts can handle these prim types. */
705 return true;
706 }
707 break;
708 }
709
710 return false;
711 }
712
713 /*
714 * Handle VBOs using primitive restart.
715 * Verify that restart index and primitive type can be handled by the HW.
716 * Return true if this routine did the rendering
717 * Return false if this routine did NOT render because restart can be handled
718 * in HW.
719 */
720 static void
721 ilo_draw_vbo_with_sw_restart(struct pipe_context *pipe,
722 const struct pipe_draw_info *info)
723 {
724 struct ilo_state_vector *vec = &ilo_context(pipe)->state_vector;
725 struct pipe_draw_info *restart_info = NULL;
726 int sub_prim_count = 1;
727
728 /*
729 * We have to break up the primitive into chunks manually
730 * Worst case, every other index could be a restart index so
731 * need to have space for that many primitives
732 */
733 restart_info = MALLOC(((info->count + 1) / 2) * sizeof(*info));
734 if (NULL == restart_info) {
735 /* If we can't get memory for this, bail out */
736 ilo_err("%s:%d - Out of memory", __FILE__, __LINE__);
737 return;
738 }
739
740 if (vec->ib.buffer) {
741 struct pipe_transfer *transfer;
742 const void *map;
743
744 map = pipe_buffer_map(pipe, vec->ib.buffer,
745 PIPE_TRANSFER_READ, &transfer);
746
747 sub_prim_count = ilo_find_sub_primitives(map + vec->ib.offset,
748 vec->ib.index_size, info, restart_info);
749
750 pipe_buffer_unmap(pipe, transfer);
751 }
752 else {
753 sub_prim_count =
754 ilo_find_sub_primitives(vec->ib.user_buffer,
755 vec->ib.index_size, info, restart_info);
756 }
757
758 info = restart_info;
759
760 while (sub_prim_count > 0) {
761 pipe->draw_vbo(pipe, info);
762
763 sub_prim_count--;
764 info++;
765 }
766
767 FREE(restart_info);
768 }
769
770 static void
771 ilo_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
772 {
773 struct ilo_context *ilo = ilo_context(pipe);
774 struct ilo_3d *hw3d = ilo->hw3d;
775 int prim_generated, prim_emitted;
776
777 if (ilo_debug & ILO_DEBUG_DRAW) {
778 if (info->indexed) {
779 ilo_printf("indexed draw %s: "
780 "index start %d, count %d, vertex range [%d, %d]\n",
781 u_prim_name(info->mode), info->start, info->count,
782 info->min_index, info->max_index);
783 }
784 else {
785 ilo_printf("draw %s: vertex start %d, count %d\n",
786 u_prim_name(info->mode), info->start, info->count);
787 }
788
789 ilo_state_vector_dump_dirty(&ilo->state_vector);
790 }
791
792 if (!ilo_3d_pass_render_condition(ilo))
793 return;
794
795 if (info->primitive_restart && info->indexed) {
796 /*
797 * Want to draw an indexed primitive using primitive restart
798 * Check that HW can handle the request and fall to SW if not.
799 */
800 if (!ilo_check_restart_index(ilo, info->restart_index) ||
801 !ilo_check_restart_prim_type(ilo, info->mode)) {
802 ilo_draw_vbo_with_sw_restart(pipe, info);
803 return;
804 }
805 }
806
807 ilo_finalize_3d_states(ilo, info);
808
809 ilo_shader_cache_upload(ilo->shader_cache, &hw3d->cp->builder);
810
811 ilo_blit_resolve_framebuffer(ilo);
812
813 /* If draw_vbo ever fails, return immediately. */
814 if (!draw_vbo(hw3d, &ilo->state_vector, &prim_generated, &prim_emitted))
815 return;
816
817 /* clear dirty status */
818 ilo->state_vector.dirty = 0x0;
819 hw3d->new_batch = false;
820
821 /* avoid dangling pointer reference */
822 ilo->state_vector.draw = NULL;
823
824 update_prim_count(hw3d, prim_generated, prim_emitted);
825
826 if (ilo_debug & ILO_DEBUG_NOCACHE)
827 ilo_3d_pipeline_emit_flush(hw3d->pipeline);
828 }
829
830 static void
831 ilo_render_condition(struct pipe_context *pipe,
832 struct pipe_query *query,
833 boolean condition,
834 uint mode)
835 {
836 struct ilo_context *ilo = ilo_context(pipe);
837 struct ilo_3d *hw3d = ilo->hw3d;
838
839 /* reference count? */
840 hw3d->render_condition.query = query;
841 hw3d->render_condition.mode = mode;
842 hw3d->render_condition.cond = condition;
843 }
844
845 static void
846 ilo_texture_barrier(struct pipe_context *pipe)
847 {
848 struct ilo_context *ilo = ilo_context(pipe);
849 struct ilo_3d *hw3d = ilo->hw3d;
850
851 if (ilo->cp->ring != INTEL_RING_RENDER)
852 return;
853
854 ilo_3d_pipeline_emit_flush(hw3d->pipeline);
855
856 /* don't know why */
857 if (ilo_dev_gen(ilo->dev) >= ILO_GEN(7))
858 ilo_cp_submit(hw3d->cp, "texture barrier");
859 }
860
861 static void
862 ilo_get_sample_position(struct pipe_context *pipe,
863 unsigned sample_count,
864 unsigned sample_index,
865 float *out_value)
866 {
867 struct ilo_context *ilo = ilo_context(pipe);
868 struct ilo_3d *hw3d = ilo->hw3d;
869
870 ilo_3d_pipeline_get_sample_position(hw3d->pipeline,
871 sample_count, sample_index,
872 &out_value[0], &out_value[1]);
873 }
874
875 /**
876 * Initialize 3D-related functions.
877 */
878 void
879 ilo_init_3d_functions(struct ilo_context *ilo)
880 {
881 ilo->base.draw_vbo = ilo_draw_vbo;
882 ilo->base.render_condition = ilo_render_condition;
883 ilo->base.texture_barrier = ilo_texture_barrier;
884 ilo->base.get_sample_position = ilo_get_sample_position;
885 }