mesa: Remove Array._DrawArrays.
[mesa.git] / src / mesa / tnl / t_vertex.c
1 /*
2 * Copyright 2003 VMware, Inc.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * on the rights to use, copy, modify, merge, publish, distribute, sub
9 * license, and/or sell copies of the Software, and to permit persons to whom
10 * the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 * VMWARE AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
22 * USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Keith Whitwell <keithw@vmware.com>
26 */
27
28 #include <stdio.h>
29 #include "main/glheader.h"
30 #include "main/context.h"
31 #include "main/execmem.h"
32 #include "swrast/s_chan.h"
33 #include "t_context.h"
34 #include "t_vertex.h"
35
36 #define DBG 0
37
38 /* Build and manage clipspace/ndc/window vertices.
39 */
40
41 static GLboolean match_fastpath( struct tnl_clipspace *vtx,
42 const struct tnl_clipspace_fastpath *fp)
43 {
44 GLuint j;
45
46 if (vtx->attr_count != fp->attr_count)
47 return GL_FALSE;
48
49 for (j = 0; j < vtx->attr_count; j++)
50 if (vtx->attr[j].format != fp->attr[j].format ||
51 vtx->attr[j].inputsize != fp->attr[j].size ||
52 vtx->attr[j].vertoffset != fp->attr[j].offset)
53 return GL_FALSE;
54
55 if (fp->match_strides) {
56 if (vtx->vertex_size != fp->vertex_size)
57 return GL_FALSE;
58
59 for (j = 0; j < vtx->attr_count; j++)
60 if (vtx->attr[j].inputstride != fp->attr[j].stride)
61 return GL_FALSE;
62 }
63
64 return GL_TRUE;
65 }
66
67 static GLboolean search_fastpath_emit( struct tnl_clipspace *vtx )
68 {
69 struct tnl_clipspace_fastpath *fp = vtx->fastpath;
70
71 for ( ; fp ; fp = fp->next) {
72 if (match_fastpath(vtx, fp)) {
73 vtx->emit = fp->func;
74 return GL_TRUE;
75 }
76 }
77
78 return GL_FALSE;
79 }
80
81 void _tnl_register_fastpath( struct tnl_clipspace *vtx,
82 GLboolean match_strides )
83 {
84 struct tnl_clipspace_fastpath *fastpath = CALLOC_STRUCT(tnl_clipspace_fastpath);
85 GLuint i;
86
87 if (fastpath == NULL) {
88 _mesa_error_no_memory(__func__);
89 return;
90 }
91
92 fastpath->vertex_size = vtx->vertex_size;
93 fastpath->attr_count = vtx->attr_count;
94 fastpath->match_strides = match_strides;
95 fastpath->func = vtx->emit;
96 fastpath->attr = malloc(vtx->attr_count * sizeof(fastpath->attr[0]));
97
98 if (fastpath->attr == NULL) {
99 free(fastpath);
100 _mesa_error_no_memory(__func__);
101 return;
102 }
103
104 for (i = 0; i < vtx->attr_count; i++) {
105 fastpath->attr[i].format = vtx->attr[i].format;
106 fastpath->attr[i].stride = vtx->attr[i].inputstride;
107 fastpath->attr[i].size = vtx->attr[i].inputsize;
108 fastpath->attr[i].offset = vtx->attr[i].vertoffset;
109 }
110
111 fastpath->next = vtx->fastpath;
112 vtx->fastpath = fastpath;
113 }
114
115
116
117 /***********************************************************************
118 * Build codegen functions or return generic ones:
119 */
120 static void choose_emit_func( struct gl_context *ctx, GLuint count, GLubyte *dest)
121 {
122 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
123 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
124 struct tnl_clipspace_attr *a = vtx->attr;
125 const GLuint attr_count = vtx->attr_count;
126 GLuint j;
127
128 for (j = 0; j < attr_count; j++) {
129 GLvector4f *vptr = VB->AttribPtr[a[j].attrib];
130 a[j].inputstride = vptr->stride;
131 a[j].inputsize = vptr->size;
132 a[j].emit = a[j].insert[vptr->size - 1]; /* not always used */
133 }
134
135 vtx->emit = NULL;
136
137 /* Does this match an existing (hardwired, codegen or known-bad)
138 * fastpath?
139 */
140 if (search_fastpath_emit(vtx)) {
141 /* Use this result. If it is null, then it is already known
142 * that the current state will fail for codegen and there is no
143 * point trying again.
144 */
145 }
146 else if (vtx->codegen_emit) {
147 vtx->codegen_emit(ctx);
148 }
149
150 if (!vtx->emit) {
151 _tnl_generate_hardwired_emit(ctx);
152 }
153
154 /* Otherwise use the generic version:
155 */
156 if (!vtx->emit)
157 vtx->emit = _tnl_generic_emit;
158
159 vtx->emit( ctx, count, dest );
160 }
161
162
163
164 static void choose_interp_func( struct gl_context *ctx,
165 GLfloat t,
166 GLuint edst, GLuint eout, GLuint ein,
167 GLboolean force_boundary )
168 {
169 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
170 GLboolean unfilled = (ctx->Polygon.FrontMode != GL_FILL ||
171 ctx->Polygon.BackMode != GL_FILL);
172 GLboolean twosided = ctx->Light.Enabled && ctx->Light.Model.TwoSide;
173
174 if (vtx->need_extras && (twosided || unfilled)) {
175 vtx->interp = _tnl_generic_interp_extras;
176 } else {
177 vtx->interp = _tnl_generic_interp;
178 }
179
180 vtx->interp( ctx, t, edst, eout, ein, force_boundary );
181 }
182
183
184 static void choose_copy_pv_func( struct gl_context *ctx, GLuint edst, GLuint esrc )
185 {
186 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
187 GLboolean unfilled = (ctx->Polygon.FrontMode != GL_FILL ||
188 ctx->Polygon.BackMode != GL_FILL);
189
190 GLboolean twosided = ctx->Light.Enabled && ctx->Light.Model.TwoSide;
191
192 if (vtx->need_extras && (twosided || unfilled)) {
193 vtx->copy_pv = _tnl_generic_copy_pv_extras;
194 } else {
195 vtx->copy_pv = _tnl_generic_copy_pv;
196 }
197
198 vtx->copy_pv( ctx, edst, esrc );
199 }
200
201
202 /***********************************************************************
203 * Public entrypoints, mostly dispatch to the above:
204 */
205
206
207 /* Interpolate between two vertices to produce a third:
208 */
209 void _tnl_interp( struct gl_context *ctx,
210 GLfloat t,
211 GLuint edst, GLuint eout, GLuint ein,
212 GLboolean force_boundary )
213 {
214 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
215 vtx->interp( ctx, t, edst, eout, ein, force_boundary );
216 }
217
218 /* Copy colors from one vertex to another:
219 */
220 void _tnl_copy_pv( struct gl_context *ctx, GLuint edst, GLuint esrc )
221 {
222 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
223 vtx->copy_pv( ctx, edst, esrc );
224 }
225
226
227 /* Extract a named attribute from a hardware vertex. Will have to
228 * reverse any viewport transformation, swizzling or other conversions
229 * which may have been applied:
230 */
231 void _tnl_get_attr( struct gl_context *ctx, const void *vin,
232 GLenum attr, GLfloat *dest )
233 {
234 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
235 const struct tnl_clipspace_attr *a = vtx->attr;
236 const GLuint attr_count = vtx->attr_count;
237 GLuint j;
238
239 for (j = 0; j < attr_count; j++) {
240 if (a[j].attrib == attr) {
241 a[j].extract( &a[j], dest, (GLubyte *)vin + a[j].vertoffset );
242 return;
243 }
244 }
245
246 /* Else return the value from ctx->Current.
247 */
248 if (attr == _TNL_ATTRIB_POINTSIZE) {
249 /* If the hardware vertex doesn't have point size then use size from
250 * struct gl_context. XXX this will be wrong if drawing attenuated points!
251 */
252 dest[0] = ctx->Point.Size;
253 }
254 else {
255 memcpy( dest, ctx->Current.Attrib[attr], 4*sizeof(GLfloat));
256 }
257 }
258
259
260 /* Complementary operation to the above.
261 */
262 void _tnl_set_attr( struct gl_context *ctx, void *vout,
263 GLenum attr, const GLfloat *src )
264 {
265 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
266 const struct tnl_clipspace_attr *a = vtx->attr;
267 const GLuint attr_count = vtx->attr_count;
268 GLuint j;
269
270 for (j = 0; j < attr_count; j++) {
271 if (a[j].attrib == attr) {
272 a[j].insert[4-1]( &a[j], (GLubyte *)vout + a[j].vertoffset, src );
273 return;
274 }
275 }
276 }
277
278
279 void *_tnl_get_vertex( struct gl_context *ctx, GLuint nr )
280 {
281 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
282
283 return vtx->vertex_buf + nr * vtx->vertex_size;
284 }
285
286 void _tnl_invalidate_vertex_state( struct gl_context *ctx, GLuint new_state )
287 {
288 /* if two-sided lighting changes or filled/unfilled polygon state changes */
289 if (new_state & (_NEW_LIGHT | _NEW_POLYGON) ) {
290 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
291 vtx->new_inputs = ~0;
292 vtx->interp = choose_interp_func;
293 vtx->copy_pv = choose_copy_pv_func;
294 }
295 }
296
297 static void invalidate_funcs( struct tnl_clipspace *vtx )
298 {
299 vtx->emit = choose_emit_func;
300 vtx->interp = choose_interp_func;
301 vtx->copy_pv = choose_copy_pv_func;
302 vtx->new_inputs = ~0;
303 }
304
305 GLuint _tnl_install_attrs( struct gl_context *ctx, const struct tnl_attr_map *map,
306 GLuint nr, const GLfloat *vp,
307 GLuint unpacked_size )
308 {
309 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
310 GLuint offset = 0;
311 GLuint i, j;
312
313 assert(nr < _TNL_ATTRIB_MAX);
314 assert(nr == 0 || map[0].attrib == VERT_ATTRIB_POS);
315
316 vtx->new_inputs = ~0;
317 vtx->need_viewport = GL_FALSE;
318
319 if (vp) {
320 vtx->need_viewport = GL_TRUE;
321 }
322
323 for (j = 0, i = 0; i < nr; i++) {
324 const GLuint format = map[i].format;
325 if (format == EMIT_PAD) {
326 if (DBG)
327 printf("%d: pad %d, offset %d\n", i,
328 map[i].offset, offset);
329
330 offset += map[i].offset;
331
332 }
333 else {
334 GLuint tmpoffset;
335
336 if (unpacked_size)
337 tmpoffset = map[i].offset;
338 else
339 tmpoffset = offset;
340
341 if (vtx->attr_count != j ||
342 vtx->attr[j].attrib != map[i].attrib ||
343 vtx->attr[j].format != format ||
344 vtx->attr[j].vertoffset != tmpoffset) {
345 invalidate_funcs(vtx);
346
347 vtx->attr[j].attrib = map[i].attrib;
348 vtx->attr[j].format = format;
349 vtx->attr[j].vp = vp;
350 vtx->attr[j].insert = _tnl_format_info[format].insert;
351 vtx->attr[j].extract = _tnl_format_info[format].extract;
352 vtx->attr[j].vertattrsize = _tnl_format_info[format].attrsize;
353 vtx->attr[j].vertoffset = tmpoffset;
354 }
355
356
357 if (DBG)
358 printf("%d: %s, vp %p, offset %d\n", i,
359 _tnl_format_info[format].name, (void *)vp,
360 vtx->attr[j].vertoffset);
361
362 offset += _tnl_format_info[format].attrsize;
363 j++;
364 }
365 }
366
367 vtx->attr_count = j;
368
369 if (unpacked_size)
370 vtx->vertex_size = unpacked_size;
371 else
372 vtx->vertex_size = offset;
373
374 assert(vtx->vertex_size <= vtx->max_vertex_size);
375 return vtx->vertex_size;
376 }
377
378
379
380 void _tnl_invalidate_vertices( struct gl_context *ctx, GLuint newinputs )
381 {
382 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
383 vtx->new_inputs |= newinputs;
384 }
385
386
387 /* This event has broader use beyond this file - will move elsewhere
388 * and probably invoke a driver callback.
389 */
390 void _tnl_notify_pipeline_output_change( struct gl_context *ctx )
391 {
392 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
393 invalidate_funcs(vtx);
394 }
395
396
397 static void adjust_input_ptrs( struct gl_context *ctx, GLint diff)
398 {
399 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
400 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
401 struct tnl_clipspace_attr *a = vtx->attr;
402 const GLuint count = vtx->attr_count;
403 GLuint j;
404
405 diff -= 1;
406 for (j=0; j<count; ++j) {
407 register GLvector4f *vptr = VB->AttribPtr[a->attrib];
408 (a++)->inputptr += diff*vptr->stride;
409 }
410 }
411
412 static void update_input_ptrs( struct gl_context *ctx, GLuint start )
413 {
414 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
415 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
416 struct tnl_clipspace_attr *a = vtx->attr;
417 const GLuint count = vtx->attr_count;
418 GLuint j;
419
420 for (j = 0; j < count; j++) {
421 GLvector4f *vptr = VB->AttribPtr[a[j].attrib];
422
423 if (vtx->emit != choose_emit_func) {
424 assert(a[j].inputstride == vptr->stride);
425 assert(a[j].inputsize == vptr->size);
426 }
427
428 a[j].inputptr = ((GLubyte *)vptr->data) + start * vptr->stride;
429 }
430
431 if (a->vp) {
432 vtx->vp_scale[0] = a->vp[MAT_SX];
433 vtx->vp_scale[1] = a->vp[MAT_SY];
434 vtx->vp_scale[2] = a->vp[MAT_SZ];
435 vtx->vp_scale[3] = 1.0;
436 vtx->vp_xlate[0] = a->vp[MAT_TX];
437 vtx->vp_xlate[1] = a->vp[MAT_TY];
438 vtx->vp_xlate[2] = a->vp[MAT_TZ];
439 vtx->vp_xlate[3] = 0.0;
440 }
441 }
442
443
444 void _tnl_build_vertices( struct gl_context *ctx,
445 GLuint start,
446 GLuint end,
447 GLuint newinputs )
448 {
449 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
450 update_input_ptrs( ctx, start );
451 vtx->emit( ctx, end - start,
452 (GLubyte *)(vtx->vertex_buf +
453 start * vtx->vertex_size));
454 }
455
456 /* Emit VB vertices start..end to dest. Note that VB vertex at
457 * postion start will be emitted to dest at position zero.
458 */
459 void *_tnl_emit_vertices_to_buffer( struct gl_context *ctx,
460 GLuint start,
461 GLuint end,
462 void *dest )
463 {
464 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
465
466 update_input_ptrs(ctx, start);
467 /* Note: dest should not be adjusted for non-zero 'start' values:
468 */
469 vtx->emit( ctx, end - start, (GLubyte*) dest );
470 return (void *)((GLubyte *)dest + vtx->vertex_size * (end - start));
471 }
472
473 /* Emit indexed VB vertices start..end to dest. Note that VB vertex at
474 * postion start will be emitted to dest at position zero.
475 */
476
477 void *_tnl_emit_indexed_vertices_to_buffer( struct gl_context *ctx,
478 const GLuint *elts,
479 GLuint start,
480 GLuint end,
481 void *dest )
482 {
483 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
484 GLuint oldIndex;
485 GLubyte *cdest = dest;
486
487 update_input_ptrs(ctx, oldIndex = elts[start++]);
488 vtx->emit( ctx, 1, cdest );
489 cdest += vtx->vertex_size;
490
491 for (; start < end; ++start) {
492 adjust_input_ptrs(ctx, elts[start] - oldIndex);
493 oldIndex = elts[start];
494 vtx->emit( ctx, 1, cdest);
495 cdest += vtx->vertex_size;
496 }
497
498 return (void *) cdest;
499 }
500
501
502 void _tnl_init_vertices( struct gl_context *ctx,
503 GLuint vb_size,
504 GLuint max_vertex_size )
505 {
506 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
507
508 _tnl_install_attrs( ctx, NULL, 0, NULL, 0 );
509
510 vtx->need_extras = GL_TRUE;
511 if (max_vertex_size > vtx->max_vertex_size) {
512 _tnl_free_vertices( ctx );
513 vtx->max_vertex_size = max_vertex_size;
514 vtx->vertex_buf = _mesa_align_calloc(vb_size * max_vertex_size, 32 );
515 invalidate_funcs(vtx);
516 }
517
518 switch(CHAN_TYPE) {
519 case GL_UNSIGNED_BYTE:
520 vtx->chan_scale[0] = 255.0;
521 vtx->chan_scale[1] = 255.0;
522 vtx->chan_scale[2] = 255.0;
523 vtx->chan_scale[3] = 255.0;
524 break;
525 case GL_UNSIGNED_SHORT:
526 vtx->chan_scale[0] = 65535.0;
527 vtx->chan_scale[1] = 65535.0;
528 vtx->chan_scale[2] = 65535.0;
529 vtx->chan_scale[3] = 65535.0;
530 break;
531 default:
532 vtx->chan_scale[0] = 1.0;
533 vtx->chan_scale[1] = 1.0;
534 vtx->chan_scale[2] = 1.0;
535 vtx->chan_scale[3] = 1.0;
536 break;
537 }
538
539 vtx->identity[0] = 0.0;
540 vtx->identity[1] = 0.0;
541 vtx->identity[2] = 0.0;
542 vtx->identity[3] = 1.0;
543
544 vtx->codegen_emit = NULL;
545
546 #ifdef USE_SSE_ASM
547 if (!getenv("MESA_NO_CODEGEN"))
548 vtx->codegen_emit = _tnl_generate_sse_emit;
549 #endif
550 }
551
552
553 void _tnl_free_vertices( struct gl_context *ctx )
554 {
555 TNLcontext *tnl = TNL_CONTEXT(ctx);
556 if (tnl) {
557 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
558 struct tnl_clipspace_fastpath *fp, *tmp;
559
560 _mesa_align_free(vtx->vertex_buf);
561 vtx->vertex_buf = NULL;
562
563 for (fp = vtx->fastpath ; fp ; fp = tmp) {
564 tmp = fp->next;
565 free(fp->attr);
566
567 /* KW: At the moment, fp->func is constrained to be allocated by
568 * _mesa_exec_alloc(), as the hardwired fastpaths in
569 * t_vertex_generic.c are handled specially. It would be nice
570 * to unify them, but this probably won't change until this
571 * module gets another overhaul.
572 */
573 _mesa_exec_free((void *) fp->func);
574 free(fp);
575 }
576
577 vtx->fastpath = NULL;
578 }
579 }