vbo_exec_draw.c revision e97681c7f551a2a2a6bd5eff0f4192a870c816c0
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.2 4 * 5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 * 24 * Authors: 25 * Keith Whitwell <keith@tungstengraphics.com> 26 */ 27 28#include "main/glheader.h" 29#include "main/bufferobj.h" 30#include "main/context.h" 31#include "main/enums.h" 32#include "main/state.h" 33#include "main/macros.h" 34 35#include "vbo_context.h" 36 37 38static void vbo_exec_debug_verts( struct vbo_exec_context *exec ) 39{ 40 GLuint count = exec->vtx.vert_count; 41 GLuint i; 42 43 _mesa_printf("%s: %u vertices %d primitives, %d vertsize\n", 44 __FUNCTION__, 45 count, 46 exec->vtx.prim_count, 47 exec->vtx.vertex_size); 48 49 for (i = 0 ; i < exec->vtx.prim_count ; i++) { 50 struct _mesa_prim *prim = &exec->vtx.prim[i]; 51 _mesa_printf(" prim %d: %s%s %d..%d %s %s\n", 52 i, 53 _mesa_lookup_enum_by_nr(prim->mode), 54 prim->weak ? " (weak)" : "", 55 prim->start, 56 prim->start + prim->count, 57 prim->begin ? "BEGIN" : "(wrap)", 58 prim->end ? "END" : "(wrap)"); 59 } 60} 61 62 63/* 64 * NOTE: Need to have calculated primitives by this point -- do it on the fly. 65 * NOTE: Old 'parity' issue is gone. 66 */ 67static GLuint vbo_copy_vertices( struct vbo_exec_context *exec ) 68{ 69 GLuint nr = exec->vtx.prim[exec->vtx.prim_count-1].count; 70 GLuint ovf, i; 71 GLuint sz = exec->vtx.vertex_size; 72 GLfloat *dst = exec->vtx.copied.buffer; 73 GLfloat *src = ((GLfloat *)exec->vtx.buffer_map + 74 exec->vtx.prim[exec->vtx.prim_count-1].start * 75 exec->vtx.vertex_size); 76 77 78 switch( exec->ctx->Driver.CurrentExecPrimitive ) 79 { 80 case GL_POINTS: 81 return 0; 82 case GL_LINES: 83 ovf = nr&1; 84 for (i = 0 ; i < ovf ; i++) 85 _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) ); 86 return i; 87 case GL_TRIANGLES: 88 ovf = nr%3; 89 for (i = 0 ; i < ovf ; i++) 90 _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) ); 91 return i; 92 case GL_QUADS: 93 ovf = nr&3; 94 for (i = 0 ; i < ovf ; i++) 95 _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) ); 96 return i; 97 case GL_LINE_STRIP: 98 if (nr == 0) 99 return 0; 100 else { 101 _mesa_memcpy( dst, src+(nr-1)*sz, sz * sizeof(GLfloat) ); 102 return 1; 103 } 104 case GL_LINE_LOOP: 105 case GL_TRIANGLE_FAN: 106 case GL_POLYGON: 107 if (nr == 0) 108 return 0; 109 else if (nr == 1) { 110 _mesa_memcpy( dst, src+0, sz * sizeof(GLfloat) ); 111 return 1; 112 } else { 113 _mesa_memcpy( dst, src+0, sz * sizeof(GLfloat) ); 114 _mesa_memcpy( dst+sz, src+(nr-1)*sz, sz * sizeof(GLfloat) ); 115 return 2; 116 } 117 case GL_TRIANGLE_STRIP: 118 /* no parity issue, but need to make sure the tri is not drawn twice */ 119 if (nr & 1) { 120 exec->vtx.prim[exec->vtx.prim_count-1].count--; 121 } 122 /* fallthrough */ 123 case GL_QUAD_STRIP: 124 switch (nr) { 125 case 0: ovf = 0; break; 126 case 1: ovf = 1; break; 127 default: ovf = 2 + (nr&1); break; 128 } 129 for (i = 0 ; i < ovf ; i++) 130 _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) ); 131 return i; 132 case PRIM_OUTSIDE_BEGIN_END: 133 return 0; 134 default: 135 assert(0); 136 return 0; 137 } 138} 139 140 141 142/* TODO: populate these as the vertex is defined: 143 */ 144static void vbo_exec_bind_arrays( GLcontext *ctx ) 145{ 146 struct vbo_context *vbo = vbo_context(ctx); 147 struct vbo_exec_context *exec = &vbo->exec; 148 struct gl_client_array *arrays = exec->vtx.arrays; 149 GLuint count = exec->vtx.vert_count; 150 GLubyte *data = exec->vtx.buffer_map; 151 const GLuint *map; 152 GLuint attr; 153 GLbitfield varying_inputs = 0x0; 154 155 /* Install the default (ie Current) attributes first, then overlay 156 * all active ones. 157 */ 158 switch (get_program_mode(exec->ctx)) { 159 case VP_NONE: 160 for (attr = 0; attr < 16; attr++) { 161 exec->vtx.inputs[attr] = &vbo->legacy_currval[attr]; 162 } 163 for (attr = 0; attr < MAT_ATTRIB_MAX; attr++) { 164 exec->vtx.inputs[attr + 16] = &vbo->mat_currval[attr]; 165 } 166 map = vbo->map_vp_none; 167 break; 168 case VP_NV: 169 case VP_ARB: 170 /* The aliasing of attributes for NV vertex programs has already 171 * occurred. NV vertex programs cannot access material values, 172 * nor attributes greater than VERT_ATTRIB_TEX7. 173 */ 174 for (attr = 0; attr < 16; attr++) { 175 exec->vtx.inputs[attr] = &vbo->legacy_currval[attr]; 176 exec->vtx.inputs[attr + 16] = &vbo->generic_currval[attr]; 177 } 178 map = vbo->map_vp_arb; 179 180 /* check if VERT_ATTRIB_POS is not read but VERT_BIT_GENERIC0 is read. 181 * In that case we effectively need to route the data from 182 * glVertexAttrib(0, val) calls to feed into the GENERIC0 input. 183 */ 184 if ((ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_POS) == 0 && 185 (ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_GENERIC0)) { 186 exec->vtx.inputs[16] = exec->vtx.inputs[0]; 187 exec->vtx.attrsz[16] = exec->vtx.attrsz[0]; 188 exec->vtx.attrsz[0] = 0; 189 } 190 break; 191 default: 192 assert(0); 193 } 194 195 /* Make all active attributes (including edgeflag) available as 196 * arrays of floats. 197 */ 198 for (attr = 0; attr < VERT_ATTRIB_MAX ; attr++) { 199 const GLuint src = map[attr]; 200 201 if (exec->vtx.attrsz[src]) { 202 /* override the default array set above */ 203 exec->vtx.inputs[attr] = &arrays[attr]; 204 205 if (exec->vtx.bufferobj->Name) { 206 /* a real buffer obj: Ptr is an offset, not a pointer*/ 207 int offset; 208 assert(exec->vtx.bufferobj->Pointer); /* buf should be mapped */ 209 offset = (GLbyte *) data - (GLbyte *) exec->vtx.bufferobj->Pointer; 210 assert(offset >= 0); 211 arrays[attr].Ptr = (void *) offset; 212 } 213 else { 214 /* Ptr into ordinary app memory */ 215 arrays[attr].Ptr = (void *) data; 216 } 217 arrays[attr].Size = exec->vtx.attrsz[src]; 218 arrays[attr].StrideB = exec->vtx.vertex_size * sizeof(GLfloat); 219 arrays[attr].Stride = exec->vtx.vertex_size * sizeof(GLfloat); 220 arrays[attr].Type = GL_FLOAT; 221 arrays[attr].Format = GL_RGBA; 222 arrays[attr].Enabled = 1; 223 _mesa_reference_buffer_object(ctx, 224 &arrays[attr].BufferObj, 225 exec->vtx.bufferobj); 226 arrays[attr]._MaxElement = count; /* ??? */ 227 228 data += exec->vtx.attrsz[src] * sizeof(GLfloat); 229 varying_inputs |= 1<<attr; 230 } 231 } 232 233 _mesa_set_varying_vp_inputs( ctx, varying_inputs ); 234} 235 236 237/** 238 * Execute the buffer and save copied verts. 239 */ 240void vbo_exec_vtx_flush( struct vbo_exec_context *exec ) 241{ 242 if (0) 243 vbo_exec_debug_verts( exec ); 244 245 246 if (exec->vtx.prim_count && 247 exec->vtx.vert_count) { 248 249 exec->vtx.copied.nr = vbo_copy_vertices( exec ); 250 251 if (exec->vtx.copied.nr != exec->vtx.vert_count) { 252 GLcontext *ctx = exec->ctx; 253 254 GLenum target = GL_ARRAY_BUFFER_ARB; 255 GLenum access = GL_READ_WRITE_ARB; 256 GLenum usage = GL_STREAM_DRAW_ARB; 257 GLsizei size = VBO_VERT_BUFFER_SIZE * sizeof(GLfloat); 258 259 /* Before the unmap (why?) 260 */ 261 vbo_exec_bind_arrays( ctx ); 262 263 if (ctx->NewState) 264 _mesa_update_state( ctx ); 265 266 /* if using a real VBO, unmap it before drawing */ 267 if (exec->vtx.bufferobj->Name) { 268 ctx->Driver.UnmapBuffer(ctx, target, exec->vtx.bufferobj); 269 exec->vtx.buffer_map = NULL; 270 } 271 272 vbo_context(ctx)->draw_prims( ctx, 273 exec->vtx.inputs, 274 exec->vtx.prim, 275 exec->vtx.prim_count, 276 NULL, 277 0, 278 exec->vtx.vert_count - 1); 279 280 /* If using a real VBO, get new storage */ 281 if (exec->vtx.bufferobj->Name) { 282 ctx->Driver.BufferData(ctx, target, size, NULL, usage, exec->vtx.bufferobj); 283 exec->vtx.buffer_map = 284 ctx->Driver.MapBuffer(ctx, target, access, exec->vtx.bufferobj); 285 } 286 } 287 } 288 289 exec->vtx.prim_count = 0; 290 exec->vtx.vert_count = 0; 291 exec->vtx.vbptr = (GLfloat *)exec->vtx.buffer_map; 292} 293