t_draw.c revision 9827dc8bea422b940f1efcfbd1c0d76f8bbca844
1 2/* 3 * Mesa 3-D graphics library 4 * Version: 6.5 5 * 6 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the "Software"), 10 * to deal in the Software without restriction, including without limitation 11 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 * and/or sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included 16 * in all copies or substantial portions 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 MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 * 25 * Authors: 26 * Keith Whitwell <keith@tungstengraphics.com> 27 */ 28 29#include "glheader.h" 30#include "context.h" 31#include "imports.h" 32#include "state.h" 33#include "mtypes.h" 34#include "macros.h" 35 36#include "t_context.h" 37#include "t_pipeline.h" 38#include "t_vp_build.h" 39#include "t_vertex.h" 40#include "tnl.h" 41 42 43 44static GLfloat *get_space(GLcontext *ctx, GLuint bytes) 45{ 46 TNLcontext *tnl = TNL_CONTEXT(ctx); 47 GLubyte *space = _mesa_malloc(bytes); 48 49 tnl->block[tnl->nr_blocks++] = space; 50 return (GLfloat *)space; 51} 52 53 54static void free_space(GLcontext *ctx) 55{ 56 TNLcontext *tnl = TNL_CONTEXT(ctx); 57 GLuint i; 58 for (i = 0; i < tnl->nr_blocks; i++) 59 _mesa_free(tnl->block[i]); 60 tnl->nr_blocks = 0; 61} 62 63 64/* Convert the incoming array to GLfloats. Understands the 65 * array->Normalized flag and selects the correct conversion method. 66 */ 67#define CONVERT( TYPE, MACRO ) do { \ 68 GLuint i, j; \ 69 if (input->Normalized) { \ 70 for (i = 0; i < count; i++) { \ 71 const TYPE *in = (TYPE *)ptr; \ 72 for (j = 0; j < sz; j++) { \ 73 *fptr++ = MACRO(*in); \ 74 in++; \ 75 } \ 76 ptr += input->StrideB; \ 77 } \ 78 } else { \ 79 for (i = 0; i < count; i++) { \ 80 const TYPE *in = (TYPE *)ptr; \ 81 for (j = 0; j < sz; j++) { \ 82 *fptr++ = (GLfloat)(*in); \ 83 in++; \ 84 } \ 85 ptr += input->StrideB; \ 86 } \ 87 } \ 88} while (0) 89 90 91 92/* Adjust pointer to point at first requested element, convert to 93 * floating point, populate VB->AttribPtr[]. 94 */ 95static void _tnl_import_array( GLcontext *ctx, 96 GLuint attrib, 97 GLuint start, 98 GLuint end, 99 const struct gl_client_array *input, 100 const char *ptr ) 101{ 102 TNLcontext *tnl = TNL_CONTEXT(ctx); 103 struct vertex_buffer *VB = &tnl->vb; 104 const GLuint count = end - start; 105 GLuint stride = input->StrideB; 106 107 ptr += start * stride; 108 109 if (input->Type != GL_FLOAT) { 110 const GLuint sz = input->Size; 111 GLfloat *fptr = get_space(ctx, count * sz * sizeof(GLfloat)); 112 113 switch (input->Type) { 114 case GL_BYTE: 115 CONVERT(GLbyte, BYTE_TO_FLOAT); 116 break; 117 case GL_UNSIGNED_BYTE: 118 CONVERT(GLubyte, UBYTE_TO_FLOAT); 119 break; 120 case GL_SHORT: 121 CONVERT(GLshort, SHORT_TO_FLOAT); 122 break; 123 case GL_UNSIGNED_SHORT: 124 CONVERT(GLushort, USHORT_TO_FLOAT); 125 break; 126 case GL_INT: 127 CONVERT(GLint, INT_TO_FLOAT); 128 break; 129 case GL_UNSIGNED_INT: 130 CONVERT(GLuint, UINT_TO_FLOAT); 131 break; 132 case GL_DOUBLE: 133 CONVERT(GLdouble, (GLfloat)); 134 break; 135 default: 136 assert(0); 137 break; 138 } 139 140 ptr = (const char *)fptr; 141 stride = sz * sizeof(GLfloat); 142 } 143 144 VB->AttribPtr[attrib] = &tnl->tmp_inputs[attrib]; 145 VB->AttribPtr[attrib]->data = (GLfloat (*)[4])ptr; 146 VB->AttribPtr[attrib]->start = (GLfloat *)ptr; 147 VB->AttribPtr[attrib]->count = count; 148 VB->AttribPtr[attrib]->stride = stride; 149 VB->AttribPtr[attrib]->size = input->Size; 150 151 /* This should die, but so should the whole GLvector4f concept: 152 */ 153 VB->AttribPtr[attrib]->flags = (((1<<input->Size)-1) | 154 VEC_NOT_WRITEABLE | 155 (stride == 4*sizeof(GLfloat) ? 0 : VEC_BAD_STRIDE)); 156 157 VB->AttribPtr[attrib]->storage = NULL; 158} 159 160#define CLIPVERTS ((6 + MAX_CLIP_PLANES) * 2) 161 162 163static GLboolean *_tnl_import_edgeflag( GLcontext *ctx, 164 const GLvector4f *input, 165 GLuint count) 166{ 167 const GLubyte *ptr = (const GLubyte *)input->data; 168 const GLuint stride = input->stride; 169 GLboolean *space = (GLboolean *)get_space(ctx, count + CLIPVERTS); 170 GLboolean *bptr = space; 171 GLuint i; 172 173 for (i = 0; i < count; i++) { 174 *bptr++ = ((GLfloat *)ptr)[0] == 1.0; 175 ptr += stride; 176 } 177 178 return space; 179} 180 181 182static void bind_inputs( GLcontext *ctx, 183 const struct gl_client_array *inputs[], 184 GLint start, GLint end, 185 struct gl_buffer_object **bo, 186 GLuint *nr_bo ) 187{ 188 TNLcontext *tnl = TNL_CONTEXT(ctx); 189 struct vertex_buffer *VB = &tnl->vb; 190 GLuint i; 191 192 /* Map all the VBOs 193 */ 194 for (i = 0; i < VERT_ATTRIB_MAX; i++) { 195 const void *ptr; 196 197 if (inputs[i]->BufferObj->Name) { 198 if (!inputs[i]->BufferObj->Pointer) { 199 bo[*nr_bo] = inputs[i]->BufferObj; 200 *nr_bo++; 201 ctx->Driver.MapBuffer(ctx, 202 GL_ARRAY_BUFFER, 203 GL_READ_ONLY_ARB, 204 inputs[i]->BufferObj); 205 206 assert(inputs[i]->BufferObj->Pointer); 207 } 208 209 ptr = ADD_POINTERS(inputs[i]->BufferObj->Pointer, 210 inputs[i]->Ptr); 211 } 212 else 213 ptr = inputs[i]->Ptr; 214 215 /* Just make sure the array is floating point, otherwise convert to 216 * temporary storage. Rebase arrays so that 'start' becomes 217 * element zero. 218 * 219 * XXX: remove the GLvector4f type at some stage and just use 220 * client arrays. 221 */ 222 _tnl_import_array(ctx, i, start, end, inputs[i], ptr); 223 } 224 225 /* Legacy pointers -- remove one day. 226 */ 227 VB->ObjPtr = VB->AttribPtr[_TNL_ATTRIB_POS]; 228 VB->NormalPtr = VB->AttribPtr[_TNL_ATTRIB_NORMAL]; 229 VB->ColorPtr[0] = VB->AttribPtr[_TNL_ATTRIB_COLOR0]; 230 VB->ColorPtr[1] = NULL; 231 VB->IndexPtr[0] = VB->AttribPtr[_TNL_ATTRIB_COLOR_INDEX]; 232 VB->IndexPtr[1] = NULL; 233 VB->SecondaryColorPtr[0] = VB->AttribPtr[_TNL_ATTRIB_COLOR1]; 234 VB->SecondaryColorPtr[1] = NULL; 235 VB->FogCoordPtr = VB->AttribPtr[_TNL_ATTRIB_FOG]; 236 237 for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) { 238 VB->TexCoordPtr[i] = VB->AttribPtr[_TNL_ATTRIB_TEX0 + i]; 239 } 240 241 /* Clipping and drawing code still requires this to be a packed 242 * array of ubytes which can be written into. TODO: Fix and 243 * remove. 244 */ 245 if (ctx->Polygon.FrontMode != GL_FILL || 246 ctx->Polygon.BackMode != GL_FILL) 247 { 248 VB->EdgeFlag = _tnl_import_edgeflag( ctx, 249 VB->AttribPtr[_TNL_ATTRIB_EDGEFLAG], 250 VB->Count ); 251 } 252 253} 254 255 256/* Translate indices to GLuints and store in VB->Elts. 257 */ 258static void bind_indicies( GLcontext *ctx, 259 const struct _mesa_index_buffer *ib, 260 struct gl_buffer_object **bo, 261 GLuint *nr_bo) 262{ 263 TNLcontext *tnl = TNL_CONTEXT(ctx); 264 struct vertex_buffer *VB = &tnl->vb; 265 266 if (!ib) 267 return; 268 269 if (ib->obj->Name && !ib->obj->Pointer) { 270 bo[*nr_bo] = ib->obj; 271 *nr_bo++; 272 ctx->Driver.MapBuffer(ctx, 273 GL_ELEMENT_ARRAY_BUFFER, 274 GL_READ_ONLY_ARB, 275 ib->obj); 276 277 assert(ib->obj->Pointer); 278 } 279 280 VB->Elts = (GLuint *)ADD_POINTERS(ib->obj->Pointer, 281 ib->ptr); 282 283 VB->Elts += ib->rebase; 284 285 switch (ib->type) { 286 case GL_UNSIGNED_INT: 287 return; 288 case GL_UNSIGNED_SHORT: 289 break; 290 case GL_UNSIGNED_BYTE: 291 break; 292 } 293} 294 295static void unmap_vbos( GLcontext *ctx, 296 struct gl_buffer_object **bo, 297 GLuint nr_bo ) 298{ 299 GLuint i; 300 for (i = 0; i < nr_bo; i++) { 301 ctx->Driver.UnmapBuffer(ctx, 302 0, /* target -- I don't see why this would be needed */ 303 bo[i]); 304 } 305} 306 307 308 309/* This is the main entrypoint into the slimmed-down software tnl 310 * module. In a regular swtnl driver, this can be plugged straight 311 * into the vbo->Driver.DrawPrims() callback. 312 */ 313void _tnl_draw_prims( GLcontext *ctx, 314 const struct gl_client_array *arrays[], 315 const struct _mesa_prim *prim, 316 GLuint nr_prims, 317 const struct _mesa_index_buffer *ib, 318 GLuint min_index, 319 GLuint max_index) 320{ 321 TNLcontext *tnl = TNL_CONTEXT(ctx); 322 struct vertex_buffer *VB = &tnl->vb; 323 324 /* May need to map a vertex buffer object for every attribute plus 325 * one for the index buffer. 326 */ 327 struct gl_buffer_object *bo[VERT_ATTRIB_MAX + 1]; 328 GLuint nr_bo = 0; 329 330 /* Binding inputs may imply mapping some vertex buffer objects. 331 * They will need to be unmapped below. 332 */ 333 bind_inputs(ctx, arrays, min_index, max_index, bo, &nr_bo); 334 bind_indicies(ctx, ib, bo, &nr_bo); 335 336 VB->Primitive = prim; 337 VB->PrimitiveCount = nr_prims; 338 VB->Count = max_index - min_index; 339 340 TNL_CONTEXT(ctx)->Driver.RunPipeline(ctx); 341 342 unmap_vbos(ctx, bo, nr_bo); 343 free_space(ctx); 344} 345 346