t_draw.c revision c1f859d4
1/*
2 * Mesa 3-D graphics library
3 * Version:  7.1
4 *
5 * Copyright (C) 1999-2007  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/context.h"
30#include "main/imports.h"
31#include "main/state.h"
32#include "main/mtypes.h"
33#include "main/macros.h"
34#include "main/enums.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 GLubyte *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 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 count,
98			       const struct gl_client_array *input,
99			       const GLubyte *ptr )
100{
101   TNLcontext *tnl = TNL_CONTEXT(ctx);
102   struct vertex_buffer *VB = &tnl->vb;
103   GLuint stride = input->StrideB;
104
105   if (input->Type != GL_FLOAT) {
106      const GLuint sz = input->Size;
107      GLubyte *buf = get_space(ctx, count * sz * sizeof(GLfloat));
108      GLfloat *fptr = (GLfloat *)buf;
109
110      switch (input->Type) {
111      case GL_BYTE:
112	 CONVERT(GLbyte, BYTE_TO_FLOAT);
113	 break;
114      case GL_UNSIGNED_BYTE:
115	 CONVERT(GLubyte, UBYTE_TO_FLOAT);
116	 break;
117      case GL_SHORT:
118	 CONVERT(GLshort, SHORT_TO_FLOAT);
119	 break;
120      case GL_UNSIGNED_SHORT:
121	 CONVERT(GLushort, USHORT_TO_FLOAT);
122	 break;
123      case GL_INT:
124	 CONVERT(GLint, INT_TO_FLOAT);
125	 break;
126      case GL_UNSIGNED_INT:
127	 CONVERT(GLuint, UINT_TO_FLOAT);
128	 break;
129      case GL_DOUBLE:
130	 CONVERT(GLdouble, (GLfloat));
131	 break;
132      default:
133	 assert(0);
134	 break;
135      }
136
137      ptr = buf;
138      stride = sz * sizeof(GLfloat);
139   }
140
141   VB->AttribPtr[attrib] = &tnl->tmp_inputs[attrib];
142   VB->AttribPtr[attrib]->data = (GLfloat (*)[4])ptr;
143   VB->AttribPtr[attrib]->start = (GLfloat *)ptr;
144   VB->AttribPtr[attrib]->count = count;
145   VB->AttribPtr[attrib]->stride = stride;
146   VB->AttribPtr[attrib]->size = input->Size;
147
148   /* This should die, but so should the whole GLvector4f concept:
149    */
150   VB->AttribPtr[attrib]->flags = (((1<<input->Size)-1) |
151				   VEC_NOT_WRITEABLE |
152				   (stride == 4*sizeof(GLfloat) ? 0 : VEC_BAD_STRIDE));
153
154   VB->AttribPtr[attrib]->storage = NULL;
155}
156
157#define CLIPVERTS  ((6 + MAX_CLIP_PLANES) * 2)
158
159
160static GLboolean *_tnl_import_edgeflag( GLcontext *ctx,
161					const GLvector4f *input,
162					GLuint count)
163{
164   const GLubyte *ptr = (const GLubyte *)input->data;
165   const GLuint stride = input->stride;
166   GLboolean *space = (GLboolean *)get_space(ctx, count + CLIPVERTS);
167   GLboolean *bptr = space;
168   GLuint i;
169
170   for (i = 0; i < count; i++) {
171      *bptr++ = ((GLfloat *)ptr)[0] == 1.0;
172      ptr += stride;
173   }
174
175   return space;
176}
177
178
179static void bind_inputs( GLcontext *ctx,
180			 const struct gl_client_array *inputs[],
181			 GLint count,
182			 struct gl_buffer_object **bo,
183			 GLuint *nr_bo )
184{
185   TNLcontext *tnl = TNL_CONTEXT(ctx);
186   struct vertex_buffer *VB = &tnl->vb;
187   GLuint i;
188
189   /* Map all the VBOs
190    */
191   for (i = 0; i < VERT_ATTRIB_MAX; i++) {
192      const void *ptr;
193
194      if (inputs[i]->BufferObj->Name) {
195	 if (!inputs[i]->BufferObj->Pointer) {
196	    bo[*nr_bo] = inputs[i]->BufferObj;
197	    (*nr_bo)++;
198	    ctx->Driver.MapBuffer(ctx,
199				  GL_ARRAY_BUFFER,
200				  GL_READ_ONLY_ARB,
201				  inputs[i]->BufferObj);
202
203	    assert(inputs[i]->BufferObj->Pointer);
204	 }
205
206	 ptr = ADD_POINTERS(inputs[i]->BufferObj->Pointer,
207			    inputs[i]->Ptr);
208      }
209      else
210	 ptr = inputs[i]->Ptr;
211
212      /* Just make sure the array is floating point, otherwise convert to
213       * temporary storage.
214       *
215       * XXX: remove the GLvector4f type at some stage and just use
216       * client arrays.
217       */
218      _tnl_import_array(ctx, i, count, inputs[i], ptr);
219   }
220
221   /* We process only the vertices between min & max index:
222    */
223   VB->Count = count;
224
225
226   /* Legacy pointers -- remove one day.
227    */
228   VB->ObjPtr = VB->AttribPtr[_TNL_ATTRIB_POS];
229   VB->NormalPtr = VB->AttribPtr[_TNL_ATTRIB_NORMAL];
230   VB->ColorPtr[0] = VB->AttribPtr[_TNL_ATTRIB_COLOR0];
231   VB->ColorPtr[1] = NULL;
232   VB->IndexPtr[0] = VB->AttribPtr[_TNL_ATTRIB_COLOR_INDEX];
233   VB->IndexPtr[1] = NULL;
234   VB->SecondaryColorPtr[0] = VB->AttribPtr[_TNL_ATTRIB_COLOR1];
235   VB->SecondaryColorPtr[1] = NULL;
236   VB->FogCoordPtr = VB->AttribPtr[_TNL_ATTRIB_FOG];
237
238   for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) {
239      VB->TexCoordPtr[i] = VB->AttribPtr[_TNL_ATTRIB_TEX0 + i];
240   }
241
242   /* Clipping and drawing code still requires this to be a packed
243    * array of ubytes which can be written into.  TODO: Fix and
244    * remove.
245    */
246   if (ctx->Polygon.FrontMode != GL_FILL ||
247       ctx->Polygon.BackMode != GL_FILL)
248   {
249      VB->EdgeFlag = _tnl_import_edgeflag( ctx,
250					   VB->AttribPtr[_TNL_ATTRIB_EDGEFLAG],
251					   VB->Count );
252   }
253   else {
254      /* the data previously pointed to by EdgeFlag may have been freed */
255      VB->EdgeFlag = NULL;
256   }
257}
258
259
260/* Translate indices to GLuints and store in VB->Elts.
261 */
262static void bind_indices( GLcontext *ctx,
263			  const struct _mesa_index_buffer *ib,
264			  struct gl_buffer_object **bo,
265			  GLuint *nr_bo)
266{
267   TNLcontext *tnl = TNL_CONTEXT(ctx);
268   struct vertex_buffer *VB = &tnl->vb;
269   GLuint i;
270   void *ptr;
271
272   if (!ib) {
273      VB->Elts = NULL;
274      return;
275   }
276
277   if (ib->obj->Name && !ib->obj->Pointer) {
278      bo[*nr_bo] = ib->obj;
279      (*nr_bo)++;
280      ctx->Driver.MapBuffer(ctx,
281			    GL_ELEMENT_ARRAY_BUFFER,
282			    GL_READ_ONLY_ARB,
283			    ib->obj);
284
285      assert(ib->obj->Pointer);
286   }
287
288   ptr = ADD_POINTERS(ib->obj->Pointer, ib->ptr);
289
290   if (ib->type == GL_UNSIGNED_INT) {
291      VB->Elts = (GLuint *) ptr;
292   }
293   else {
294      GLuint *elts = (GLuint *)get_space(ctx, ib->count * sizeof(GLuint));
295      VB->Elts = elts;
296
297      if (ib->type == GL_UNSIGNED_SHORT) {
298	 const GLushort *in = (GLushort *)ptr;
299	 for (i = 0; i < ib->count; i++)
300	    *elts++ = (GLuint)(*in++);
301      }
302      else {
303	 const GLubyte *in = (GLubyte *)ptr;
304	 for (i = 0; i < ib->count; i++)
305	    *elts++ = (GLuint)(*in++);
306      }
307   }
308}
309
310static void bind_prims( GLcontext *ctx,
311			const struct _mesa_prim *prim,
312			GLuint nr_prims )
313{
314   TNLcontext *tnl = TNL_CONTEXT(ctx);
315   struct vertex_buffer *VB = &tnl->vb;
316
317   VB->Primitive = prim;
318   VB->PrimitiveCount = nr_prims;
319}
320
321static void unmap_vbos( GLcontext *ctx,
322			struct gl_buffer_object **bo,
323			GLuint nr_bo )
324{
325   GLuint i;
326   for (i = 0; i < nr_bo; i++) {
327      ctx->Driver.UnmapBuffer(ctx,
328			      0, /* target -- I don't see why this would be needed */
329			      bo[i]);
330   }
331}
332
333
334
335/* This is the main entrypoint into the slimmed-down software tnl
336 * module.  In a regular swtnl driver, this can be plugged straight
337 * into the vbo->Driver.DrawPrims() callback.
338 */
339void _tnl_draw_prims( GLcontext *ctx,
340		      const struct gl_client_array *arrays[],
341		      const struct _mesa_prim *prim,
342		      GLuint nr_prims,
343		      const struct _mesa_index_buffer *ib,
344		      GLuint min_index,
345		      GLuint max_index)
346{
347   TNLcontext *tnl = TNL_CONTEXT(ctx);
348   const GLuint TEST_SPLIT = 0;
349   const GLint max = TEST_SPLIT ? 8 : tnl->vb.Size - MAX_CLIPPED_VERTICES;
350
351   if (0)
352   {
353      GLuint i;
354      _mesa_printf("%s %d..%d\n", __FUNCTION__, min_index, max_index);
355      for (i = 0; i < nr_prims; i++)
356	 _mesa_printf("prim %d: %s start %d count %d\n", i,
357		      _mesa_lookup_enum_by_nr(prim[i].mode),
358		      prim[i].start,
359		      prim[i].count);
360   }
361
362   if (min_index) {
363      /* We always translate away calls with min_index != 0.
364       */
365      vbo_rebase_prims( ctx, arrays, prim, nr_prims, ib,
366			min_index, max_index,
367			_tnl_draw_prims );
368      return;
369   }
370   else if (max_index > max) {
371      /* The software TNL pipeline has a fixed amount of storage for
372       * vertices and it is necessary to split incoming drawing commands
373       * if they exceed that limit.
374       */
375      struct split_limits limits;
376      limits.max_verts = max;
377      limits.max_vb_size = ~0;
378      limits.max_indices = ~0;
379
380      /* This will split the buffers one way or another and
381       * recursively call back into this function.
382       */
383      vbo_split_prims( ctx, arrays, prim, nr_prims, ib,
384		       0, max_index,
385		       _tnl_draw_prims,
386		       &limits );
387   }
388   else {
389      /* May need to map a vertex buffer object for every attribute plus
390       * one for the index buffer.
391       */
392      struct gl_buffer_object *bo[VERT_ATTRIB_MAX + 1];
393      GLuint nr_bo = 0;
394
395      /* Binding inputs may imply mapping some vertex buffer objects.
396       * They will need to be unmapped below.
397       */
398      bind_inputs(ctx, arrays, max_index+1, bo, &nr_bo);
399      bind_indices(ctx, ib, bo, &nr_bo);
400      bind_prims(ctx, prim, nr_prims );
401
402      TNL_CONTEXT(ctx)->Driver.RunPipeline(ctx);
403
404      unmap_vbos(ctx, bo, nr_bo);
405      free_space(ctx);
406   }
407}
408
409