brw_draw.c revision 14ec34d64733478b773190cb62be37b7b2871a7f
1/************************************************************************** 2 * 3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28#include <stdlib.h> 29 30#include "glheader.h" 31#include "context.h" 32#include "state.h" 33#include "api_validate.h" 34#include "enums.h" 35 36#include "brw_draw.h" 37#include "brw_defines.h" 38#include "brw_attrib.h" 39#include "brw_context.h" 40#include "brw_aub.h" 41#include "brw_state.h" 42#include "brw_fallback.h" 43 44#include "intel_ioctl.h" 45#include "intel_batchbuffer.h" 46#include "intel_buffer_objects.h" 47 48 49 50 51 52 53static GLuint hw_prim[GL_POLYGON+1] = { 54 _3DPRIM_POINTLIST, 55 _3DPRIM_LINELIST, 56 _3DPRIM_LINELOOP, 57 _3DPRIM_LINESTRIP, 58 _3DPRIM_TRILIST, 59 _3DPRIM_TRISTRIP, 60 _3DPRIM_TRIFAN, 61 _3DPRIM_QUADLIST, 62 _3DPRIM_QUADSTRIP, 63 _3DPRIM_POLYGON 64}; 65 66 67static const GLenum reduced_prim[GL_POLYGON+1] = { 68 GL_POINTS, 69 GL_LINES, 70 GL_LINES, 71 GL_LINES, 72 GL_TRIANGLES, 73 GL_TRIANGLES, 74 GL_TRIANGLES, 75 GL_TRIANGLES, 76 GL_TRIANGLES, 77 GL_TRIANGLES 78}; 79 80 81/* When the primitive changes, set a state bit and re-validate. Not 82 * the nicest and would rather deal with this by having all the 83 * programs be immune to the active primitive (ie. cope with all 84 * possibilities). That may not be realistic however. 85 */ 86static GLuint brw_set_prim(struct brw_context *brw, GLenum prim) 87{ 88 if (INTEL_DEBUG & DEBUG_PRIMS) 89 _mesa_printf("PRIM: %s\n", _mesa_lookup_enum_by_nr(prim)); 90 91 /* Slight optimization to avoid the GS program when not needed: 92 */ 93 if (prim == GL_QUAD_STRIP && 94 brw->attribs.Light->ShadeModel != GL_FLAT && 95 brw->attribs.Polygon->FrontMode == GL_FILL && 96 brw->attribs.Polygon->BackMode == GL_FILL) 97 prim = GL_TRIANGLE_STRIP; 98 99 if (prim != brw->primitive) { 100 brw->primitive = prim; 101 brw->state.dirty.brw |= BRW_NEW_PRIMITIVE; 102 103 if (reduced_prim[prim] != brw->intel.reduced_primitive) { 104 brw->intel.reduced_primitive = reduced_prim[prim]; 105 brw->state.dirty.brw |= BRW_NEW_REDUCED_PRIMITIVE; 106 } 107 108 brw_validate_state(brw); 109 } 110 111 return hw_prim[prim]; 112} 113 114 115static GLuint trim(GLenum prim, GLuint length) 116{ 117 if (prim == GL_QUAD_STRIP) 118 return length > 3 ? (length - length % 2) : 0; 119 else if (prim == GL_QUADS) 120 return length - length % 4; 121 else 122 return length; 123} 124 125 126 127 128static void brw_emit_prim( struct brw_context *brw, 129 const struct brw_draw_prim *prim ) 130 131{ 132 struct brw_3d_primitive prim_packet; 133 134 if (INTEL_DEBUG & DEBUG_PRIMS) 135 _mesa_printf("PRIM: %s %d %d\n", _mesa_lookup_enum_by_nr(prim->mode), 136 prim->start, prim->count); 137 138 prim_packet.header.opcode = CMD_3D_PRIM; 139 prim_packet.header.length = sizeof(prim_packet)/4 - 2; 140 prim_packet.header.pad = 0; 141 prim_packet.header.topology = brw_set_prim(brw, prim->mode); 142 prim_packet.header.indexed = prim->indexed; 143 144 prim_packet.verts_per_instance = trim(prim->mode, prim->count); 145 prim_packet.start_vert_location = prim->start; 146 prim_packet.instance_count = 1; 147 prim_packet.start_instance_location = 0; 148 prim_packet.base_vert_location = 0; 149 150 if (prim_packet.verts_per_instance) { 151 intel_batchbuffer_data( brw->intel.batch, &prim_packet, sizeof(prim_packet), 152 INTEL_BATCH_CLIPRECTS); 153 } 154} 155 156 157 158static void update_current_size( struct gl_client_array *array) 159{ 160 const GLfloat *ptr = (const GLfloat *)array->Ptr; 161 162 assert(array->StrideB == 0); 163 assert(array->Type == GL_FLOAT || array->Type == GL_UNSIGNED_BYTE); 164 165 if (ptr[3] != 1.0) 166 array->Size = 4; 167 else if (ptr[2] != 0.0) 168 array->Size = 3; 169 else if (ptr[1] != 0.0) 170 array->Size = 2; 171 else 172 array->Size = 1; 173} 174 175 176 177/* Fill in any gaps in passed arrays with pointers to current 178 * attributes: 179 */ 180static void brw_merge_inputs( struct brw_context *brw, 181 const struct gl_client_array *arrays[]) 182{ 183 struct gl_client_array *current_values = brw->vb.current_values; 184 struct brw_vertex_element *inputs = brw->vb.inputs; 185 struct brw_vertex_info old = brw->vb.info; 186 GLuint i; 187 188 memset(inputs, 0, sizeof(*inputs)); 189 memset(&brw->vb.info, 0, sizeof(brw->vb.info)); 190 191 for (i = 0; i < BRW_ATTRIB_MAX; i++) { 192 if (arrays[i] && arrays[i]->Enabled) 193 { 194 brw->vb.inputs[i].glarray = arrays[i]; 195 brw->vb.info.varying |= 1 << i; 196 } 197 else 198 { 199 brw->vb.inputs[i].glarray = ¤t_values[i]; 200 update_current_size(¤t_values[i]); 201 } 202 203 brw->vb.info.sizes[i/16] |= (inputs[i].glarray->Size - 1) << ((i%16) * 2); 204 } 205 206 /* Raise statechanges if input sizes and varying have changed: 207 */ 208 if (memcmp(brw->vb.info.sizes, old.sizes, sizeof(old.sizes)) != 0) 209 brw->state.dirty.brw |= BRW_NEW_INPUT_DIMENSIONS; 210 211 if (brw->vb.info.varying != old.varying) 212 brw->state.dirty.brw |= BRW_NEW_INPUT_VARYING; 213} 214 215static GLboolean check_fallbacks( struct brw_context *brw, 216 const struct brw_draw_prim *prim, 217 GLuint nr_prims ) 218{ 219 GLuint i; 220 221 if (!brw->intel.strict_conformance) 222 return GL_FALSE; 223 224 if (brw->attribs.Polygon->SmoothFlag) { 225 for (i = 0; i < nr_prims; i++) 226 if (reduced_prim[prim[i].mode] == GL_TRIANGLES) 227 return GL_TRUE; 228 } 229 230 /* BRW hardware will do AA lines, but they are non-conformant it 231 * seems. TBD whether we keep this fallback: 232 */ 233 if (brw->attribs.Line->SmoothFlag) { 234 for (i = 0; i < nr_prims; i++) 235 if (reduced_prim[prim[i].mode] == GL_LINES) 236 return GL_TRUE; 237 } 238 239 /* Stipple -- these fallbacks could be resolved with a little 240 * bit of work? 241 */ 242 if (brw->attribs.Line->StippleFlag) { 243 for (i = 0; i < nr_prims; i++) { 244 /* GS doesn't get enough information to know when to reset 245 * the stipple counter?!? 246 */ 247 if (prim[i].mode == GL_LINE_LOOP) 248 return GL_TRUE; 249 250 if (prim[i].mode == GL_POLYGON && 251 (brw->attribs.Polygon->FrontMode == GL_LINE || 252 brw->attribs.Polygon->BackMode == GL_LINE)) 253 return GL_TRUE; 254 } 255 } 256 257 258 if (brw->attribs.Point->SmoothFlag) { 259 for (i = 0; i < nr_prims; i++) 260 if (prim[i].mode == GL_POINTS) 261 return GL_TRUE; 262 } 263 264 return GL_FALSE; 265} 266 267 268GLboolean brw_draw_prims( GLcontext *ctx, 269 const struct gl_client_array *arrays[], 270 const struct brw_draw_prim *prim, 271 GLuint nr_prims, 272 const struct brw_draw_index_buffer *ib, 273 GLuint min_index, 274 GLuint max_index, 275 GLuint flags ) 276{ 277 struct intel_context *intel = intel_context(ctx); 278 struct brw_context *brw = brw_context(ctx); 279 GLboolean retval = GL_FALSE; 280 GLuint i; 281 282 if (ctx->NewState) 283 _mesa_update_state( ctx ); 284 285 /* Bind all inputs, derive varying and size information: 286 */ 287 brw_merge_inputs( brw, arrays ); 288 289 /* Have to validate state quite late. Will rebuild tnl_program, 290 * which depends on varying information. 291 * 292 * Note this is where brw->vs->prog_data.inputs_read is calculated, 293 * so can't access it earlier. 294 */ 295 296 LOCK_HARDWARE(intel); 297 { 298 assert(intel->locked); 299 300 /* Set the first primitive early, ahead of validate_state: 301 */ 302 brw_set_prim(brw, prim[0].mode); 303 304 /* XXX: Need to separate validate and upload of state. 305 */ 306 brw_validate_state( brw ); 307 308 /* Various fallback checks: 309 */ 310 if (brw->intel.Fallback) 311 goto out; 312 313 if (check_fallbacks( brw, prim, nr_prims )) 314 goto out; 315 316 /* Upload index, vertex data: 317 */ 318 if (ib) 319 brw_upload_indices( brw, ib ); 320 321 if (!brw_upload_vertices( brw, min_index, max_index)) { 322 goto out; 323 } 324 325 /* Emit prims to batchbuffer: 326 */ 327 for (i = 0; i < nr_prims; i++) { 328 brw_emit_prim(brw, &prim[i]); 329 } 330 331 retval = GL_TRUE; 332 } 333 334 out: 335 336 /* Currently have to do this to synchronize with the map/unmap of 337 * the vertex buffer in brw_exec_api.c. Not sure if there is any 338 * way around this, as not every flush is due to a buffer filling 339 * up. 340 */ 341 intel_batchbuffer_flush( brw->intel.batch ); 342 343 if (intel->thrashing) { 344 bmSetFence(intel); 345 } 346 347 /* Free any old data so it doesn't clog up texture memory - we 348 * won't be referencing it again. 349 */ 350 while (brw->vb.upload.wrap != brw->vb.upload.buf) { 351 ctx->Driver.BufferData(ctx, 352 GL_ARRAY_BUFFER_ARB, 353 BRW_UPLOAD_INIT_SIZE, 354 NULL, 355 GL_DYNAMIC_DRAW_ARB, 356 brw->vb.upload.vbo[brw->vb.upload.wrap]); 357 brw->vb.upload.wrap++; 358 brw->vb.upload.wrap %= BRW_NR_UPLOAD_BUFS; 359 } 360 361 UNLOCK_HARDWARE(intel); 362 return retval; 363} 364 365static void brw_invalidate_vbo_cb( struct intel_context *intel, void *ptr ) 366{ 367 /* nothing to do, we don't rely on the contents being preserved */ 368} 369 370 371void brw_draw_init( struct brw_context *brw ) 372{ 373 GLcontext *ctx = &brw->intel.ctx; 374 GLuint i; 375 376 brw->vb.upload.size = BRW_UPLOAD_INIT_SIZE; 377 378 for (i = 0; i < BRW_NR_UPLOAD_BUFS; i++) { 379 brw->vb.upload.vbo[i] = ctx->Driver.NewBufferObject(ctx, 1, GL_ARRAY_BUFFER_ARB); 380 381 /* XXX: Set these to no-backing-store 382 */ 383 bmBufferSetInvalidateCB(&brw->intel, 384 intel_bufferobj_buffer(intel_buffer_object(brw->vb.upload.vbo[i])), 385 brw_invalidate_vbo_cb, 386 &brw->intel, 387 GL_TRUE); 388 389 } 390 391 ctx->Driver.BufferData( ctx, 392 GL_ARRAY_BUFFER_ARB, 393 BRW_UPLOAD_INIT_SIZE, 394 NULL, 395 GL_DYNAMIC_DRAW_ARB, 396 brw->vb.upload.vbo[0] ); 397 398 399 brw_init_current_values(ctx, brw->vb.current_values); 400} 401 402void brw_draw_destroy( struct brw_context *brw ) 403{ 404 GLcontext *ctx = &brw->intel.ctx; 405 GLuint i; 406 407 for (i = 0; i < BRW_NR_UPLOAD_BUFS; i++) 408 ctx->Driver.DeleteBuffer(ctx, brw->vb.upload.vbo[i]); 409} 410