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