Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4358 | Serge | 1 | /************************************************************************** |
2 | |||
3 | Copyright 2002-2008 Tungsten Graphics Inc., Cedar Park, Texas. |
||
4 | |||
5 | 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 | on the rights to use, copy, modify, merge, publish, distribute, sub |
||
11 | license, and/or sell copies of the Software, and to permit persons to whom |
||
12 | the Software is furnished to do so, subject to the following conditions: |
||
13 | |||
14 | The above copyright notice and this permission notice (including the next |
||
15 | paragraph) shall be included in all copies or substantial portions of the |
||
16 | Software. |
||
17 | |||
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
20 | FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL |
||
21 | TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, |
||
22 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
||
23 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
||
24 | USE OR OTHER DEALINGS IN THE SOFTWARE. |
||
25 | |||
26 | **************************************************************************/ |
||
27 | |||
28 | /* |
||
29 | * Authors: |
||
30 | * Keith Whitwell |
||
31 | */ |
||
32 | |||
33 | |||
34 | |||
35 | /* Display list compiler attempts to store lists of vertices with the |
||
36 | * same vertex layout. Additionally it attempts to minimize the need |
||
37 | * for execute-time fixup of these vertex lists, allowing them to be |
||
38 | * cached on hardware. |
||
39 | * |
||
40 | * There are still some circumstances where this can be thwarted, for |
||
41 | * example by building a list that consists of one very long primitive |
||
42 | * (eg Begin(Triangles), 1000 vertices, End), and calling that list |
||
43 | * from inside a different begin/end object (Begin(Lines), CallList, |
||
44 | * End). |
||
45 | * |
||
46 | * In that case the code will have to replay the list as individual |
||
47 | * commands through the Exec dispatch table, or fix up the copied |
||
48 | * vertices at execute-time. |
||
49 | * |
||
50 | * The other case where fixup is required is when a vertex attribute |
||
51 | * is introduced in the middle of a primitive. Eg: |
||
52 | * Begin(Lines) |
||
53 | * TexCoord1f() Vertex2f() |
||
54 | * TexCoord1f() Color3f() Vertex2f() |
||
55 | * End() |
||
56 | * |
||
57 | * If the current value of Color isn't known at compile-time, this |
||
58 | * primitive will require fixup. |
||
59 | * |
||
60 | * |
||
61 | * The list compiler currently doesn't attempt to compile lists |
||
62 | * containing EvalCoord or EvalPoint commands. On encountering one of |
||
63 | * these, compilation falls back to opcodes. |
||
64 | * |
||
65 | * This could be improved to fallback only when a mix of EvalCoord and |
||
66 | * Vertex commands are issued within a single primitive. |
||
67 | */ |
||
68 | |||
69 | |||
70 | #include "main/glheader.h" |
||
71 | #include "main/bufferobj.h" |
||
72 | #include "main/context.h" |
||
73 | #include "main/dlist.h" |
||
74 | #include "main/enums.h" |
||
75 | #include "main/eval.h" |
||
76 | #include "main/macros.h" |
||
77 | #include "main/api_validate.h" |
||
78 | #include "main/api_arrayelt.h" |
||
79 | #include "main/vtxfmt.h" |
||
80 | #include "main/dispatch.h" |
||
81 | |||
82 | #include "vbo_context.h" |
||
83 | #include "vbo_noop.h" |
||
84 | |||
85 | |||
86 | #ifdef ERROR |
||
87 | #undef ERROR |
||
88 | #endif |
||
89 | |||
90 | |||
91 | /* An interesting VBO number/name to help with debugging */ |
||
92 | #define VBO_BUF_ID 12345 |
||
93 | |||
94 | |||
95 | /* |
||
96 | * NOTE: Old 'parity' issue is gone, but copying can still be |
||
97 | * wrong-footed on replay. |
||
98 | */ |
||
99 | static GLuint |
||
100 | _save_copy_vertices(struct gl_context *ctx, |
||
101 | const struct vbo_save_vertex_list *node, |
||
102 | const GLfloat * src_buffer) |
||
103 | { |
||
104 | struct vbo_save_context *save = &vbo_context(ctx)->save; |
||
105 | const struct _mesa_prim *prim = &node->prim[node->prim_count - 1]; |
||
106 | GLuint nr = prim->count; |
||
107 | GLuint sz = save->vertex_size; |
||
108 | const GLfloat *src = src_buffer + prim->start * sz; |
||
109 | GLfloat *dst = save->copied.buffer; |
||
110 | GLuint ovf, i; |
||
111 | |||
112 | if (prim->end) |
||
113 | return 0; |
||
114 | |||
115 | switch (prim->mode) { |
||
116 | case GL_POINTS: |
||
117 | return 0; |
||
118 | case GL_LINES: |
||
119 | ovf = nr & 1; |
||
120 | for (i = 0; i < ovf; i++) |
||
121 | memcpy(dst + i * sz, src + (nr - ovf + i) * sz, |
||
122 | sz * sizeof(GLfloat)); |
||
123 | return i; |
||
124 | case GL_TRIANGLES: |
||
125 | ovf = nr % 3; |
||
126 | for (i = 0; i < ovf; i++) |
||
127 | memcpy(dst + i * sz, src + (nr - ovf + i) * sz, |
||
128 | sz * sizeof(GLfloat)); |
||
129 | return i; |
||
130 | case GL_QUADS: |
||
131 | ovf = nr & 3; |
||
132 | for (i = 0; i < ovf; i++) |
||
133 | memcpy(dst + i * sz, src + (nr - ovf + i) * sz, |
||
134 | sz * sizeof(GLfloat)); |
||
135 | return i; |
||
136 | case GL_LINE_STRIP: |
||
137 | if (nr == 0) |
||
138 | return 0; |
||
139 | else { |
||
140 | memcpy(dst, src + (nr - 1) * sz, sz * sizeof(GLfloat)); |
||
141 | return 1; |
||
142 | } |
||
143 | case GL_LINE_LOOP: |
||
144 | case GL_TRIANGLE_FAN: |
||
145 | case GL_POLYGON: |
||
146 | if (nr == 0) |
||
147 | return 0; |
||
148 | else if (nr == 1) { |
||
149 | memcpy(dst, src + 0, sz * sizeof(GLfloat)); |
||
150 | return 1; |
||
151 | } |
||
152 | else { |
||
153 | memcpy(dst, src + 0, sz * sizeof(GLfloat)); |
||
154 | memcpy(dst + sz, src + (nr - 1) * sz, sz * sizeof(GLfloat)); |
||
155 | return 2; |
||
156 | } |
||
157 | case GL_TRIANGLE_STRIP: |
||
158 | case GL_QUAD_STRIP: |
||
159 | switch (nr) { |
||
160 | case 0: |
||
161 | ovf = 0; |
||
162 | break; |
||
163 | case 1: |
||
164 | ovf = 1; |
||
165 | break; |
||
166 | default: |
||
167 | ovf = 2 + (nr & 1); |
||
168 | break; |
||
169 | } |
||
170 | for (i = 0; i < ovf; i++) |
||
171 | memcpy(dst + i * sz, src + (nr - ovf + i) * sz, |
||
172 | sz * sizeof(GLfloat)); |
||
173 | return i; |
||
174 | default: |
||
175 | assert(0); |
||
176 | return 0; |
||
177 | } |
||
178 | } |
||
179 | |||
180 | |||
181 | static struct vbo_save_vertex_store * |
||
182 | alloc_vertex_store(struct gl_context *ctx) |
||
183 | { |
||
184 | struct vbo_save_context *save = &vbo_context(ctx)->save; |
||
185 | struct vbo_save_vertex_store *vertex_store = |
||
186 | CALLOC_STRUCT(vbo_save_vertex_store); |
||
187 | |||
188 | /* obj->Name needs to be non-zero, but won't ever be examined more |
||
189 | * closely than that. In particular these buffers won't be entered |
||
190 | * into the hash and can never be confused with ones visible to the |
||
191 | * user. Perhaps there could be a special number for internal |
||
192 | * buffers: |
||
193 | */ |
||
194 | vertex_store->bufferobj = ctx->Driver.NewBufferObject(ctx, |
||
195 | VBO_BUF_ID, |
||
196 | GL_ARRAY_BUFFER_ARB); |
||
197 | if (vertex_store->bufferobj) { |
||
198 | save->out_of_memory = |
||
199 | !ctx->Driver.BufferData(ctx, |
||
200 | GL_ARRAY_BUFFER_ARB, |
||
201 | VBO_SAVE_BUFFER_SIZE * sizeof(GLfloat), |
||
202 | NULL, GL_STATIC_DRAW_ARB, |
||
203 | vertex_store->bufferobj); |
||
204 | } |
||
205 | else { |
||
206 | save->out_of_memory = GL_TRUE; |
||
207 | } |
||
208 | |||
209 | if (save->out_of_memory) { |
||
210 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "internal VBO allocation"); |
||
211 | _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop); |
||
212 | } |
||
213 | |||
214 | vertex_store->buffer = NULL; |
||
215 | vertex_store->used = 0; |
||
216 | vertex_store->refcount = 1; |
||
217 | |||
218 | return vertex_store; |
||
219 | } |
||
220 | |||
221 | |||
222 | static void |
||
223 | free_vertex_store(struct gl_context *ctx, |
||
224 | struct vbo_save_vertex_store *vertex_store) |
||
225 | { |
||
226 | assert(!vertex_store->buffer); |
||
227 | |||
228 | if (vertex_store->bufferobj) { |
||
229 | _mesa_reference_buffer_object(ctx, &vertex_store->bufferobj, NULL); |
||
230 | } |
||
231 | |||
232 | free(vertex_store); |
||
233 | } |
||
234 | |||
235 | |||
236 | GLfloat * |
||
237 | vbo_save_map_vertex_store(struct gl_context *ctx, |
||
238 | struct vbo_save_vertex_store *vertex_store) |
||
239 | { |
||
240 | assert(vertex_store->bufferobj); |
||
241 | assert(!vertex_store->buffer); |
||
242 | if (vertex_store->bufferobj->Size > 0) { |
||
243 | vertex_store->buffer = |
||
244 | (GLfloat *) ctx->Driver.MapBufferRange(ctx, 0, |
||
245 | vertex_store->bufferobj->Size, |
||
246 | GL_MAP_WRITE_BIT, /* not used */ |
||
247 | vertex_store->bufferobj); |
||
248 | assert(vertex_store->buffer); |
||
249 | return vertex_store->buffer + vertex_store->used; |
||
250 | } |
||
251 | else { |
||
252 | /* probably ran out of memory for buffers */ |
||
253 | return NULL; |
||
254 | } |
||
255 | } |
||
256 | |||
257 | |||
258 | void |
||
259 | vbo_save_unmap_vertex_store(struct gl_context *ctx, |
||
260 | struct vbo_save_vertex_store *vertex_store) |
||
261 | { |
||
262 | if (vertex_store->bufferobj->Size > 0) { |
||
263 | ctx->Driver.UnmapBuffer(ctx, vertex_store->bufferobj); |
||
264 | } |
||
265 | vertex_store->buffer = NULL; |
||
266 | } |
||
267 | |||
268 | |||
269 | static struct vbo_save_primitive_store * |
||
270 | alloc_prim_store(struct gl_context *ctx) |
||
271 | { |
||
272 | struct vbo_save_primitive_store *store = |
||
273 | CALLOC_STRUCT(vbo_save_primitive_store); |
||
274 | (void) ctx; |
||
275 | store->used = 0; |
||
276 | store->refcount = 1; |
||
277 | return store; |
||
278 | } |
||
279 | |||
280 | |||
281 | static void |
||
282 | _save_reset_counters(struct gl_context *ctx) |
||
283 | { |
||
284 | struct vbo_save_context *save = &vbo_context(ctx)->save; |
||
285 | |||
286 | save->prim = save->prim_store->buffer + save->prim_store->used; |
||
287 | save->buffer = save->vertex_store->buffer + save->vertex_store->used; |
||
288 | |||
289 | assert(save->buffer == save->buffer_ptr); |
||
290 | |||
291 | if (save->vertex_size) |
||
292 | save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) / |
||
293 | save->vertex_size); |
||
294 | else |
||
295 | save->max_vert = 0; |
||
296 | |||
297 | save->vert_count = 0; |
||
298 | save->prim_count = 0; |
||
299 | save->prim_max = VBO_SAVE_PRIM_SIZE - save->prim_store->used; |
||
300 | save->dangling_attr_ref = 0; |
||
301 | } |
||
302 | |||
303 | /** |
||
304 | * For a list of prims, try merging prims that can just be extensions of the |
||
305 | * previous prim. |
||
306 | */ |
||
307 | static void |
||
308 | merge_prims(struct gl_context *ctx, |
||
309 | struct _mesa_prim *prim_list, |
||
310 | GLuint *prim_count) |
||
311 | { |
||
312 | GLuint i; |
||
313 | struct _mesa_prim *prev_prim = prim_list; |
||
314 | |||
315 | for (i = 1; i < *prim_count; i++) { |
||
316 | struct _mesa_prim *this_prim = prim_list + i; |
||
317 | |||
318 | vbo_try_prim_conversion(this_prim); |
||
319 | |||
320 | if (vbo_can_merge_prims(prev_prim, this_prim)) { |
||
321 | /* We've found a prim that just extend the previous one. Tack it |
||
322 | * onto the previous one, and let this primitive struct get dropped. |
||
323 | */ |
||
324 | vbo_merge_prims(prev_prim, this_prim); |
||
325 | continue; |
||
326 | } |
||
327 | |||
328 | /* If any previous primitives have been dropped, then we need to copy |
||
329 | * this later one into the next available slot. |
||
330 | */ |
||
331 | prev_prim++; |
||
332 | if (prev_prim != this_prim) |
||
333 | *prev_prim = *this_prim; |
||
334 | } |
||
335 | |||
336 | *prim_count = prev_prim - prim_list + 1; |
||
337 | } |
||
338 | |||
339 | /** |
||
340 | * Insert the active immediate struct onto the display list currently |
||
341 | * being built. |
||
342 | */ |
||
343 | static void |
||
344 | _save_compile_vertex_list(struct gl_context *ctx) |
||
345 | { |
||
346 | struct vbo_save_context *save = &vbo_context(ctx)->save; |
||
347 | struct vbo_save_vertex_list *node; |
||
348 | |||
349 | /* Allocate space for this structure in the display list currently |
||
350 | * being compiled. |
||
351 | */ |
||
352 | node = (struct vbo_save_vertex_list *) |
||
353 | _mesa_dlist_alloc(ctx, save->opcode_vertex_list, sizeof(*node)); |
||
354 | |||
355 | if (!node) |
||
356 | return; |
||
357 | |||
358 | /* Duplicate our template, increment refcounts to the storage structs: |
||
359 | */ |
||
360 | memcpy(node->attrsz, save->attrsz, sizeof(node->attrsz)); |
||
361 | memcpy(node->attrtype, save->attrtype, sizeof(node->attrtype)); |
||
362 | node->vertex_size = save->vertex_size; |
||
363 | node->buffer_offset = |
||
364 | (save->buffer - save->vertex_store->buffer) * sizeof(GLfloat); |
||
365 | node->count = save->vert_count; |
||
366 | node->wrap_count = save->copied.nr; |
||
367 | node->dangling_attr_ref = save->dangling_attr_ref; |
||
368 | node->prim = save->prim; |
||
369 | node->prim_count = save->prim_count; |
||
370 | node->vertex_store = save->vertex_store; |
||
371 | node->prim_store = save->prim_store; |
||
372 | |||
373 | node->vertex_store->refcount++; |
||
374 | node->prim_store->refcount++; |
||
375 | |||
376 | if (node->prim[0].no_current_update) { |
||
377 | node->current_size = 0; |
||
378 | node->current_data = NULL; |
||
379 | } |
||
380 | else { |
||
381 | node->current_size = node->vertex_size - node->attrsz[0]; |
||
382 | node->current_data = NULL; |
||
383 | |||
384 | if (node->current_size) { |
||
385 | /* If the malloc fails, we just pull the data out of the VBO |
||
386 | * later instead. |
||
387 | */ |
||
388 | node->current_data = malloc(node->current_size * sizeof(GLfloat)); |
||
389 | if (node->current_data) { |
||
390 | const char *buffer = (const char *) save->vertex_store->buffer; |
||
391 | unsigned attr_offset = node->attrsz[0] * sizeof(GLfloat); |
||
392 | unsigned vertex_offset = 0; |
||
393 | |||
394 | if (node->count) |
||
395 | vertex_offset = |
||
396 | (node->count - 1) * node->vertex_size * sizeof(GLfloat); |
||
397 | |||
398 | memcpy(node->current_data, |
||
399 | buffer + node->buffer_offset + vertex_offset + attr_offset, |
||
400 | node->current_size * sizeof(GLfloat)); |
||
401 | } |
||
402 | } |
||
403 | } |
||
404 | |||
405 | assert(node->attrsz[VBO_ATTRIB_POS] != 0 || node->count == 0); |
||
406 | |||
407 | if (save->dangling_attr_ref) |
||
408 | ctx->ListState.CurrentList->Flags |= DLIST_DANGLING_REFS; |
||
409 | |||
410 | save->vertex_store->used += save->vertex_size * node->count; |
||
411 | save->prim_store->used += node->prim_count; |
||
412 | |||
413 | /* Copy duplicated vertices |
||
414 | */ |
||
415 | save->copied.nr = _save_copy_vertices(ctx, node, save->buffer); |
||
416 | |||
417 | merge_prims(ctx, node->prim, &node->prim_count); |
||
418 | |||
419 | /* Deal with GL_COMPILE_AND_EXECUTE: |
||
420 | */ |
||
421 | if (ctx->ExecuteFlag) { |
||
422 | struct _glapi_table *dispatch = GET_DISPATCH(); |
||
423 | |||
424 | _glapi_set_dispatch(ctx->Exec); |
||
425 | |||
426 | vbo_loopback_vertex_list(ctx, |
||
427 | (const GLfloat *) ((const char *) save-> |
||
428 | vertex_store->buffer + |
||
429 | node->buffer_offset), |
||
430 | node->attrsz, node->prim, node->prim_count, |
||
431 | node->wrap_count, node->vertex_size); |
||
432 | |||
433 | _glapi_set_dispatch(dispatch); |
||
434 | } |
||
435 | |||
436 | /* Decide whether the storage structs are full, or can be used for |
||
437 | * the next vertex lists as well. |
||
438 | */ |
||
439 | if (save->vertex_store->used > |
||
440 | VBO_SAVE_BUFFER_SIZE - 16 * (save->vertex_size + 4)) { |
||
441 | |||
442 | /* Unmap old store: |
||
443 | */ |
||
444 | vbo_save_unmap_vertex_store(ctx, save->vertex_store); |
||
445 | |||
446 | /* Release old reference: |
||
447 | */ |
||
448 | save->vertex_store->refcount--; |
||
449 | assert(save->vertex_store->refcount != 0); |
||
450 | save->vertex_store = NULL; |
||
451 | |||
452 | /* Allocate and map new store: |
||
453 | */ |
||
454 | save->vertex_store = alloc_vertex_store(ctx); |
||
455 | save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store); |
||
456 | save->out_of_memory = save->buffer_ptr == NULL; |
||
457 | } |
||
458 | |||
459 | if (save->prim_store->used > VBO_SAVE_PRIM_SIZE - 6) { |
||
460 | save->prim_store->refcount--; |
||
461 | assert(save->prim_store->refcount != 0); |
||
462 | save->prim_store = alloc_prim_store(ctx); |
||
463 | } |
||
464 | |||
465 | /* Reset our structures for the next run of vertices: |
||
466 | */ |
||
467 | _save_reset_counters(ctx); |
||
468 | } |
||
469 | |||
470 | |||
471 | /** |
||
472 | * This is called when we fill a vertex buffer before we hit a glEnd(). |
||
473 | * We |
||
474 | * TODO -- If no new vertices have been stored, don't bother saving it. |
||
475 | */ |
||
476 | static void |
||
477 | _save_wrap_buffers(struct gl_context *ctx) |
||
478 | { |
||
479 | struct vbo_save_context *save = &vbo_context(ctx)->save; |
||
480 | GLint i = save->prim_count - 1; |
||
481 | GLenum mode; |
||
482 | GLboolean weak; |
||
483 | GLboolean no_current_update; |
||
484 | |||
485 | assert(i < (GLint) save->prim_max); |
||
486 | assert(i >= 0); |
||
487 | |||
488 | /* Close off in-progress primitive. |
||
489 | */ |
||
490 | save->prim[i].count = (save->vert_count - save->prim[i].start); |
||
491 | mode = save->prim[i].mode; |
||
492 | weak = save->prim[i].weak; |
||
493 | no_current_update = save->prim[i].no_current_update; |
||
494 | |||
495 | /* store the copied vertices, and allocate a new list. |
||
496 | */ |
||
497 | _save_compile_vertex_list(ctx); |
||
498 | |||
499 | /* Restart interrupted primitive |
||
500 | */ |
||
501 | save->prim[0].mode = mode; |
||
502 | save->prim[0].weak = weak; |
||
503 | save->prim[0].no_current_update = no_current_update; |
||
504 | save->prim[0].begin = 0; |
||
505 | save->prim[0].end = 0; |
||
506 | save->prim[0].pad = 0; |
||
507 | save->prim[0].start = 0; |
||
508 | save->prim[0].count = 0; |
||
509 | save->prim[0].num_instances = 1; |
||
510 | save->prim[0].base_instance = 0; |
||
511 | save->prim_count = 1; |
||
512 | } |
||
513 | |||
514 | |||
515 | /** |
||
516 | * Called only when buffers are wrapped as the result of filling the |
||
517 | * vertex_store struct. |
||
518 | */ |
||
519 | static void |
||
520 | _save_wrap_filled_vertex(struct gl_context *ctx) |
||
521 | { |
||
522 | struct vbo_save_context *save = &vbo_context(ctx)->save; |
||
523 | GLfloat *data = save->copied.buffer; |
||
524 | GLuint i; |
||
525 | |||
526 | /* Emit a glEnd to close off the last vertex list. |
||
527 | */ |
||
528 | _save_wrap_buffers(ctx); |
||
529 | |||
530 | /* Copy stored stored vertices to start of new list. |
||
531 | */ |
||
532 | assert(save->max_vert - save->vert_count > save->copied.nr); |
||
533 | |||
534 | for (i = 0; i < save->copied.nr; i++) { |
||
535 | memcpy(save->buffer_ptr, data, save->vertex_size * sizeof(GLfloat)); |
||
536 | data += save->vertex_size; |
||
537 | save->buffer_ptr += save->vertex_size; |
||
538 | save->vert_count++; |
||
539 | } |
||
540 | } |
||
541 | |||
542 | |||
543 | static void |
||
544 | _save_copy_to_current(struct gl_context *ctx) |
||
545 | { |
||
546 | struct vbo_save_context *save = &vbo_context(ctx)->save; |
||
547 | GLuint i; |
||
548 | |||
549 | for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) { |
||
550 | if (save->attrsz[i]) { |
||
551 | save->currentsz[i][0] = save->attrsz[i]; |
||
552 | COPY_CLEAN_4V_TYPE_AS_FLOAT(save->current[i], save->attrsz[i], |
||
553 | save->attrptr[i], save->attrtype[i]); |
||
554 | } |
||
555 | } |
||
556 | } |
||
557 | |||
558 | |||
559 | static void |
||
560 | _save_copy_from_current(struct gl_context *ctx) |
||
561 | { |
||
562 | struct vbo_save_context *save = &vbo_context(ctx)->save; |
||
563 | GLint i; |
||
564 | |||
565 | for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) { |
||
566 | switch (save->attrsz[i]) { |
||
567 | case 4: |
||
568 | save->attrptr[i][3] = save->current[i][3]; |
||
569 | case 3: |
||
570 | save->attrptr[i][2] = save->current[i][2]; |
||
571 | case 2: |
||
572 | save->attrptr[i][1] = save->current[i][1]; |
||
573 | case 1: |
||
574 | save->attrptr[i][0] = save->current[i][0]; |
||
575 | case 0: |
||
576 | break; |
||
577 | } |
||
578 | } |
||
579 | } |
||
580 | |||
581 | |||
582 | /** |
||
583 | * Called when we increase the size of a vertex attribute. For example, |
||
584 | * if we've seen one or more glTexCoord2f() calls and now we get a |
||
585 | * glTexCoord3f() call. |
||
586 | * Flush existing data, set new attrib size, replay copied vertices. |
||
587 | */ |
||
588 | static void |
||
589 | _save_upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz) |
||
590 | { |
||
591 | struct vbo_save_context *save = &vbo_context(ctx)->save; |
||
592 | GLuint oldsz; |
||
593 | GLuint i; |
||
594 | GLfloat *tmp; |
||
595 | |||
596 | /* Store the current run of vertices, and emit a GL_END. Emit a |
||
597 | * BEGIN in the new buffer. |
||
598 | */ |
||
599 | if (save->vert_count) |
||
600 | _save_wrap_buffers(ctx); |
||
601 | else |
||
602 | assert(save->copied.nr == 0); |
||
603 | |||
604 | /* Do a COPY_TO_CURRENT to ensure back-copying works for the case |
||
605 | * when the attribute already exists in the vertex and is having |
||
606 | * its size increased. |
||
607 | */ |
||
608 | _save_copy_to_current(ctx); |
||
609 | |||
610 | /* Fix up sizes: |
||
611 | */ |
||
612 | oldsz = save->attrsz[attr]; |
||
613 | save->attrsz[attr] = newsz; |
||
614 | |||
615 | save->vertex_size += newsz - oldsz; |
||
616 | save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) / |
||
617 | save->vertex_size); |
||
618 | save->vert_count = 0; |
||
619 | |||
620 | /* Recalculate all the attrptr[] values: |
||
621 | */ |
||
622 | for (i = 0, tmp = save->vertex; i < VBO_ATTRIB_MAX; i++) { |
||
623 | if (save->attrsz[i]) { |
||
624 | save->attrptr[i] = tmp; |
||
625 | tmp += save->attrsz[i]; |
||
626 | } |
||
627 | else { |
||
628 | save->attrptr[i] = NULL; /* will not be dereferenced. */ |
||
629 | } |
||
630 | } |
||
631 | |||
632 | /* Copy from current to repopulate the vertex with correct values. |
||
633 | */ |
||
634 | _save_copy_from_current(ctx); |
||
635 | |||
636 | /* Replay stored vertices to translate them to new format here. |
||
637 | * |
||
638 | * If there are copied vertices and the new (upgraded) attribute |
||
639 | * has not been defined before, this list is somewhat degenerate, |
||
640 | * and will need fixup at runtime. |
||
641 | */ |
||
642 | if (save->copied.nr) { |
||
643 | const GLfloat *data = save->copied.buffer; |
||
644 | GLfloat *dest = save->buffer; |
||
645 | GLuint j; |
||
646 | |||
647 | /* Need to note this and fix up at runtime (or loopback): |
||
648 | */ |
||
649 | if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) { |
||
650 | assert(oldsz == 0); |
||
651 | save->dangling_attr_ref = GL_TRUE; |
||
652 | } |
||
653 | |||
654 | for (i = 0; i < save->copied.nr; i++) { |
||
655 | for (j = 0; j < VBO_ATTRIB_MAX; j++) { |
||
656 | if (save->attrsz[j]) { |
||
657 | if (j == attr) { |
||
658 | if (oldsz) { |
||
659 | COPY_CLEAN_4V_TYPE_AS_FLOAT(dest, oldsz, data, |
||
660 | save->attrtype[j]); |
||
661 | data += oldsz; |
||
662 | dest += newsz; |
||
663 | } |
||
664 | else { |
||
665 | COPY_SZ_4V(dest, newsz, save->current[attr]); |
||
666 | dest += newsz; |
||
667 | } |
||
668 | } |
||
669 | else { |
||
670 | GLint sz = save->attrsz[j]; |
||
671 | COPY_SZ_4V(dest, sz, data); |
||
672 | data += sz; |
||
673 | dest += sz; |
||
674 | } |
||
675 | } |
||
676 | } |
||
677 | } |
||
678 | |||
679 | save->buffer_ptr = dest; |
||
680 | save->vert_count += save->copied.nr; |
||
681 | } |
||
682 | } |
||
683 | |||
684 | |||
685 | /** |
||
686 | * This is called when the size of a vertex attribute changes. |
||
687 | * For example, after seeing one or more glTexCoord2f() calls we |
||
688 | * get a glTexCoord4f() or glTexCoord1f() call. |
||
689 | */ |
||
690 | static void |
||
691 | save_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint sz) |
||
692 | { |
||
693 | struct vbo_save_context *save = &vbo_context(ctx)->save; |
||
694 | |||
695 | if (sz > save->attrsz[attr]) { |
||
696 | /* New size is larger. Need to flush existing vertices and get |
||
697 | * an enlarged vertex format. |
||
698 | */ |
||
699 | _save_upgrade_vertex(ctx, attr, sz); |
||
700 | } |
||
701 | else if (sz < save->active_sz[attr]) { |
||
702 | GLuint i; |
||
703 | const GLfloat *id = vbo_get_default_vals_as_float(save->attrtype[attr]); |
||
704 | |||
705 | /* New size is equal or smaller - just need to fill in some |
||
706 | * zeros. |
||
707 | */ |
||
708 | for (i = sz; i <= save->attrsz[attr]; i++) |
||
709 | save->attrptr[attr][i - 1] = id[i - 1]; |
||
710 | } |
||
711 | |||
712 | save->active_sz[attr] = sz; |
||
713 | } |
||
714 | |||
715 | |||
716 | /** |
||
717 | * Reset the current size of all vertex attributes to the default |
||
718 | * value of 0. This signals that we haven't yet seen any per-vertex |
||
719 | * commands such as glNormal3f() or glTexCoord2f(). |
||
720 | */ |
||
721 | static void |
||
722 | _save_reset_vertex(struct gl_context *ctx) |
||
723 | { |
||
724 | struct vbo_save_context *save = &vbo_context(ctx)->save; |
||
725 | GLuint i; |
||
726 | |||
727 | for (i = 0; i < VBO_ATTRIB_MAX; i++) { |
||
728 | save->attrsz[i] = 0; |
||
729 | save->active_sz[i] = 0; |
||
730 | } |
||
731 | |||
732 | save->vertex_size = 0; |
||
733 | } |
||
734 | |||
735 | |||
736 | |||
737 | #define ERROR(err) _mesa_compile_error(ctx, err, __FUNCTION__); |
||
738 | |||
739 | |||
740 | /* Only one size for each attribute may be active at once. Eg. if |
||
741 | * Color3f is installed/active, then Color4f may not be, even if the |
||
742 | * vertex actually contains 4 color coordinates. This is because the |
||
743 | * 3f version won't otherwise set color[3] to 1.0 -- this is the job |
||
744 | * of the chooser function when switching between Color4f and Color3f. |
||
745 | */ |
||
746 | #define ATTR(A, N, T, V0, V1, V2, V3) \ |
||
747 | do { \ |
||
748 | struct vbo_save_context *save = &vbo_context(ctx)->save; \ |
||
749 | \ |
||
750 | if (save->active_sz[A] != N) \ |
||
751 | save_fixup_vertex(ctx, A, N); \ |
||
752 | \ |
||
753 | { \ |
||
754 | GLfloat *dest = save->attrptr[A]; \ |
||
755 | if (N>0) dest[0] = V0; \ |
||
756 | if (N>1) dest[1] = V1; \ |
||
757 | if (N>2) dest[2] = V2; \ |
||
758 | if (N>3) dest[3] = V3; \ |
||
759 | save->attrtype[A] = T; \ |
||
760 | } \ |
||
761 | \ |
||
762 | if ((A) == 0) { \ |
||
763 | GLuint i; \ |
||
764 | \ |
||
765 | for (i = 0; i < save->vertex_size; i++) \ |
||
766 | save->buffer_ptr[i] = save->vertex[i]; \ |
||
767 | \ |
||
768 | save->buffer_ptr += save->vertex_size; \ |
||
769 | \ |
||
770 | if (++save->vert_count >= save->max_vert) \ |
||
771 | _save_wrap_filled_vertex(ctx); \ |
||
772 | } \ |
||
773 | } while (0) |
||
774 | |||
775 | #define TAG(x) _save_##x |
||
776 | |||
777 | #include "vbo_attrib_tmp.h" |
||
778 | |||
779 | |||
780 | |||
781 | #define MAT( ATTR, N, face, params ) \ |
||
782 | do { \ |
||
783 | if (face != GL_BACK) \ |
||
784 | MAT_ATTR( ATTR, N, params ); /* front */ \ |
||
785 | if (face != GL_FRONT) \ |
||
786 | MAT_ATTR( ATTR + 1, N, params ); /* back */ \ |
||
787 | } while (0) |
||
788 | |||
789 | |||
790 | /** |
||
791 | * Save a glMaterial call found between glBegin/End. |
||
792 | * glMaterial calls outside Begin/End are handled in dlist.c. |
||
793 | */ |
||
794 | static void GLAPIENTRY |
||
795 | _save_Materialfv(GLenum face, GLenum pname, const GLfloat *params) |
||
796 | { |
||
797 | GET_CURRENT_CONTEXT(ctx); |
||
798 | |||
799 | if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { |
||
800 | _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(face)"); |
||
801 | return; |
||
802 | } |
||
803 | |||
804 | switch (pname) { |
||
805 | case GL_EMISSION: |
||
806 | MAT(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params); |
||
807 | break; |
||
808 | case GL_AMBIENT: |
||
809 | MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params); |
||
810 | break; |
||
811 | case GL_DIFFUSE: |
||
812 | MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params); |
||
813 | break; |
||
814 | case GL_SPECULAR: |
||
815 | MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params); |
||
816 | break; |
||
817 | case GL_SHININESS: |
||
818 | if (*params < 0 || *params > ctx->Const.MaxShininess) { |
||
819 | _mesa_compile_error(ctx, GL_INVALID_VALUE, "glMaterial(shininess)"); |
||
820 | } |
||
821 | else { |
||
822 | MAT(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params); |
||
823 | } |
||
824 | break; |
||
825 | case GL_COLOR_INDEXES: |
||
826 | MAT(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params); |
||
827 | break; |
||
828 | case GL_AMBIENT_AND_DIFFUSE: |
||
829 | MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params); |
||
830 | MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params); |
||
831 | break; |
||
832 | default: |
||
833 | _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(pname)"); |
||
834 | return; |
||
835 | } |
||
836 | } |
||
837 | |||
838 | |||
839 | /* Cope with EvalCoord/CallList called within a begin/end object: |
||
840 | * -- Flush current buffer |
||
841 | * -- Fallback to opcodes for the rest of the begin/end object. |
||
842 | */ |
||
843 | static void |
||
844 | dlist_fallback(struct gl_context *ctx) |
||
845 | { |
||
846 | struct vbo_save_context *save = &vbo_context(ctx)->save; |
||
847 | |||
848 | if (save->vert_count || save->prim_count) { |
||
849 | if (save->prim_count > 0) { |
||
850 | /* Close off in-progress primitive. */ |
||
851 | GLint i = save->prim_count - 1; |
||
852 | save->prim[i].count = save->vert_count - save->prim[i].start; |
||
853 | } |
||
854 | |||
855 | /* Need to replay this display list with loopback, |
||
856 | * unfortunately, otherwise this primitive won't be handled |
||
857 | * properly: |
||
858 | */ |
||
859 | save->dangling_attr_ref = 1; |
||
860 | |||
861 | _save_compile_vertex_list(ctx); |
||
862 | } |
||
863 | |||
864 | _save_copy_to_current(ctx); |
||
865 | _save_reset_vertex(ctx); |
||
866 | _save_reset_counters(ctx); |
||
867 | if (save->out_of_memory) { |
||
868 | _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop); |
||
869 | } |
||
870 | else { |
||
871 | _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt); |
||
872 | } |
||
873 | ctx->Driver.SaveNeedFlush = GL_FALSE; |
||
874 | } |
||
875 | |||
876 | |||
877 | static void GLAPIENTRY |
||
878 | _save_EvalCoord1f(GLfloat u) |
||
879 | { |
||
880 | GET_CURRENT_CONTEXT(ctx); |
||
881 | dlist_fallback(ctx); |
||
882 | CALL_EvalCoord1f(ctx->Save, (u)); |
||
883 | } |
||
884 | |||
885 | static void GLAPIENTRY |
||
886 | _save_EvalCoord1fv(const GLfloat * v) |
||
887 | { |
||
888 | GET_CURRENT_CONTEXT(ctx); |
||
889 | dlist_fallback(ctx); |
||
890 | CALL_EvalCoord1fv(ctx->Save, (v)); |
||
891 | } |
||
892 | |||
893 | static void GLAPIENTRY |
||
894 | _save_EvalCoord2f(GLfloat u, GLfloat v) |
||
895 | { |
||
896 | GET_CURRENT_CONTEXT(ctx); |
||
897 | dlist_fallback(ctx); |
||
898 | CALL_EvalCoord2f(ctx->Save, (u, v)); |
||
899 | } |
||
900 | |||
901 | static void GLAPIENTRY |
||
902 | _save_EvalCoord2fv(const GLfloat * v) |
||
903 | { |
||
904 | GET_CURRENT_CONTEXT(ctx); |
||
905 | dlist_fallback(ctx); |
||
906 | CALL_EvalCoord2fv(ctx->Save, (v)); |
||
907 | } |
||
908 | |||
909 | static void GLAPIENTRY |
||
910 | _save_EvalPoint1(GLint i) |
||
911 | { |
||
912 | GET_CURRENT_CONTEXT(ctx); |
||
913 | dlist_fallback(ctx); |
||
914 | CALL_EvalPoint1(ctx->Save, (i)); |
||
915 | } |
||
916 | |||
917 | static void GLAPIENTRY |
||
918 | _save_EvalPoint2(GLint i, GLint j) |
||
919 | { |
||
920 | GET_CURRENT_CONTEXT(ctx); |
||
921 | dlist_fallback(ctx); |
||
922 | CALL_EvalPoint2(ctx->Save, (i, j)); |
||
923 | } |
||
924 | |||
925 | static void GLAPIENTRY |
||
926 | _save_CallList(GLuint l) |
||
927 | { |
||
928 | GET_CURRENT_CONTEXT(ctx); |
||
929 | dlist_fallback(ctx); |
||
930 | CALL_CallList(ctx->Save, (l)); |
||
931 | } |
||
932 | |||
933 | static void GLAPIENTRY |
||
934 | _save_CallLists(GLsizei n, GLenum type, const GLvoid * v) |
||
935 | { |
||
936 | GET_CURRENT_CONTEXT(ctx); |
||
937 | dlist_fallback(ctx); |
||
938 | CALL_CallLists(ctx->Save, (n, type, v)); |
||
939 | } |
||
940 | |||
941 | |||
942 | |||
943 | /** |
||
944 | * Called via ctx->Driver.NotifySaveBegin() when a glBegin is getting |
||
945 | * compiled into a display list. |
||
946 | * Updating of ctx->Driver.CurrentSavePrimitive is already taken care of. |
||
947 | */ |
||
948 | GLboolean |
||
949 | vbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode) |
||
950 | { |
||
951 | struct vbo_save_context *save = &vbo_context(ctx)->save; |
||
952 | const GLuint i = save->prim_count++; |
||
953 | |||
954 | assert(i < save->prim_max); |
||
955 | save->prim[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK; |
||
956 | save->prim[i].begin = 1; |
||
957 | save->prim[i].end = 0; |
||
958 | save->prim[i].weak = (mode & VBO_SAVE_PRIM_WEAK) ? 1 : 0; |
||
959 | save->prim[i].no_current_update = |
||
960 | (mode & VBO_SAVE_PRIM_NO_CURRENT_UPDATE) ? 1 : 0; |
||
961 | save->prim[i].pad = 0; |
||
962 | save->prim[i].start = save->vert_count; |
||
963 | save->prim[i].count = 0; |
||
964 | save->prim[i].num_instances = 1; |
||
965 | save->prim[i].base_instance = 0; |
||
966 | |||
967 | if (save->out_of_memory) { |
||
968 | _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop); |
||
969 | } |
||
970 | else { |
||
971 | _mesa_install_save_vtxfmt(ctx, &save->vtxfmt); |
||
972 | } |
||
973 | |||
974 | /* We need to call SaveFlushVertices() if there's state change */ |
||
975 | ctx->Driver.SaveNeedFlush = GL_TRUE; |
||
976 | |||
977 | /* GL_TRUE means we've handled this glBegin here; don't compile a BEGIN |
||
978 | * opcode into the display list. |
||
979 | */ |
||
980 | return GL_TRUE; |
||
981 | } |
||
982 | |||
983 | |||
984 | static void GLAPIENTRY |
||
985 | _save_End(void) |
||
986 | { |
||
987 | GET_CURRENT_CONTEXT(ctx); |
||
988 | struct vbo_save_context *save = &vbo_context(ctx)->save; |
||
989 | const GLint i = save->prim_count - 1; |
||
990 | |||
991 | ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END; |
||
992 | save->prim[i].end = 1; |
||
993 | save->prim[i].count = (save->vert_count - save->prim[i].start); |
||
994 | |||
995 | if (i == (GLint) save->prim_max - 1) { |
||
996 | _save_compile_vertex_list(ctx); |
||
997 | assert(save->copied.nr == 0); |
||
998 | } |
||
999 | |||
1000 | /* Swap out this vertex format while outside begin/end. Any color, |
||
1001 | * etc. received between here and the next begin will be compiled |
||
1002 | * as opcodes. |
||
1003 | */ |
||
1004 | if (save->out_of_memory) { |
||
1005 | _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop); |
||
1006 | } |
||
1007 | else { |
||
1008 | _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt); |
||
1009 | } |
||
1010 | } |
||
1011 | |||
1012 | |||
1013 | static void GLAPIENTRY |
||
1014 | _save_Begin(GLenum mode) |
||
1015 | { |
||
1016 | GET_CURRENT_CONTEXT(ctx); |
||
1017 | (void) mode; |
||
1018 | _mesa_compile_error(ctx, GL_INVALID_OPERATION, "Recursive glBegin"); |
||
1019 | } |
||
1020 | |||
1021 | |||
1022 | static void GLAPIENTRY |
||
1023 | _save_PrimitiveRestartNV(void) |
||
1024 | { |
||
1025 | GLenum curPrim; |
||
1026 | GET_CURRENT_CONTEXT(ctx); |
||
1027 | |||
1028 | curPrim = ctx->Driver.CurrentSavePrimitive; |
||
1029 | |||
1030 | _save_End(); |
||
1031 | _save_Begin(curPrim); |
||
1032 | } |
||
1033 | |||
1034 | |||
1035 | /* Unlike the functions above, these are to be hooked into the vtxfmt |
||
1036 | * maintained in ctx->ListState, active when the list is known or |
||
1037 | * suspected to be outside any begin/end primitive. |
||
1038 | * Note: OBE = Outside Begin/End |
||
1039 | */ |
||
1040 | static void GLAPIENTRY |
||
1041 | _save_OBE_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) |
||
1042 | { |
||
1043 | GET_CURRENT_CONTEXT(ctx); |
||
1044 | vbo_save_NotifyBegin(ctx, GL_QUADS | VBO_SAVE_PRIM_WEAK); |
||
1045 | CALL_Vertex2f(GET_DISPATCH(), (x1, y1)); |
||
1046 | CALL_Vertex2f(GET_DISPATCH(), (x2, y1)); |
||
1047 | CALL_Vertex2f(GET_DISPATCH(), (x2, y2)); |
||
1048 | CALL_Vertex2f(GET_DISPATCH(), (x1, y2)); |
||
1049 | CALL_End(GET_DISPATCH(), ()); |
||
1050 | } |
||
1051 | |||
1052 | |||
1053 | static void GLAPIENTRY |
||
1054 | _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count) |
||
1055 | { |
||
1056 | GET_CURRENT_CONTEXT(ctx); |
||
1057 | struct vbo_save_context *save = &vbo_context(ctx)->save; |
||
1058 | GLint i; |
||
1059 | |||
1060 | if (!_mesa_is_valid_prim_mode(ctx, mode)) { |
||
1061 | _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)"); |
||
1062 | return; |
||
1063 | } |
||
1064 | if (count < 0) { |
||
1065 | _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count<0)"); |
||
1066 | return; |
||
1067 | } |
||
1068 | |||
1069 | if (save->out_of_memory) |
||
1070 | return; |
||
1071 | |||
1072 | _ae_map_vbos(ctx); |
||
1073 | |||
1074 | vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK |
||
1075 | | VBO_SAVE_PRIM_NO_CURRENT_UPDATE)); |
||
1076 | |||
1077 | for (i = 0; i < count; i++) |
||
1078 | CALL_ArrayElement(GET_DISPATCH(), (start + i)); |
||
1079 | CALL_End(GET_DISPATCH(), ()); |
||
1080 | |||
1081 | _ae_unmap_vbos(ctx); |
||
1082 | } |
||
1083 | |||
1084 | |||
1085 | /* Could do better by copying the arrays and element list intact and |
||
1086 | * then emitting an indexed prim at runtime. |
||
1087 | */ |
||
1088 | static void GLAPIENTRY |
||
1089 | _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type, |
||
1090 | const GLvoid * indices) |
||
1091 | { |
||
1092 | GET_CURRENT_CONTEXT(ctx); |
||
1093 | struct vbo_save_context *save = &vbo_context(ctx)->save; |
||
1094 | GLint i; |
||
1095 | |||
1096 | if (!_mesa_is_valid_prim_mode(ctx, mode)) { |
||
1097 | _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)"); |
||
1098 | return; |
||
1099 | } |
||
1100 | if (count < 0) { |
||
1101 | _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)"); |
||
1102 | return; |
||
1103 | } |
||
1104 | if (type != GL_UNSIGNED_BYTE && |
||
1105 | type != GL_UNSIGNED_SHORT && |
||
1106 | type != GL_UNSIGNED_INT) { |
||
1107 | _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)"); |
||
1108 | return; |
||
1109 | } |
||
1110 | |||
1111 | if (save->out_of_memory) |
||
1112 | return; |
||
1113 | |||
1114 | _ae_map_vbos(ctx); |
||
1115 | |||
1116 | if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) |
||
1117 | indices = |
||
1118 | ADD_POINTERS(ctx->Array.ArrayObj->ElementArrayBufferObj->Pointer, indices); |
||
1119 | |||
1120 | vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK | |
||
1121 | VBO_SAVE_PRIM_NO_CURRENT_UPDATE)); |
||
1122 | |||
1123 | switch (type) { |
||
1124 | case GL_UNSIGNED_BYTE: |
||
1125 | for (i = 0; i < count; i++) |
||
1126 | CALL_ArrayElement(GET_DISPATCH(), (((GLubyte *) indices)[i])); |
||
1127 | break; |
||
1128 | case GL_UNSIGNED_SHORT: |
||
1129 | for (i = 0; i < count; i++) |
||
1130 | CALL_ArrayElement(GET_DISPATCH(), (((GLushort *) indices)[i])); |
||
1131 | break; |
||
1132 | case GL_UNSIGNED_INT: |
||
1133 | for (i = 0; i < count; i++) |
||
1134 | CALL_ArrayElement(GET_DISPATCH(), (((GLuint *) indices)[i])); |
||
1135 | break; |
||
1136 | default: |
||
1137 | _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)"); |
||
1138 | break; |
||
1139 | } |
||
1140 | |||
1141 | CALL_End(GET_DISPATCH(), ()); |
||
1142 | |||
1143 | _ae_unmap_vbos(ctx); |
||
1144 | } |
||
1145 | |||
1146 | |||
1147 | static void GLAPIENTRY |
||
1148 | _save_OBE_DrawRangeElements(GLenum mode, GLuint start, GLuint end, |
||
1149 | GLsizei count, GLenum type, |
||
1150 | const GLvoid * indices) |
||
1151 | { |
||
1152 | GET_CURRENT_CONTEXT(ctx); |
||
1153 | struct vbo_save_context *save = &vbo_context(ctx)->save; |
||
1154 | |||
1155 | if (!_mesa_is_valid_prim_mode(ctx, mode)) { |
||
1156 | _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)"); |
||
1157 | return; |
||
1158 | } |
||
1159 | if (count < 0) { |
||
1160 | _mesa_compile_error(ctx, GL_INVALID_VALUE, |
||
1161 | "glDrawRangeElements(count<0)"); |
||
1162 | return; |
||
1163 | } |
||
1164 | if (type != GL_UNSIGNED_BYTE && |
||
1165 | type != GL_UNSIGNED_SHORT && |
||
1166 | type != GL_UNSIGNED_INT) { |
||
1167 | _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)"); |
||
1168 | return; |
||
1169 | } |
||
1170 | if (end < start) { |
||
1171 | _mesa_compile_error(ctx, GL_INVALID_VALUE, |
||
1172 | "glDrawRangeElements(end < start)"); |
||
1173 | return; |
||
1174 | } |
||
1175 | |||
1176 | if (save->out_of_memory) |
||
1177 | return; |
||
1178 | |||
1179 | _save_OBE_DrawElements(mode, count, type, indices); |
||
1180 | } |
||
1181 | |||
1182 | |||
1183 | static void GLAPIENTRY |
||
1184 | _save_OBE_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type, |
||
1185 | const GLvoid * const *indices, GLsizei primcount) |
||
1186 | { |
||
1187 | GLsizei i; |
||
1188 | |||
1189 | for (i = 0; i < primcount; i++) { |
||
1190 | if (count[i] > 0) { |
||
1191 | CALL_DrawElements(GET_DISPATCH(), (mode, count[i], type, indices[i])); |
||
1192 | } |
||
1193 | } |
||
1194 | } |
||
1195 | |||
1196 | |||
1197 | static void GLAPIENTRY |
||
1198 | _save_OBE_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count, |
||
1199 | GLenum type, |
||
1200 | const GLvoid * const *indices, |
||
1201 | GLsizei primcount, |
||
1202 | const GLint *basevertex) |
||
1203 | { |
||
1204 | GLsizei i; |
||
1205 | |||
1206 | for (i = 0; i < primcount; i++) { |
||
1207 | if (count[i] > 0) { |
||
1208 | CALL_DrawElementsBaseVertex(GET_DISPATCH(), (mode, count[i], type, |
||
1209 | indices[i], |
||
1210 | basevertex[i])); |
||
1211 | } |
||
1212 | } |
||
1213 | } |
||
1214 | |||
1215 | |||
1216 | static void |
||
1217 | _save_vtxfmt_init(struct gl_context *ctx) |
||
1218 | { |
||
1219 | struct vbo_save_context *save = &vbo_context(ctx)->save; |
||
1220 | GLvertexformat *vfmt = &save->vtxfmt; |
||
1221 | |||
1222 | vfmt->ArrayElement = _ae_ArrayElement; |
||
1223 | |||
1224 | vfmt->Color3f = _save_Color3f; |
||
1225 | vfmt->Color3fv = _save_Color3fv; |
||
1226 | vfmt->Color4f = _save_Color4f; |
||
1227 | vfmt->Color4fv = _save_Color4fv; |
||
1228 | vfmt->EdgeFlag = _save_EdgeFlag; |
||
1229 | vfmt->End = _save_End; |
||
1230 | vfmt->PrimitiveRestartNV = _save_PrimitiveRestartNV; |
||
1231 | vfmt->FogCoordfEXT = _save_FogCoordfEXT; |
||
1232 | vfmt->FogCoordfvEXT = _save_FogCoordfvEXT; |
||
1233 | vfmt->Indexf = _save_Indexf; |
||
1234 | vfmt->Indexfv = _save_Indexfv; |
||
1235 | vfmt->Materialfv = _save_Materialfv; |
||
1236 | vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f; |
||
1237 | vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv; |
||
1238 | vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f; |
||
1239 | vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv; |
||
1240 | vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f; |
||
1241 | vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv; |
||
1242 | vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f; |
||
1243 | vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv; |
||
1244 | vfmt->Normal3f = _save_Normal3f; |
||
1245 | vfmt->Normal3fv = _save_Normal3fv; |
||
1246 | vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT; |
||
1247 | vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT; |
||
1248 | vfmt->TexCoord1f = _save_TexCoord1f; |
||
1249 | vfmt->TexCoord1fv = _save_TexCoord1fv; |
||
1250 | vfmt->TexCoord2f = _save_TexCoord2f; |
||
1251 | vfmt->TexCoord2fv = _save_TexCoord2fv; |
||
1252 | vfmt->TexCoord3f = _save_TexCoord3f; |
||
1253 | vfmt->TexCoord3fv = _save_TexCoord3fv; |
||
1254 | vfmt->TexCoord4f = _save_TexCoord4f; |
||
1255 | vfmt->TexCoord4fv = _save_TexCoord4fv; |
||
1256 | vfmt->Vertex2f = _save_Vertex2f; |
||
1257 | vfmt->Vertex2fv = _save_Vertex2fv; |
||
1258 | vfmt->Vertex3f = _save_Vertex3f; |
||
1259 | vfmt->Vertex3fv = _save_Vertex3fv; |
||
1260 | vfmt->Vertex4f = _save_Vertex4f; |
||
1261 | vfmt->Vertex4fv = _save_Vertex4fv; |
||
1262 | vfmt->VertexAttrib1fARB = _save_VertexAttrib1fARB; |
||
1263 | vfmt->VertexAttrib1fvARB = _save_VertexAttrib1fvARB; |
||
1264 | vfmt->VertexAttrib2fARB = _save_VertexAttrib2fARB; |
||
1265 | vfmt->VertexAttrib2fvARB = _save_VertexAttrib2fvARB; |
||
1266 | vfmt->VertexAttrib3fARB = _save_VertexAttrib3fARB; |
||
1267 | vfmt->VertexAttrib3fvARB = _save_VertexAttrib3fvARB; |
||
1268 | vfmt->VertexAttrib4fARB = _save_VertexAttrib4fARB; |
||
1269 | vfmt->VertexAttrib4fvARB = _save_VertexAttrib4fvARB; |
||
1270 | |||
1271 | vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV; |
||
1272 | vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV; |
||
1273 | vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV; |
||
1274 | vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV; |
||
1275 | vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV; |
||
1276 | vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV; |
||
1277 | vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV; |
||
1278 | vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV; |
||
1279 | |||
1280 | /* integer-valued */ |
||
1281 | vfmt->VertexAttribI1i = _save_VertexAttribI1i; |
||
1282 | vfmt->VertexAttribI2i = _save_VertexAttribI2i; |
||
1283 | vfmt->VertexAttribI3i = _save_VertexAttribI3i; |
||
1284 | vfmt->VertexAttribI4i = _save_VertexAttribI4i; |
||
1285 | vfmt->VertexAttribI2iv = _save_VertexAttribI2iv; |
||
1286 | vfmt->VertexAttribI3iv = _save_VertexAttribI3iv; |
||
1287 | vfmt->VertexAttribI4iv = _save_VertexAttribI4iv; |
||
1288 | |||
1289 | /* unsigned integer-valued */ |
||
1290 | vfmt->VertexAttribI1ui = _save_VertexAttribI1ui; |
||
1291 | vfmt->VertexAttribI2ui = _save_VertexAttribI2ui; |
||
1292 | vfmt->VertexAttribI3ui = _save_VertexAttribI3ui; |
||
1293 | vfmt->VertexAttribI4ui = _save_VertexAttribI4ui; |
||
1294 | vfmt->VertexAttribI2uiv = _save_VertexAttribI2uiv; |
||
1295 | vfmt->VertexAttribI3uiv = _save_VertexAttribI3uiv; |
||
1296 | vfmt->VertexAttribI4uiv = _save_VertexAttribI4uiv; |
||
1297 | |||
1298 | vfmt->VertexP2ui = _save_VertexP2ui; |
||
1299 | vfmt->VertexP3ui = _save_VertexP3ui; |
||
1300 | vfmt->VertexP4ui = _save_VertexP4ui; |
||
1301 | vfmt->VertexP2uiv = _save_VertexP2uiv; |
||
1302 | vfmt->VertexP3uiv = _save_VertexP3uiv; |
||
1303 | vfmt->VertexP4uiv = _save_VertexP4uiv; |
||
1304 | |||
1305 | vfmt->TexCoordP1ui = _save_TexCoordP1ui; |
||
1306 | vfmt->TexCoordP2ui = _save_TexCoordP2ui; |
||
1307 | vfmt->TexCoordP3ui = _save_TexCoordP3ui; |
||
1308 | vfmt->TexCoordP4ui = _save_TexCoordP4ui; |
||
1309 | vfmt->TexCoordP1uiv = _save_TexCoordP1uiv; |
||
1310 | vfmt->TexCoordP2uiv = _save_TexCoordP2uiv; |
||
1311 | vfmt->TexCoordP3uiv = _save_TexCoordP3uiv; |
||
1312 | vfmt->TexCoordP4uiv = _save_TexCoordP4uiv; |
||
1313 | |||
1314 | vfmt->MultiTexCoordP1ui = _save_MultiTexCoordP1ui; |
||
1315 | vfmt->MultiTexCoordP2ui = _save_MultiTexCoordP2ui; |
||
1316 | vfmt->MultiTexCoordP3ui = _save_MultiTexCoordP3ui; |
||
1317 | vfmt->MultiTexCoordP4ui = _save_MultiTexCoordP4ui; |
||
1318 | vfmt->MultiTexCoordP1uiv = _save_MultiTexCoordP1uiv; |
||
1319 | vfmt->MultiTexCoordP2uiv = _save_MultiTexCoordP2uiv; |
||
1320 | vfmt->MultiTexCoordP3uiv = _save_MultiTexCoordP3uiv; |
||
1321 | vfmt->MultiTexCoordP4uiv = _save_MultiTexCoordP4uiv; |
||
1322 | |||
1323 | vfmt->NormalP3ui = _save_NormalP3ui; |
||
1324 | vfmt->NormalP3uiv = _save_NormalP3uiv; |
||
1325 | |||
1326 | vfmt->ColorP3ui = _save_ColorP3ui; |
||
1327 | vfmt->ColorP4ui = _save_ColorP4ui; |
||
1328 | vfmt->ColorP3uiv = _save_ColorP3uiv; |
||
1329 | vfmt->ColorP4uiv = _save_ColorP4uiv; |
||
1330 | |||
1331 | vfmt->SecondaryColorP3ui = _save_SecondaryColorP3ui; |
||
1332 | vfmt->SecondaryColorP3uiv = _save_SecondaryColorP3uiv; |
||
1333 | |||
1334 | vfmt->VertexAttribP1ui = _save_VertexAttribP1ui; |
||
1335 | vfmt->VertexAttribP2ui = _save_VertexAttribP2ui; |
||
1336 | vfmt->VertexAttribP3ui = _save_VertexAttribP3ui; |
||
1337 | vfmt->VertexAttribP4ui = _save_VertexAttribP4ui; |
||
1338 | |||
1339 | vfmt->VertexAttribP1uiv = _save_VertexAttribP1uiv; |
||
1340 | vfmt->VertexAttribP2uiv = _save_VertexAttribP2uiv; |
||
1341 | vfmt->VertexAttribP3uiv = _save_VertexAttribP3uiv; |
||
1342 | vfmt->VertexAttribP4uiv = _save_VertexAttribP4uiv; |
||
1343 | |||
1344 | /* This will all require us to fallback to saving the list as opcodes: |
||
1345 | */ |
||
1346 | vfmt->CallList = _save_CallList; |
||
1347 | vfmt->CallLists = _save_CallLists; |
||
1348 | |||
1349 | vfmt->EvalCoord1f = _save_EvalCoord1f; |
||
1350 | vfmt->EvalCoord1fv = _save_EvalCoord1fv; |
||
1351 | vfmt->EvalCoord2f = _save_EvalCoord2f; |
||
1352 | vfmt->EvalCoord2fv = _save_EvalCoord2fv; |
||
1353 | vfmt->EvalPoint1 = _save_EvalPoint1; |
||
1354 | vfmt->EvalPoint2 = _save_EvalPoint2; |
||
1355 | |||
1356 | /* These calls all generate GL_INVALID_OPERATION since this vtxfmt is |
||
1357 | * only used when we're inside a glBegin/End pair. |
||
1358 | */ |
||
1359 | vfmt->Begin = _save_Begin; |
||
1360 | } |
||
1361 | |||
1362 | |||
1363 | /** |
||
1364 | * Initialize the dispatch table with the VBO functions for display |
||
1365 | * list compilation. |
||
1366 | */ |
||
1367 | void |
||
1368 | vbo_initialize_save_dispatch(const struct gl_context *ctx, |
||
1369 | struct _glapi_table *exec) |
||
1370 | { |
||
1371 | SET_DrawArrays(exec, _save_OBE_DrawArrays); |
||
1372 | SET_DrawElements(exec, _save_OBE_DrawElements); |
||
1373 | SET_DrawRangeElements(exec, _save_OBE_DrawRangeElements); |
||
1374 | SET_MultiDrawElementsEXT(exec, _save_OBE_MultiDrawElements); |
||
1375 | SET_MultiDrawElementsBaseVertex(exec, _save_OBE_MultiDrawElementsBaseVertex); |
||
1376 | SET_Rectf(exec, _save_OBE_Rectf); |
||
1377 | /* Note: other glDraw functins aren't compiled into display lists */ |
||
1378 | } |
||
1379 | |||
1380 | |||
1381 | |||
1382 | void |
||
1383 | vbo_save_SaveFlushVertices(struct gl_context *ctx) |
||
1384 | { |
||
1385 | struct vbo_save_context *save = &vbo_context(ctx)->save; |
||
1386 | |||
1387 | /* Noop when we are actually active: |
||
1388 | */ |
||
1389 | if (ctx->Driver.CurrentSavePrimitive <= PRIM_MAX) |
||
1390 | return; |
||
1391 | |||
1392 | if (save->vert_count || save->prim_count) |
||
1393 | _save_compile_vertex_list(ctx); |
||
1394 | |||
1395 | _save_copy_to_current(ctx); |
||
1396 | _save_reset_vertex(ctx); |
||
1397 | _save_reset_counters(ctx); |
||
1398 | ctx->Driver.SaveNeedFlush = GL_FALSE; |
||
1399 | } |
||
1400 | |||
1401 | |||
1402 | void |
||
1403 | vbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode) |
||
1404 | { |
||
1405 | struct vbo_save_context *save = &vbo_context(ctx)->save; |
||
1406 | |||
1407 | (void) list; |
||
1408 | (void) mode; |
||
1409 | |||
1410 | if (!save->prim_store) |
||
1411 | save->prim_store = alloc_prim_store(ctx); |
||
1412 | |||
1413 | if (!save->vertex_store) |
||
1414 | save->vertex_store = alloc_vertex_store(ctx); |
||
1415 | |||
1416 | save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store); |
||
1417 | |||
1418 | _save_reset_vertex(ctx); |
||
1419 | _save_reset_counters(ctx); |
||
1420 | ctx->Driver.SaveNeedFlush = GL_FALSE; |
||
1421 | } |
||
1422 | |||
1423 | |||
1424 | void |
||
1425 | vbo_save_EndList(struct gl_context *ctx) |
||
1426 | { |
||
1427 | struct vbo_save_context *save = &vbo_context(ctx)->save; |
||
1428 | |||
1429 | /* EndList called inside a (saved) Begin/End pair? |
||
1430 | */ |
||
1431 | if (_mesa_inside_dlist_begin_end(ctx)) { |
||
1432 | if (save->prim_count > 0) { |
||
1433 | GLint i = save->prim_count - 1; |
||
1434 | ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END; |
||
1435 | save->prim[i].end = 0; |
||
1436 | save->prim[i].count = (save->vert_count - save->prim[i].start); |
||
1437 | } |
||
1438 | |||
1439 | /* Make sure this vertex list gets replayed by the "loopback" |
||
1440 | * mechanism: |
||
1441 | */ |
||
1442 | save->dangling_attr_ref = 1; |
||
1443 | vbo_save_SaveFlushVertices(ctx); |
||
1444 | |||
1445 | /* Swap out this vertex format while outside begin/end. Any color, |
||
1446 | * etc. received between here and the next begin will be compiled |
||
1447 | * as opcodes. |
||
1448 | */ |
||
1449 | _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt); |
||
1450 | } |
||
1451 | |||
1452 | vbo_save_unmap_vertex_store(ctx, save->vertex_store); |
||
1453 | |||
1454 | assert(save->vertex_size == 0); |
||
1455 | } |
||
1456 | |||
1457 | |||
1458 | void |
||
1459 | vbo_save_BeginCallList(struct gl_context *ctx, struct gl_display_list *dlist) |
||
1460 | { |
||
1461 | struct vbo_save_context *save = &vbo_context(ctx)->save; |
||
1462 | save->replay_flags |= dlist->Flags; |
||
1463 | } |
||
1464 | |||
1465 | |||
1466 | void |
||
1467 | vbo_save_EndCallList(struct gl_context *ctx) |
||
1468 | { |
||
1469 | struct vbo_save_context *save = &vbo_context(ctx)->save; |
||
1470 | |||
1471 | if (ctx->ListState.CallDepth == 1) { |
||
1472 | /* This is correct: want to keep only the VBO_SAVE_FALLBACK |
||
1473 | * flag, if it is set: |
||
1474 | */ |
||
1475 | save->replay_flags &= VBO_SAVE_FALLBACK; |
||
1476 | } |
||
1477 | } |
||
1478 | |||
1479 | |||
1480 | static void |
||
1481 | vbo_destroy_vertex_list(struct gl_context *ctx, void *data) |
||
1482 | { |
||
1483 | struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data; |
||
1484 | (void) ctx; |
||
1485 | |||
1486 | if (--node->vertex_store->refcount == 0) |
||
1487 | free_vertex_store(ctx, node->vertex_store); |
||
1488 | |||
1489 | if (--node->prim_store->refcount == 0) |
||
1490 | free(node->prim_store); |
||
1491 | |||
1492 | free(node->current_data); |
||
1493 | node->current_data = NULL; |
||
1494 | } |
||
1495 | |||
1496 | |||
1497 | static void |
||
1498 | vbo_print_vertex_list(struct gl_context *ctx, void *data) |
||
1499 | { |
||
1500 | struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data; |
||
1501 | GLuint i; |
||
1502 | (void) ctx; |
||
1503 | |||
1504 | printf("VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n", |
||
1505 | node->count, node->prim_count, node->vertex_size); |
||
1506 | |||
1507 | for (i = 0; i < node->prim_count; i++) { |
||
1508 | struct _mesa_prim *prim = &node->prim[i]; |
||
1509 | printf(" prim %d: %s%s %d..%d %s %s\n", |
||
1510 | i, |
||
1511 | _mesa_lookup_prim_by_nr(prim->mode), |
||
1512 | prim->weak ? " (weak)" : "", |
||
1513 | prim->start, |
||
1514 | prim->start + prim->count, |
||
1515 | (prim->begin) ? "BEGIN" : "(wrap)", |
||
1516 | (prim->end) ? "END" : "(wrap)"); |
||
1517 | } |
||
1518 | } |
||
1519 | |||
1520 | |||
1521 | /** |
||
1522 | * Called during context creation/init. |
||
1523 | */ |
||
1524 | static void |
||
1525 | _save_current_init(struct gl_context *ctx) |
||
1526 | { |
||
1527 | struct vbo_save_context *save = &vbo_context(ctx)->save; |
||
1528 | GLint i; |
||
1529 | |||
1530 | for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_GENERIC15; i++) { |
||
1531 | const GLuint j = i - VBO_ATTRIB_POS; |
||
1532 | ASSERT(j < VERT_ATTRIB_MAX); |
||
1533 | save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j]; |
||
1534 | save->current[i] = ctx->ListState.CurrentAttrib[j]; |
||
1535 | } |
||
1536 | |||
1537 | for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) { |
||
1538 | const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL; |
||
1539 | ASSERT(j < MAT_ATTRIB_MAX); |
||
1540 | save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j]; |
||
1541 | save->current[i] = ctx->ListState.CurrentMaterial[j]; |
||
1542 | } |
||
1543 | } |
||
1544 | |||
1545 | |||
1546 | /** |
||
1547 | * Initialize the display list compiler. Called during context creation. |
||
1548 | */ |
||
1549 | void |
||
1550 | vbo_save_api_init(struct vbo_save_context *save) |
||
1551 | { |
||
1552 | struct gl_context *ctx = save->ctx; |
||
1553 | GLuint i; |
||
1554 | |||
1555 | save->opcode_vertex_list = |
||
1556 | _mesa_dlist_alloc_opcode(ctx, |
||
1557 | sizeof(struct vbo_save_vertex_list), |
||
1558 | vbo_save_playback_vertex_list, |
||
1559 | vbo_destroy_vertex_list, |
||
1560 | vbo_print_vertex_list); |
||
1561 | |||
1562 | ctx->Driver.NotifySaveBegin = vbo_save_NotifyBegin; |
||
1563 | |||
1564 | _save_vtxfmt_init(ctx); |
||
1565 | _save_current_init(ctx); |
||
1566 | _mesa_noop_vtxfmt_init(&save->vtxfmt_noop); |
||
1567 | |||
1568 | /* These will actually get set again when binding/drawing */ |
||
1569 | for (i = 0; i < VBO_ATTRIB_MAX; i++) |
||
1570 | save->inputs[i] = &save->arrays[i]; |
||
1571 | }>>=>>=>>=>>>>>0)"); |