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 31 #include "brw_context.h" 32 #include "brw_defines.h" 33 #include "brw_draw.h" 34 35 #include "intel_batchbuffer.h" 36 37 /** 38 * Check if the hardware's cut index support can handle the primitive 39 * restart index value. 40 */ 41 static bool 42 can_cut_index_handle_restart_index(struct gl_context *ctx, 43 const struct _mesa_index_buffer *ib) 44 { 45 struct intel_context *intel = intel_context(ctx); 46 47 /* Haswell supports an arbitrary cut index. */ 48 if (intel->is_haswell) 49 return true; 50 51 bool cut_index_will_work; 52 53 switch (ib->type) { 54 case GL_UNSIGNED_BYTE: 55 cut_index_will_work = (ctx->Array.RestartIndex & 0xff) == 0xff; 56 break; 57 case GL_UNSIGNED_SHORT: 58 cut_index_will_work = (ctx->Array.RestartIndex & 0xffff) == 0xffff; 59 break; 60 case GL_UNSIGNED_INT: 61 cut_index_will_work = ctx->Array.RestartIndex == 0xffffffff; 62 break; 63 default: 64 cut_index_will_work = false; 65 assert(0); 66 } 67 68 return cut_index_will_work; 69 } 70 71 /** 72 * Check if the hardware's cut index support can handle the primitive 73 * restart case. 74 */ 75 static bool 76 can_cut_index_handle_prims(struct gl_context *ctx, 77 const struct _mesa_prim *prim, 78 GLuint nr_prims, 79 const struct _mesa_index_buffer *ib) 80 { 81 struct brw_context *brw = brw_context(ctx); 82 83 if (brw->sol.counting_primitives_generated || 84 brw->sol.counting_primitives_written) { 85 /* Counting primitives generated in hardware is not currently 86 * supported, so take the software path. We need to investigate 87 * the *_PRIMITIVES_COUNT registers to allow this to be handled 88 * entirely in hardware. 89 */ 90 return false; 91 } 92 93 if (!can_cut_index_handle_restart_index(ctx, ib)) { 94 /* The primitive restart index can't be handled, so take 95 * the software path 96 */ 97 return false; 98 } 99 100 for ( ; nr_prims > 0; nr_prims--) { 101 switch(prim->mode) { 102 case GL_POINTS: 103 case GL_LINES: 104 case GL_LINE_STRIP: 105 case GL_TRIANGLES: 106 case GL_TRIANGLE_STRIP: 107 /* Cut index supports these primitive types */ 108 break; 109 default: 110 /* Cut index does not support these primitive types */ 111 //case GL_LINE_LOOP: 112 //case GL_TRIANGLE_FAN: 113 //case GL_QUADS: 114 //case GL_QUAD_STRIP: 115 //case GL_POLYGON: 116 return false; 117 } 118 } 119 120 return true; 121 } 122 123 /** 124 * Check if primitive restart is enabled, and if so, handle it properly. 125 * 126 * In some cases the support will be handled in software. When available 127 * hardware will handle primitive restart. 128 */ 129 GLboolean 130 brw_handle_primitive_restart(struct gl_context *ctx, 131 const struct _mesa_prim *prim, 132 GLuint nr_prims, 133 const struct _mesa_index_buffer *ib) 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 the driver has requested software handling of primitive restarts, 143 * then the VBO module has already taken care of things, and we can 144 * just draw as normal. 145 */ 146 if (ctx->Const.PrimitiveRestartInSoftware) { 147 return GL_FALSE; 148 } 149 150 /* If we have set the in_progress flag, then we are in the middle 151 * of handling the primitive restart draw. 152 */ 153 if (brw->prim_restart.in_progress) { 154 return GL_FALSE; 155 } 156 157 /* If PrimitiveRestart is not enabled, then we aren't concerned about 158 * handling this draw. 159 */ 160 if (!(ctx->Array.PrimitiveRestart)) { 161 return GL_FALSE; 162 } 163 164 /* Signal that we are in the process of handling the 165 * primitive restart draw 166 */ 167 brw->prim_restart.in_progress = true; 168 169 if (can_cut_index_handle_prims(ctx, prim, nr_prims, ib)) { 170 /* Cut index should work for primitive restart, so use it 171 */ 172 brw->prim_restart.enable_cut_index = true; 173 brw_draw_prims(ctx, prim, nr_prims, ib, GL_FALSE, -1, -1, NULL); 174 brw->prim_restart.enable_cut_index = false; 175 } else { 176 /* Not all the primitive draw modes are supported by the cut index, 177 * so take the software path 178 */ 179 vbo_sw_primitive_restart(ctx, prim, nr_prims, ib); 180 } 181 182 brw->prim_restart.in_progress = false; 183 184 /* The primitive restart draw was completed, so return true. */ 185 return GL_TRUE; 186 } 187 188 static void 189 haswell_upload_cut_index(struct brw_context *brw) 190 { 191 struct intel_context *intel = &brw->intel; 192 struct gl_context *ctx = &intel->ctx; 193 194 /* Don't trigger on Ivybridge */ 195 if (!intel->is_haswell) 196 return; 197 198 const unsigned cut_index_setting = 199 ctx->Array.PrimitiveRestart ? HSW_CUT_INDEX_ENABLE : 0; 200 201 BEGIN_BATCH(2); 202 OUT_BATCH(_3DSTATE_VF << 16 | cut_index_setting | (2 - 2)); 203 OUT_BATCH(ctx->Array.RestartIndex); 204 ADVANCE_BATCH(); 205 } 206 207 const struct brw_tracked_state haswell_cut_index = { 208 .dirty = { 209 .mesa = _NEW_TRANSFORM, 210 .brw = 0, 211 .cache = 0, 212 }, 213 .emit = haswell_upload_cut_index, 214 }; 215