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 (at) intel.com> 25 * 26 */ 27 28 #include "main/imports.h" 29 #include "main/bufferobj.h" 30 #include "main/varray.h" 31 #include "vbo/vbo.h" 32 33 #include "brw_context.h" 34 #include "brw_defines.h" 35 #include "brw_draw.h" 36 37 #include "intel_batchbuffer.h" 38 39 /** 40 * Check if the hardware's cut index support can handle the primitive 41 * restart index value (pre-Haswell only). 42 */ 43 static bool 44 can_cut_index_handle_restart_index(struct gl_context *ctx, 45 const struct _mesa_index_buffer *ib) 46 { 47 /* The FixedIndex variant means 0xFF, 0xFFFF, or 0xFFFFFFFF based on 48 * the index buffer type, which corresponds exactly to the hardware. 49 */ 50 if (ctx->Array.PrimitiveRestartFixedIndex) 51 return true; 52 53 bool cut_index_will_work; 54 55 switch (ib->type) { 56 case GL_UNSIGNED_BYTE: 57 cut_index_will_work = ctx->Array.RestartIndex == 0xff; 58 break; 59 case GL_UNSIGNED_SHORT: 60 cut_index_will_work = ctx->Array.RestartIndex == 0xffff; 61 break; 62 case GL_UNSIGNED_INT: 63 cut_index_will_work = ctx->Array.RestartIndex == 0xffffffff; 64 break; 65 default: 66 unreachable("not reached"); 67 } 68 69 return cut_index_will_work; 70 } 71 72 /** 73 * Check if the hardware's cut index support can handle the primitive 74 * restart case. 75 */ 76 static bool 77 can_cut_index_handle_prims(struct gl_context *ctx, 78 const struct _mesa_prim *prim, 79 GLuint nr_prims, 80 const struct _mesa_index_buffer *ib) 81 { 82 struct brw_context *brw = brw_context(ctx); 83 84 /* Otherwise Haswell can do it all. */ 85 if (brw->gen >= 8 || brw->is_haswell) 86 return true; 87 88 if (!can_cut_index_handle_restart_index(ctx, ib)) { 89 /* The primitive restart index can't be handled, so take 90 * the software path 91 */ 92 return false; 93 } 94 95 for (unsigned i = 0; i < nr_prims; i++) { 96 switch (prim[i].mode) { 97 case GL_POINTS: 98 case GL_LINES: 99 case GL_LINE_STRIP: 100 case GL_TRIANGLES: 101 case GL_TRIANGLE_STRIP: 102 case GL_LINES_ADJACENCY: 103 case GL_LINE_STRIP_ADJACENCY: 104 case GL_TRIANGLES_ADJACENCY: 105 case GL_TRIANGLE_STRIP_ADJACENCY: 106 /* Cut index supports these primitive types */ 107 break; 108 default: 109 /* Cut index does not support these primitive types */ 110 //case GL_LINE_LOOP: 111 //case GL_TRIANGLE_FAN: 112 //case GL_QUADS: 113 //case GL_QUAD_STRIP: 114 //case GL_POLYGON: 115 return false; 116 } 117 } 118 119 return true; 120 } 121 122 /** 123 * Check if primitive restart is enabled, and if so, handle it properly. 124 * 125 * In some cases the support will be handled in software. When available 126 * hardware will handle primitive restart. 127 */ 128 GLboolean 129 brw_handle_primitive_restart(struct gl_context *ctx, 130 const struct _mesa_prim *prims, 131 GLuint nr_prims, 132 const struct _mesa_index_buffer *ib, 133 struct gl_buffer_object *indirect) 134 { 135 struct brw_context *brw = brw_context(ctx); 136 137 /* We only need to handle cases where there is an index buffer. */ 138 if (ib == NULL) { 139 return GL_FALSE; 140 } 141 142 /* If we have set the in_progress flag, then we are in the middle 143 * of handling the primitive restart draw. 144 */ 145 if (brw->prim_restart.in_progress) { 146 return GL_FALSE; 147 } 148 149 /* If PrimitiveRestart is not enabled, then we aren't concerned about 150 * handling this draw. 151 */ 152 if (!(ctx->Array._PrimitiveRestart)) { 153 return GL_FALSE; 154 } 155 156 /* Signal that we are in the process of handling the 157 * primitive restart draw 158 */ 159 brw->prim_restart.in_progress = true; 160 161 if (can_cut_index_handle_prims(ctx, prims, nr_prims, ib)) { 162 /* Cut index should work for primitive restart, so use it 163 */ 164 brw->prim_restart.enable_cut_index = true; 165 brw_draw_prims(ctx, prims, nr_prims, ib, GL_FALSE, -1, -1, NULL, 0, 166 indirect); 167 brw->prim_restart.enable_cut_index = false; 168 } else { 169 /* Not all the primitive draw modes are supported by the cut index, 170 * so take the software path 171 */ 172 vbo_sw_primitive_restart(ctx, prims, nr_prims, ib, indirect); 173 } 174 175 brw->prim_restart.in_progress = false; 176 177 /* The primitive restart draw was completed, so return true. */ 178 return GL_TRUE; 179 } 180 181 static void 182 haswell_upload_cut_index(struct brw_context *brw) 183 { 184 struct gl_context *ctx = &brw->ctx; 185 186 /* Don't trigger on Ivybridge */ 187 if (brw->gen < 8 && !brw->is_haswell) 188 return; 189 190 const unsigned cut_index_setting = 191 ctx->Array._PrimitiveRestart ? HSW_CUT_INDEX_ENABLE : 0; 192 193 /* BRW_NEW_INDEX_BUFFER */ 194 unsigned cut_index; 195 if (brw->ib.ib) { 196 cut_index = _mesa_primitive_restart_index(ctx, brw->ib.type); 197 } else { 198 /* There's no index buffer, but primitive restart may still apply 199 * to glDrawArrays and such. FIXED_INDEX mode only applies to drawing 200 * operations that use an index buffer, so we can ignore it and use 201 * the GL restart index directly. 202 */ 203 cut_index = ctx->Array.RestartIndex; 204 } 205 206 BEGIN_BATCH(2); 207 OUT_BATCH(_3DSTATE_VF << 16 | cut_index_setting | (2 - 2)); 208 OUT_BATCH(cut_index); 209 ADVANCE_BATCH(); 210 } 211 212 const struct brw_tracked_state haswell_cut_index = { 213 .dirty = { 214 .mesa = _NEW_TRANSFORM, 215 .brw = BRW_NEW_BLORP | 216 BRW_NEW_INDEX_BUFFER, 217 }, 218 .emit = haswell_upload_cut_index, 219 }; 220