1 /*
2 * Copyright © 2012 Intel Corporation
3 *
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 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
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
13 * Software.
14 *
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 NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 * Authors:
24 * Jordan Justen <jordan.l.justen@intel.com>
25 *
26 */
27
28 #include "main/bufferobj.h"
29 #include "main/varray.h"
30 #include "vbo/vbo.h"
31
32 #include "brw_context.h"
33 #include "brw_defines.h"
34 #include "brw_draw.h"
35
36 #include "brw_batch.h"
37
38
39 #define UPDATE_MIN2(a, b) (a) = MIN2((a), (b))
40 #define UPDATE_MAX2(a, b) (a) = MAX2((a), (b))
41
42 /*
43 * Notes on primitive restart:
44 * The code below is used when the driver does not fully support primitive
45 * restart (for example, if it only does restart index of ~0).
46 *
47 * We map the index buffer, find the restart indexes, unmap
48 * the index buffer then draw the sub-primitives delineated by the restarts.
49 *
50 * A couple possible optimizations:
51 * 1. Save the list of sub-primitive (start, count) values in a list attached
52 * to the index buffer for re-use in subsequent draws. The list would be
53 * invalidated when the contents of the buffer changed.
54 * 2. If drawing triangle strips or quad strips, create a new index buffer
55 * that uses duplicated vertices to render the disjoint strips as one
56 * long strip. We'd have to be careful to avoid using too much memory
57 * for this.
58 *
59 * Finally, some apps might perform better if they don't use primitive restart
60 * at all rather than this fallback path. Set MESA_EXTENSION_OVERRIDE to
61 * "-GL_NV_primitive_restart" to test that.
62 */
63
64
65 struct sub_primitive
66 {
67 GLuint start;
68 GLuint count;
69 GLuint min_index;
70 GLuint max_index;
71 };
72
73
74 /**
75 * Scan the elements array to find restart indexes. Return an array
76 * of struct sub_primitive to indicate how to draw the sub-primitives
77 * are delineated by the restart index.
78 */
79 static struct sub_primitive *
find_sub_primitives(const void * elements,unsigned element_size,unsigned start,unsigned end,unsigned restart_index,unsigned * num_sub_prims)80 find_sub_primitives(const void *elements, unsigned element_size,
81 unsigned start, unsigned end, unsigned restart_index,
82 unsigned *num_sub_prims)
83 {
84 const unsigned max_prims = end - start;
85 struct sub_primitive *sub_prims;
86 unsigned i, cur_start, cur_count;
87 GLuint scan_index;
88 unsigned scan_num;
89
90 sub_prims =
91 malloc(max_prims * sizeof(struct sub_primitive));
92
93 if (!sub_prims) {
94 *num_sub_prims = 0;
95 return NULL;
96 }
97
98 cur_start = start;
99 cur_count = 0;
100 scan_num = 0;
101
102 #define IB_INDEX_READ(TYPE, INDEX) (((const GL##TYPE *) elements)[INDEX])
103
104 #define SCAN_ELEMENTS(TYPE) \
105 sub_prims[scan_num].min_index = (GL##TYPE) 0xffffffff; \
106 sub_prims[scan_num].max_index = 0; \
107 for (i = start; i < end; i++) { \
108 scan_index = IB_INDEX_READ(TYPE, i); \
109 if (scan_index == restart_index) { \
110 if (cur_count > 0) { \
111 assert(scan_num < max_prims); \
112 sub_prims[scan_num].start = cur_start; \
113 sub_prims[scan_num].count = cur_count; \
114 scan_num++; \
115 sub_prims[scan_num].min_index = (GL##TYPE) 0xffffffff; \
116 sub_prims[scan_num].max_index = 0; \
117 } \
118 cur_start = i + 1; \
119 cur_count = 0; \
120 } \
121 else { \
122 UPDATE_MIN2(sub_prims[scan_num].min_index, scan_index); \
123 UPDATE_MAX2(sub_prims[scan_num].max_index, scan_index); \
124 cur_count++; \
125 } \
126 } \
127 if (cur_count > 0) { \
128 assert(scan_num < max_prims); \
129 sub_prims[scan_num].start = cur_start; \
130 sub_prims[scan_num].count = cur_count; \
131 scan_num++; \
132 }
133
134 switch (element_size) {
135 case 1:
136 SCAN_ELEMENTS(ubyte);
137 break;
138 case 2:
139 SCAN_ELEMENTS(ushort);
140 break;
141 case 4:
142 SCAN_ELEMENTS(uint);
143 break;
144 default:
145 assert(0 && "bad index_size in find_sub_primitives()");
146 }
147
148 #undef SCAN_ELEMENTS
149
150 *num_sub_prims = scan_num;
151
152 return sub_prims;
153 }
154
155
156 /**
157 * Handle primitive restart in software.
158 *
159 * This function breaks up calls into the driver so primitive restart
160 * support is not required in the driver.
161 */
162 static void
vbo_sw_primitive_restart_common_start(struct gl_context * ctx,const struct _mesa_prim * prims,GLuint nr_prims,const struct _mesa_index_buffer * ib,GLuint num_instances,GLuint base_instance,struct gl_buffer_object * indirect,GLsizeiptr indirect_offset,bool primitive_restart,unsigned restart_index)163 vbo_sw_primitive_restart_common_start(struct gl_context *ctx,
164 const struct _mesa_prim *prims,
165 GLuint nr_prims,
166 const struct _mesa_index_buffer *ib,
167 GLuint num_instances,
168 GLuint base_instance,
169 struct gl_buffer_object *indirect,
170 GLsizeiptr indirect_offset,
171 bool primitive_restart,
172 unsigned restart_index)
173 {
174 GLuint prim_num;
175 struct _mesa_prim new_prim;
176 struct _mesa_index_buffer new_ib;
177 struct sub_primitive *sub_prims;
178 struct sub_primitive *sub_prim;
179 GLuint num_sub_prims;
180 GLuint sub_prim_num;
181 GLuint end_index;
182 GLuint sub_end_index;
183 struct _mesa_prim temp_prim;
184 GLboolean map_ib = ib->obj && !ib->obj->Mappings[MAP_INTERNAL].Pointer;
185 const void *ptr;
186
187 /* If there is an indirect buffer, map it and extract the draw params */
188 if (indirect) {
189 const uint32_t *indirect_params;
190 if (!ctx->Driver.MapBufferRange(ctx, 0, indirect->Size, GL_MAP_READ_BIT,
191 indirect, MAP_INTERNAL)) {
192
193 /* something went wrong with mapping, give up */
194 _mesa_error(ctx, GL_OUT_OF_MEMORY,
195 "failed to map indirect buffer for sw primitive restart");
196 return;
197 }
198
199 assert(nr_prims == 1);
200 new_prim = prims[0];
201 indirect_params = (const uint32_t *)
202 ADD_POINTERS(indirect->Mappings[MAP_INTERNAL].Pointer,
203 indirect_offset);
204
205 new_prim.count = indirect_params[0];
206 new_prim.start = indirect_params[2];
207 new_prim.basevertex = indirect_params[3];
208
209 num_instances = indirect_params[1];
210 base_instance = indirect_params[4];
211
212 new_ib = *ib;
213 new_ib.count = new_prim.count;
214
215 prims = &new_prim;
216 ib = &new_ib;
217
218 ctx->Driver.UnmapBuffer(ctx, indirect, MAP_INTERNAL);
219 }
220
221 /* Find the sub-primitives. These are regions in the index buffer which
222 * are split based on the primitive restart index value.
223 */
224 if (map_ib) {
225 ctx->Driver.MapBufferRange(ctx, 0, ib->obj->Size, GL_MAP_READ_BIT,
226 ib->obj, MAP_INTERNAL);
227 }
228
229 if (ib->obj)
230 ptr = ADD_POINTERS(ib->obj->Mappings[MAP_INTERNAL].Pointer, ib->ptr);
231 else
232 ptr = ib->ptr;
233
234 sub_prims = find_sub_primitives(ptr, 1 << ib->index_size_shift,
235 prims[0].start, prims[0].start + ib->count,
236 restart_index, &num_sub_prims);
237
238 if (map_ib) {
239 ctx->Driver.UnmapBuffer(ctx, ib->obj, MAP_INTERNAL);
240 }
241
242 /* Loop over the primitives, and use the located sub-primitives to draw
243 * each primitive with a break to implement each primitive restart.
244 */
245 for (prim_num = 0; prim_num < nr_prims; prim_num++) {
246 end_index = prims[prim_num].start + prims[prim_num].count;
247 memcpy(&temp_prim, &prims[prim_num], sizeof (temp_prim));
248 /* Loop over the sub-primitives drawing sub-ranges of the primitive. */
249 for (sub_prim_num = 0; sub_prim_num < num_sub_prims; sub_prim_num++) {
250 sub_prim = &sub_prims[sub_prim_num];
251 sub_end_index = sub_prim->start + sub_prim->count;
252 if (prims[prim_num].start <= sub_prim->start) {
253 temp_prim.start = MAX2(prims[prim_num].start, sub_prim->start);
254 temp_prim.count = MIN2(sub_end_index, end_index) - temp_prim.start;
255 if ((temp_prim.start == sub_prim->start) &&
256 (temp_prim.count == sub_prim->count)) {
257 ctx->Driver.Draw(ctx, &temp_prim, 1, ib, true, false, 0,
258 sub_prim->min_index, sub_prim->max_index,
259 num_instances, base_instance);
260 } else {
261 ctx->Driver.Draw(ctx, &temp_prim, 1, ib,
262 false, false, 0, -1, -1,
263 num_instances, base_instance);
264 }
265 }
266 if (sub_end_index >= end_index) {
267 break;
268 }
269 }
270 }
271
272 free(sub_prims);
273 }
274
275 static void
vbo_sw_primitive_restart(struct gl_context * ctx,const struct _mesa_prim * prims,GLuint nr_prims,const struct _mesa_index_buffer * ib,GLuint num_instances,GLuint base_instance,struct gl_buffer_object * indirect,GLsizeiptr indirect_offset,bool primitive_restart,unsigned restart_index)276 vbo_sw_primitive_restart(struct gl_context *ctx,
277 const struct _mesa_prim *prims,
278 GLuint nr_prims,
279 const struct _mesa_index_buffer *ib,
280 GLuint num_instances,
281 GLuint base_instance,
282 struct gl_buffer_object *indirect,
283 GLsizeiptr indirect_offset,
284 bool primitive_restart,
285 unsigned restart_index)
286 {
287 unsigned i;
288 for (i = 1; i < nr_prims; i++) {
289 if (prims[i].start != prims[0].start)
290 break;
291 }
292
293 vbo_sw_primitive_restart_common_start(ctx, &prims[0], i, ib,
294 num_instances, base_instance,
295 indirect, indirect_offset,
296 primitive_restart,
297 restart_index);
298 if (i != nr_prims) {
299 vbo_sw_primitive_restart(ctx, &prims[i], nr_prims - i, ib,
300 num_instances, base_instance,
301 indirect, indirect_offset,
302 primitive_restart,
303 restart_index);
304 }
305 }
306
307 /**
308 * Check if the hardware's cut index support can handle the primitive
309 * restart index value (pre-Haswell only).
310 */
311 static bool
can_cut_index_handle_restart_index(struct gl_context * ctx,const struct _mesa_index_buffer * ib,unsigned restart_index)312 can_cut_index_handle_restart_index(struct gl_context *ctx,
313 const struct _mesa_index_buffer *ib,
314 unsigned restart_index)
315 {
316 /* The FixedIndex variant means 0xFF, 0xFFFF, or 0xFFFFFFFF based on
317 * the index buffer type, which corresponds exactly to the hardware.
318 */
319 if (ctx->Array.PrimitiveRestartFixedIndex)
320 return true;
321
322 bool cut_index_will_work;
323
324 switch (ib->index_size_shift) {
325 case 0:
326 cut_index_will_work = restart_index == 0xff;
327 break;
328 case 1:
329 cut_index_will_work = restart_index == 0xffff;
330 break;
331 case 2:
332 cut_index_will_work = restart_index == 0xffffffff;
333 break;
334 default:
335 unreachable("not reached");
336 }
337
338 return cut_index_will_work;
339 }
340
341 /**
342 * Check if the hardware's cut index support can handle the primitive
343 * restart case.
344 */
345 static bool
can_cut_index_handle_prims(struct gl_context * ctx,const struct _mesa_prim * prim,GLuint nr_prims,const struct _mesa_index_buffer * ib,unsigned restart_index)346 can_cut_index_handle_prims(struct gl_context *ctx,
347 const struct _mesa_prim *prim,
348 GLuint nr_prims,
349 const struct _mesa_index_buffer *ib,
350 unsigned restart_index)
351 {
352 struct brw_context *brw = brw_context(ctx);
353 const struct intel_device_info *devinfo = &brw->screen->devinfo;
354
355 /* Otherwise Haswell can do it all. */
356 if (devinfo->verx10 >= 75)
357 return true;
358
359 if (!can_cut_index_handle_restart_index(ctx, ib, restart_index)) {
360 /* The primitive restart index can't be handled, so take
361 * the software path
362 */
363 return false;
364 }
365
366 for (unsigned i = 0; i < nr_prims; i++) {
367 switch (prim[i].mode) {
368 case GL_POINTS:
369 case GL_LINES:
370 case GL_LINE_STRIP:
371 case GL_TRIANGLES:
372 case GL_TRIANGLE_STRIP:
373 case GL_LINES_ADJACENCY:
374 case GL_LINE_STRIP_ADJACENCY:
375 case GL_TRIANGLES_ADJACENCY:
376 case GL_TRIANGLE_STRIP_ADJACENCY:
377 /* Cut index supports these primitive types */
378 break;
379 default:
380 /* Cut index does not support these primitive types */
381 //case GL_LINE_LOOP:
382 //case GL_TRIANGLE_FAN:
383 //case GL_QUADS:
384 //case GL_QUAD_STRIP:
385 //case GL_POLYGON:
386 return false;
387 }
388 }
389
390 return true;
391 }
392
393 /**
394 * Check if primitive restart is enabled, and if so, handle it properly.
395 *
396 * In some cases the support will be handled in software. When available
397 * hardware will handle primitive restart.
398 */
399 GLboolean
brw_handle_primitive_restart(struct gl_context * ctx,const struct _mesa_prim * prims,GLuint nr_prims,const struct _mesa_index_buffer * ib,GLuint num_instances,GLuint base_instance,bool primitive_restart,unsigned restart_index)400 brw_handle_primitive_restart(struct gl_context *ctx,
401 const struct _mesa_prim *prims,
402 GLuint nr_prims,
403 const struct _mesa_index_buffer *ib,
404 GLuint num_instances, GLuint base_instance,
405 bool primitive_restart,
406 unsigned restart_index)
407 {
408 struct brw_context *brw = brw_context(ctx);
409
410 /* We only need to handle cases where there is an index buffer. */
411 if (ib == NULL) {
412 return GL_FALSE;
413 }
414
415 /* If we have set the in_progress flag, then we are in the middle
416 * of handling the primitive restart draw.
417 */
418 if (brw->prim_restart.in_progress) {
419 return GL_FALSE;
420 }
421
422 /* If PrimitiveRestart is not enabled, then we aren't concerned about
423 * handling this draw.
424 */
425 if (!primitive_restart) {
426 return GL_FALSE;
427 }
428
429 /* Signal that we are in the process of handling the
430 * primitive restart draw
431 */
432 brw->prim_restart.in_progress = true;
433
434 if (can_cut_index_handle_prims(ctx, prims, nr_prims, ib, restart_index)) {
435 /* Cut index should work for primitive restart, so use it
436 */
437 brw->prim_restart.enable_cut_index = true;
438 brw->prim_restart.restart_index = restart_index;
439 brw_draw_prims(ctx, prims, nr_prims, ib, false, primitive_restart,
440 restart_index, -1, -1,
441 num_instances, base_instance);
442 brw->prim_restart.enable_cut_index = false;
443 } else {
444 /* Not all the primitive draw modes are supported by the cut index,
445 * so take the software path
446 */
447 struct gl_buffer_object *indirect_data = brw->draw.draw_indirect_data;
448
449 /* Clear this to make the draw direct. */
450 brw->draw.draw_indirect_data = NULL;
451
452 vbo_sw_primitive_restart(ctx, prims, nr_prims, ib, num_instances,
453 base_instance, indirect_data,
454 brw->draw.draw_indirect_offset,
455 primitive_restart, restart_index);
456 }
457
458 brw->prim_restart.in_progress = false;
459
460 /* The primitive restart draw was completed, so return true. */
461 return GL_TRUE;
462 }
463