2 ** Copyright 2006, The Android Open Source Project
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
8 ** http://www.apache.org/licenses/LICENSE-2.0
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
26 #include "primitives.h"
28 #include "BufferObjectManager.h"
30 // ----------------------------------------------------------------------------
32 #define VC_CACHE_STATISTICS 0
33 #define VC_CACHE_TYPE_NONE 0
34 #define VC_CACHE_TYPE_INDEXED 1
35 #define VC_CACHE_TYPE_LRU 2
36 #define VC_CACHE_TYPE VC_CACHE_TYPE_INDEXED
38 #if VC_CACHE_STATISTICS
39 #include <utils/Timers.h>
42 // ----------------------------------------------------------------------------
46 static void validate_arrays(ogles_context_t* c, GLenum mode);
48 static void compileElements__generic(ogles_context_t*,
49 vertex_t*, GLint, GLsizei);
50 static void compileElement__generic(ogles_context_t*,
53 static void drawPrimitivesPoints(ogles_context_t*, GLint, GLsizei);
54 static void drawPrimitivesLineStrip(ogles_context_t*, GLint, GLsizei);
55 static void drawPrimitivesLineLoop(ogles_context_t*, GLint, GLsizei);
56 static void drawPrimitivesLines(ogles_context_t*, GLint, GLsizei);
57 static void drawPrimitivesTriangleStrip(ogles_context_t*, GLint, GLsizei);
58 static void drawPrimitivesTriangleFan(ogles_context_t*, GLint, GLsizei);
59 static void drawPrimitivesTriangles(ogles_context_t*, GLint, GLsizei);
61 static void drawIndexedPrimitivesPoints(ogles_context_t*,
62 GLsizei, const GLvoid*);
63 static void drawIndexedPrimitivesLineStrip(ogles_context_t*,
64 GLsizei, const GLvoid*);
65 static void drawIndexedPrimitivesLineLoop(ogles_context_t*,
66 GLsizei, const GLvoid*);
67 static void drawIndexedPrimitivesLines(ogles_context_t*,
68 GLsizei, const GLvoid*);
69 static void drawIndexedPrimitivesTriangleStrip(ogles_context_t*,
70 GLsizei, const GLvoid*);
71 static void drawIndexedPrimitivesTriangleFan(ogles_context_t*,
72 GLsizei, const GLvoid*);
73 static void drawIndexedPrimitivesTriangles(ogles_context_t*,
74 GLsizei, const GLvoid*);
76 // ----------------------------------------------------------------------------
78 typedef void (*arrays_prims_fct_t)(ogles_context_t*, GLint, GLsizei);
79 static const arrays_prims_fct_t drawArraysPrims[] = {
82 drawPrimitivesLineLoop,
83 drawPrimitivesLineStrip,
84 drawPrimitivesTriangles,
85 drawPrimitivesTriangleStrip,
86 drawPrimitivesTriangleFan
89 typedef void (*elements_prims_fct_t)(ogles_context_t*, GLsizei, const GLvoid*);
90 static const elements_prims_fct_t drawElementsPrims[] = {
91 drawIndexedPrimitivesPoints,
92 drawIndexedPrimitivesLines,
93 drawIndexedPrimitivesLineLoop,
94 drawIndexedPrimitivesLineStrip,
95 drawIndexedPrimitivesTriangles,
96 drawIndexedPrimitivesTriangleStrip,
97 drawIndexedPrimitivesTriangleFan
100 // ----------------------------------------------------------------------------
105 void ogles_init_array(ogles_context_t* c)
107 c->arrays.vertex.size = 4;
108 c->arrays.vertex.type = GL_FLOAT;
109 c->arrays.color.size = 4;
110 c->arrays.color.type = GL_FLOAT;
111 c->arrays.normal.size = 4;
112 c->arrays.normal.type = GL_FLOAT;
113 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
114 c->arrays.texture[i].size = 4;
115 c->arrays.texture[i].type = GL_FLOAT;
119 if (!c->vc.vBuffer) {
120 // this could have failed
121 ogles_error(c, GL_OUT_OF_MEMORY);
125 void ogles_uninit_array(ogles_context_t* c)
130 // ----------------------------------------------------------------------------
133 #pragma mark Array fetchers
136 static void currentColor(ogles_context_t* c, GLfixed* v, const GLvoid*) {
137 memcpy(v, c->current.color.v, sizeof(vec4_t));
139 static void currentColor_clamp(ogles_context_t* c, GLfixed* v, const GLvoid*) {
140 memcpy(v, c->currentColorClamped.v, sizeof(vec4_t));
142 static void currentNormal(ogles_context_t* c, GLfixed* v, const GLvoid*) {
143 memcpy(v, c->currentNormal.v, sizeof(vec3_t));
145 static void currentTexCoord(ogles_context_t* c, GLfixed* v, const GLvoid*) {
146 memcpy(v, c->current.texture[c->arrays.tmu].v, sizeof(vec4_t));
150 static void fetchNop(ogles_context_t*, GLfixed*, const GLvoid*) {
152 static void fetch2b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
153 v[0] = gglIntToFixed(p[0]);
154 v[1] = gglIntToFixed(p[1]);
156 static void fetch2s(ogles_context_t*, GLfixed* v, const GLshort* p) {
157 v[0] = gglIntToFixed(p[0]);
158 v[1] = gglIntToFixed(p[1]);
160 static void fetch2x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
161 memcpy(v, p, 2*sizeof(GLfixed));
163 static void fetch2f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
164 v[0] = gglFloatToFixed(p[0]);
165 v[1] = gglFloatToFixed(p[1]);
167 static void fetch3b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
168 v[0] = gglIntToFixed(p[0]);
169 v[1] = gglIntToFixed(p[1]);
170 v[2] = gglIntToFixed(p[2]);
172 static void fetch3s(ogles_context_t*, GLfixed* v, const GLshort* p) {
173 v[0] = gglIntToFixed(p[0]);
174 v[1] = gglIntToFixed(p[1]);
175 v[2] = gglIntToFixed(p[2]);
177 static void fetch3x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
178 memcpy(v, p, 3*sizeof(GLfixed));
180 static void fetch3f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
181 v[0] = gglFloatToFixed(p[0]);
182 v[1] = gglFloatToFixed(p[1]);
183 v[2] = gglFloatToFixed(p[2]);
185 static void fetch4b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
186 v[0] = gglIntToFixed(p[0]);
187 v[1] = gglIntToFixed(p[1]);
188 v[2] = gglIntToFixed(p[2]);
189 v[3] = gglIntToFixed(p[3]);
191 static void fetch4s(ogles_context_t*, GLfixed* v, const GLshort* p) {
192 v[0] = gglIntToFixed(p[0]);
193 v[1] = gglIntToFixed(p[1]);
194 v[2] = gglIntToFixed(p[2]);
195 v[3] = gglIntToFixed(p[3]);
197 static void fetch4x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
198 memcpy(v, p, 4*sizeof(GLfixed));
200 static void fetch4f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
201 v[0] = gglFloatToFixed(p[0]);
202 v[1] = gglFloatToFixed(p[1]);
203 v[2] = gglFloatToFixed(p[2]);
204 v[3] = gglFloatToFixed(p[3]);
206 static void fetchExpand4ub(ogles_context_t*, GLfixed* v, const GLubyte* p) {
207 v[0] = GGL_UB_TO_X(p[0]);
208 v[1] = GGL_UB_TO_X(p[1]);
209 v[2] = GGL_UB_TO_X(p[2]);
210 v[3] = GGL_UB_TO_X(p[3]);
212 static void fetchClamp4x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
213 v[0] = gglClampx(p[0]);
214 v[1] = gglClampx(p[1]);
215 v[2] = gglClampx(p[2]);
216 v[3] = gglClampx(p[3]);
218 static void fetchClamp4f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
219 v[0] = gglClampx(gglFloatToFixed(p[0]));
220 v[1] = gglClampx(gglFloatToFixed(p[1]));
221 v[2] = gglClampx(gglFloatToFixed(p[2]));
222 v[3] = gglClampx(gglFloatToFixed(p[3]));
224 static void fetchExpand3ub(ogles_context_t*, GLfixed* v, const GLubyte* p) {
225 v[0] = GGL_UB_TO_X(p[0]);
226 v[1] = GGL_UB_TO_X(p[1]);
227 v[2] = GGL_UB_TO_X(p[2]);
230 static void fetchClamp3x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
231 v[0] = gglClampx(p[0]);
232 v[1] = gglClampx(p[1]);
233 v[2] = gglClampx(p[2]);
236 static void fetchClamp3f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
237 v[0] = gglClampx(gglFloatToFixed(p[0]));
238 v[1] = gglClampx(gglFloatToFixed(p[1]));
239 v[2] = gglClampx(gglFloatToFixed(p[2]));
242 static void fetchExpand3b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
243 v[0] = GGL_B_TO_X(p[0]);
244 v[1] = GGL_B_TO_X(p[1]);
245 v[2] = GGL_B_TO_X(p[2]);
247 static void fetchExpand3s(ogles_context_t*, GLfixed* v, const GLshort* p) {
248 v[0] = GGL_S_TO_X(p[0]);
249 v[1] = GGL_S_TO_X(p[1]);
250 v[2] = GGL_S_TO_X(p[2]);
253 typedef array_t::fetcher_t fn_t;
255 static const fn_t color_fct[2][16] = { // size={3,4}, type={ub,f,x}
256 { 0, (fn_t)fetchExpand3ub, 0, 0, 0, 0,
257 (fn_t)fetch3f, 0, 0, 0, 0, 0,
259 { 0, (fn_t)fetchExpand4ub, 0, 0, 0, 0,
260 (fn_t)fetch4f, 0, 0, 0, 0, 0,
263 static const fn_t color_clamp_fct[2][16] = { // size={3,4}, type={ub,f,x}
264 { 0, (fn_t)fetchExpand3ub, 0, 0, 0, 0,
265 (fn_t)fetchClamp3f, 0, 0, 0, 0, 0,
266 (fn_t)fetchClamp3x },
267 { 0, (fn_t)fetchExpand4ub, 0, 0, 0, 0,
268 (fn_t)fetchClamp4f, 0, 0, 0, 0, 0,
269 (fn_t)fetchClamp4x },
271 static const fn_t normal_fct[1][16] = { // size={3}, type={b,s,f,x}
272 { (fn_t)fetchExpand3b, 0,
273 (fn_t)fetchExpand3s, 0, 0, 0,
274 (fn_t)fetch3f, 0, 0, 0, 0, 0,
277 static const fn_t vertex_fct[3][16] = { // size={2,3,4}, type={b,s,f,x}
279 (fn_t)fetch2s, 0, 0, 0,
280 (fn_t)fetch2f, 0, 0, 0, 0, 0,
283 (fn_t)fetch3s, 0, 0, 0,
284 (fn_t)fetch3f, 0, 0, 0, 0, 0,
287 (fn_t)fetch4s, 0, 0, 0,
288 (fn_t)fetch4f, 0, 0, 0, 0, 0,
291 static const fn_t texture_fct[3][16] = { // size={2,3,4}, type={b,s,f,x}
293 (fn_t)fetch2s, 0, 0, 0,
294 (fn_t)fetch2f, 0, 0, 0, 0, 0,
297 (fn_t)fetch3s, 0, 0, 0,
298 (fn_t)fetch3f, 0, 0, 0, 0, 0,
301 (fn_t)fetch4s, 0, 0, 0,
302 (fn_t)fetch4f, 0, 0, 0, 0, 0,
306 // ----------------------------------------------------------------------------
313 GLint size, GLenum type, GLsizei stride,
314 const GLvoid *pointer, const buffer_t* bo, GLsizei count)
320 case GL_UNSIGNED_SHORT:
331 this->stride = stride;
332 this->pointer = pointer;
334 this->bounds = count;
337 inline void array_t::resolve()
339 physical_pointer = (bo) ? (bo->data + uintptr_t(pointer)) : pointer;
342 // ----------------------------------------------------------------------------
345 #pragma mark vertex_cache_t
348 void vertex_cache_t::init()
350 // make sure the size of vertex_t allows cache-line alignment
351 CTA<(sizeof(vertex_t) & 0x1F) == 0> assertAlignedSize;
353 const int align = 32;
354 const size_t s = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE;
355 const size_t size = s*sizeof(vertex_t) + align;
358 memset(base, 0, size);
359 vBuffer = (vertex_t*)((size_t(base) + align - 1) & ~(align-1));
360 vCache = vBuffer + VERTEX_BUFFER_SIZE;
365 void vertex_cache_t::uninit()
368 base = vBuffer = vCache = 0;
371 void vertex_cache_t::clear()
373 #if VC_CACHE_STATISTICS
374 startTime = systemTime(SYSTEM_TIME_THREAD);
379 #if VC_CACHE_TYPE == VC_CACHE_TYPE_LRU
380 vertex_t* v = vBuffer;
381 size_t count = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE;
388 sequence += INDEX_SEQ;
389 if (sequence >= 0x80000000LU) {
390 sequence = INDEX_SEQ;
391 vertex_t* v = vBuffer;
392 size_t count = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE;
400 #if VC_CACHE_STATISTICS
401 void vertex_cache_t::dump_stats(GLenum mode)
403 nsecs_t time = systemTime(SYSTEM_TIME_THREAD) - startTime;
404 uint32_t hits = total - misses;
407 case GL_POINTS: prim_count = total; break;
408 case GL_LINE_STRIP: prim_count = total - 1; break;
409 case GL_LINE_LOOP: prim_count = total - 1; break;
410 case GL_LINES: prim_count = total / 2; break;
411 case GL_TRIANGLE_STRIP: prim_count = total - 2; break;
412 case GL_TRIANGLE_FAN: prim_count = total - 2; break;
413 case GL_TRIANGLES: prim_count = total / 3; break;
416 printf( "total=%5u, hits=%5u, miss=%5u, hitrate=%3u%%,"
417 " prims=%5u, time=%6u us, prims/s=%d, v/t=%f\n",
418 total, hits, misses, (hits*100)/total,
419 prim_count, int(ns2us(time)), int(prim_count*float(seconds(1))/time),
420 float(misses) / prim_count);
423 void vertex_cache_t::dump_stats(GLenum /*mode*/)
428 // ----------------------------------------------------------------------------
433 static __attribute__((noinline))
434 void enableDisableClientState(ogles_context_t* c, GLenum array, bool enable)
436 const int tmu = c->arrays.activeTexture;
439 case GL_COLOR_ARRAY: a = &c->arrays.color; break;
440 case GL_NORMAL_ARRAY: a = &c->arrays.normal; break;
441 case GL_TEXTURE_COORD_ARRAY: a = &c->arrays.texture[tmu]; break;
442 case GL_VERTEX_ARRAY: a = &c->arrays.vertex; break;
444 ogles_error(c, GL_INVALID_ENUM);
447 a->enable = enable ? GL_TRUE : GL_FALSE;
450 // ----------------------------------------------------------------------------
453 #pragma mark Vertex Cache
456 static __attribute__((noinline))
457 vertex_t* cache_vertex(ogles_context_t* c, vertex_t* v, uint32_t index)
459 #if VC_CACHE_STATISTICS
462 if (ggl_unlikely(v->locked)) {
463 // we're just looking for an entry in the cache that is not locked.
464 // and we know that there cannot be more than 2 locked entries
465 // because a triangle needs at most 3 vertices.
466 // We never use the first and second entries because they might be in
467 // use by the striper or faner. Any other entry will do as long as
469 // We compute directly the index of a "free" entry from the locked
470 // state of v[2] and v[3].
471 v = c->vc.vBuffer + 2;
472 v += v[0].locked | (v[1].locked<<1);
474 // note: compileElement clears v->flags
475 c->arrays.compileElement(c, v, index);
480 static __attribute__((noinline))
481 vertex_t* fetch_vertex(ogles_context_t* c, size_t index)
483 index |= c->vc.sequence;
485 #if VC_CACHE_TYPE == VC_CACHE_TYPE_INDEXED
487 vertex_t* const v = c->vc.vCache +
488 (index & (vertex_cache_t::VERTEX_CACHE_SIZE-1));
490 if (ggl_likely(v->index == index)) {
494 return cache_vertex(c, v, index);
496 #elif VC_CACHE_TYPE == VC_CACHE_TYPE_LRU
498 vertex_t* v = c->vc.vCache +
499 (index & ((vertex_cache_t::VERTEX_CACHE_SIZE-1)>>1))*2;
501 // always record LRU in v[0]
502 if (ggl_likely(v[0].index == index)) {
508 if (ggl_likely(v[1].index == index)) {
514 const int lru = 1 - v[0].mru;
516 return cache_vertex(c, &v[lru], index);
518 #elif VC_CACHE_TYPE == VC_CACHE_TYPE_NONE
520 // just for debugging...
521 vertex_t* v = c->vc.vBuffer + 2;
522 return cache_vertex(c, v, index);
527 // ----------------------------------------------------------------------------
530 #pragma mark Primitive Assembly
533 void drawPrimitivesPoints(ogles_context_t* c, GLint first, GLsizei count)
535 if (ggl_unlikely(count < 1))
538 // vertex cache size must be multiple of 1
540 (vertex_cache_t::VERTEX_BUFFER_SIZE +
541 vertex_cache_t::VERTEX_CACHE_SIZE);
543 vertex_t* v = c->vc.vBuffer;
544 GLsizei num = count > vcs ? vcs : count;
545 c->arrays.cull = vertex_t::CLIP_ALL;
546 c->arrays.compileElements(c, v, first, num);
549 if (!c->arrays.cull) {
550 // quick/trivial reject of the whole batch
552 const uint32_t cc = v[0].flags;
553 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
554 c->prims.renderPoint(c, v);
562 // ----------------------------------------------------------------------------
564 void drawPrimitivesLineStrip(ogles_context_t* c, GLint first, GLsizei count)
566 if (ggl_unlikely(count < 2))
569 vertex_t *v, *v0, *v1;
570 c->arrays.cull = vertex_t::CLIP_ALL;
571 c->arrays.compileElement(c, c->vc.vBuffer, first);
575 // vertex cache size must be multiple of 1
577 (vertex_cache_t::VERTEX_BUFFER_SIZE +
578 vertex_cache_t::VERTEX_CACHE_SIZE - 1);
580 v0 = c->vc.vBuffer + 0;
581 v = c->vc.vBuffer + 1;
582 GLsizei num = count > vcs ? vcs : count;
583 c->arrays.compileElements(c, v, first, num);
586 if (!c->arrays.cull) {
587 // quick/trivial reject of the whole batch
590 const uint32_t cc = v0->flags & v1->flags;
591 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
592 c->prims.renderLine(c, v0, v1);
597 // copy back the last processed vertex
598 c->vc.vBuffer[0] = *v0;
599 c->arrays.cull = v0->flags & vertex_t::CLIP_ALL;
603 void drawPrimitivesLineLoop(ogles_context_t* c, GLint first, GLsizei count)
605 if (ggl_unlikely(count < 2))
607 drawPrimitivesLineStrip(c, first, count);
608 if (ggl_likely(count >= 3)) {
609 vertex_t* v0 = c->vc.vBuffer;
610 vertex_t* v1 = c->vc.vBuffer + 1;
611 c->arrays.compileElement(c, v1, first);
612 const uint32_t cc = v0->flags & v1->flags;
613 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
614 c->prims.renderLine(c, v0, v1);
618 void drawPrimitivesLines(ogles_context_t* c, GLint first, GLsizei count)
620 if (ggl_unlikely(count < 2))
623 // vertex cache size must be multiple of 2
625 ((vertex_cache_t::VERTEX_BUFFER_SIZE +
626 vertex_cache_t::VERTEX_CACHE_SIZE) / 2) * 2;
628 vertex_t* v = c->vc.vBuffer;
629 GLsizei num = count > vcs ? vcs : count;
630 c->arrays.cull = vertex_t::CLIP_ALL;
631 c->arrays.compileElements(c, v, first, num);
634 if (!c->arrays.cull) {
635 // quick/trivial reject of the whole batch
638 const uint32_t cc = v[0].flags & v[1].flags;
639 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
640 c->prims.renderLine(c, v, v+1);
645 } while (count >= 2);
648 // ----------------------------------------------------------------------------
650 static void drawPrimitivesTriangleFanOrStrip(ogles_context_t* c,
651 GLint first, GLsizei count, int winding)
653 // winding == 2 : fan
654 // winding == 1 : strip
656 if (ggl_unlikely(count < 3))
659 vertex_t *v, *v0, *v1, *v2;
660 c->arrays.cull = vertex_t::CLIP_ALL;
661 c->arrays.compileElements(c, c->vc.vBuffer, first, 2);
665 // vertex cache size must be multiple of 2. This is extremely important
666 // because it allows us to preserve the same winding when the whole
667 // batch is culled. We also need 2 extra vertices in the array, because
668 // we always keep the two first ones.
670 ((vertex_cache_t::VERTEX_BUFFER_SIZE +
671 vertex_cache_t::VERTEX_CACHE_SIZE - 2) / 2) * 2;
673 v0 = c->vc.vBuffer + 0;
674 v1 = c->vc.vBuffer + 1;
675 v = c->vc.vBuffer + 2;
676 GLsizei num = count > vcs ? vcs : count;
677 c->arrays.compileElements(c, v, first, num);
680 if (!c->arrays.cull) {
681 // quick/trivial reject of the whole batch
684 const uint32_t cc = v0->flags & v1->flags & v2->flags;
685 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
686 c->prims.renderTriangle(c, v0, v1, v2);
687 swap(((winding^=1) ? v1 : v0), v2);
692 v0 = c->vc.vBuffer + 2 + vcs - 2;
693 v1 = c->vc.vBuffer + 2 + vcs - 1;
694 if ((winding&2) == 0) {
695 // for strips copy back the two last compiled vertices
696 c->vc.vBuffer[0] = *v0;
698 c->vc.vBuffer[1] = *v1;
699 c->arrays.cull = v0->flags & v1->flags & vertex_t::CLIP_ALL;
704 void drawPrimitivesTriangleStrip(ogles_context_t* c,
705 GLint first, GLsizei count) {
706 drawPrimitivesTriangleFanOrStrip(c, first, count, 1);
709 void drawPrimitivesTriangleFan(ogles_context_t* c,
710 GLint first, GLsizei count) {
711 drawPrimitivesTriangleFanOrStrip(c, first, count, 2);
714 void drawPrimitivesTriangles(ogles_context_t* c, GLint first, GLsizei count)
716 if (ggl_unlikely(count < 3))
719 // vertex cache size must be multiple of 3
721 ((vertex_cache_t::VERTEX_BUFFER_SIZE +
722 vertex_cache_t::VERTEX_CACHE_SIZE) / 3) * 3;
724 vertex_t* v = c->vc.vBuffer;
725 GLsizei num = count > vcs ? vcs : count;
726 c->arrays.cull = vertex_t::CLIP_ALL;
727 c->arrays.compileElements(c, v, first, num);
730 if (!c->arrays.cull) {
731 // quick/trivial reject of the whole batch
734 const uint32_t cc = v[0].flags & v[1].flags & v[2].flags;
735 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
736 c->prims.renderTriangle(c, v, v+1, v+2);
741 } while (count >= 3);
744 // ----------------------------------------------------------------------------
749 // this looks goofy, but gcc does a great job with this...
750 static inline unsigned int read_index(int type, const GLvoid*& p) {
753 r = *(const GLubyte*)p;
754 p = (const GLubyte*)p + 1;
756 r = *(const GLushort*)p;
757 p = (const GLushort*)p + 1;
762 // ----------------------------------------------------------------------------
764 void drawIndexedPrimitivesPoints(ogles_context_t* c,
765 GLsizei count, const GLvoid *indices)
767 if (ggl_unlikely(count < 1))
769 const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
771 vertex_t * v = fetch_vertex(c, read_index(type, indices));
772 if (ggl_likely(!(v->flags & vertex_t::CLIP_ALL)))
773 c->prims.renderPoint(c, v);
779 // ----------------------------------------------------------------------------
781 void drawIndexedPrimitivesLineStrip(ogles_context_t* c,
782 GLsizei count, const GLvoid *indices)
784 if (ggl_unlikely(count < 2))
787 vertex_t * const v = c->vc.vBuffer;
791 const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
792 c->arrays.compileElement(c, v0, read_index(type, indices));
795 v1 = fetch_vertex(c, read_index(type, indices));
796 const uint32_t cc = v0->flags & v1->flags;
797 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
798 c->prims.renderLine(c, v0, v1);
806 void drawIndexedPrimitivesLineLoop(ogles_context_t* c,
807 GLsizei count, const GLvoid *indices)
809 if (ggl_unlikely(count <= 2)) {
810 drawIndexedPrimitivesLines(c, count, indices);
814 vertex_t * const v = c->vc.vBuffer;
818 const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
819 c->arrays.compileElement(c, v0, read_index(type, indices));
822 v1 = fetch_vertex(c, read_index(type, indices));
823 const uint32_t cc = v0->flags & v1->flags;
824 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
825 c->prims.renderLine(c, v0, v1);
833 const uint32_t cc = v0->flags & v1->flags;
834 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
835 c->prims.renderLine(c, v0, v1);
838 void drawIndexedPrimitivesLines(ogles_context_t* c,
839 GLsizei count, const GLvoid *indices)
841 if (ggl_unlikely(count < 2))
845 const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
847 vertex_t* const v0 = fetch_vertex(c, read_index(type, indices));
848 vertex_t* const v1 = fetch_vertex(c, read_index(type, indices));
849 const uint32_t cc = v0->flags & v1->flags;
850 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
851 c->prims.renderLine(c, v0, v1);
855 } while (count >= 0);
858 // ----------------------------------------------------------------------------
860 static void drawIndexedPrimitivesTriangleFanOrStrip(ogles_context_t* c,
861 GLsizei count, const GLvoid *indices, int winding)
863 // winding == 2 : fan
864 // winding == 1 : strip
866 if (ggl_unlikely(count < 3))
869 vertex_t * const v = c->vc.vBuffer;
874 const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
875 c->arrays.compileElement(c, v0, read_index(type, indices));
876 c->arrays.compileElement(c, v1, read_index(type, indices));
879 // note: GCC 4.1.1 here makes a prety interesting optimization
880 // where it duplicates the loop below based on c->arrays.indicesType
883 v2 = fetch_vertex(c, read_index(type, indices));
884 const uint32_t cc = v0->flags & v1->flags & v2->flags;
885 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
886 c->prims.renderTriangle(c, v0, v1, v2);
887 vertex_t* & consumed = ((winding^=1) ? v1 : v0);
888 consumed->locked = 0;
892 v0->locked = v1->locked = 0;
896 void drawIndexedPrimitivesTriangleStrip(ogles_context_t* c,
897 GLsizei count, const GLvoid *indices) {
898 drawIndexedPrimitivesTriangleFanOrStrip(c, count, indices, 1);
901 void drawIndexedPrimitivesTriangleFan(ogles_context_t* c,
902 GLsizei count, const GLvoid *indices) {
903 drawIndexedPrimitivesTriangleFanOrStrip(c, count, indices, 2);
906 void drawIndexedPrimitivesTriangles(ogles_context_t* c,
907 GLsizei count, const GLvoid *indices)
909 if (ggl_unlikely(count < 3))
913 if (ggl_likely(c->arrays.indicesType == GL_UNSIGNED_SHORT)) {
914 // This case is probably our most common case...
915 uint16_t const * p = (uint16_t const *)indices;
917 vertex_t* const v0 = fetch_vertex(c, *p++);
918 vertex_t* const v1 = fetch_vertex(c, *p++);
919 vertex_t* const v2 = fetch_vertex(c, *p++);
920 const uint32_t cc = v0->flags & v1->flags & v2->flags;
921 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
922 c->prims.renderTriangle(c, v0, v1, v2);
927 } while (count >= 0);
929 uint8_t const * p = (uint8_t const *)indices;
931 vertex_t* const v0 = fetch_vertex(c, *p++);
932 vertex_t* const v1 = fetch_vertex(c, *p++);
933 vertex_t* const v2 = fetch_vertex(c, *p++);
934 const uint32_t cc = v0->flags & v1->flags & v2->flags;
935 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
936 c->prims.renderTriangle(c, v0, v1, v2);
941 } while (count >= 0);
945 // ----------------------------------------------------------------------------
948 #pragma mark Array compilers
951 void compileElement__generic(ogles_context_t* c,
952 vertex_t* v, GLint first)
956 first &= vertex_cache_t::INDEX_MASK;
957 const GLubyte* vp = c->arrays.vertex.element(first);
960 c->arrays.vertex.fetch(c, v->obj.v, vp);
961 c->arrays.mvp_transform(&c->transforms.mvp, &v->clip, &v->obj);
962 c->arrays.perspective(c, v);
965 void compileElements__generic(ogles_context_t* c,
966 vertex_t* v, GLint first, GLsizei count)
968 const GLubyte* vp = c->arrays.vertex.element(
969 first & vertex_cache_t::INDEX_MASK);
970 const size_t stride = c->arrays.vertex.stride;
971 transform_t const* const mvp = &c->transforms.mvp;
977 c->arrays.vertex.fetch(c, v->obj.v, vp);
978 c->arrays.mvp_transform(mvp, &v->clip, &v->obj);
979 c->arrays.perspective(c, v);
986 void compileElements__3x_full(ogles_context_t* c,
987 vertex_t* v, GLint first, GLsizei count)
989 const GLfixed* vp = (const GLfixed*)c->arrays.vertex.element(first);
990 const size_t stride = c->arrays.vertex.stride / 4;
991 // const GLfixed* const& m = c->transforms.mvp.matrix.m;
994 memcpy(&m, c->transforms.mvp.matrix.m, sizeof(m));
997 const GLfixed rx = vp[0];
998 const GLfixed ry = vp[1];
999 const GLfixed rz = vp[2];
1002 v->clip.x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]);
1003 v->clip.y = mla3a(rx, m[ 1], ry, m[ 5], rz, m[ 9], m[13]);
1004 v->clip.z = mla3a(rx, m[ 2], ry, m[ 6], rz, m[10], m[14]);
1005 v->clip.w = mla3a(rx, m[ 3], ry, m[ 7], rz, m[11], m[15]);
1007 const GLfixed w = v->clip.w;
1009 if (v->clip.x < -w) clip |= vertex_t::CLIP_L;
1010 if (v->clip.x > w) clip |= vertex_t::CLIP_R;
1011 if (v->clip.y < -w) clip |= vertex_t::CLIP_B;
1012 if (v->clip.y > w) clip |= vertex_t::CLIP_T;
1013 if (v->clip.z < -w) clip |= vertex_t::CLIP_N;
1014 if (v->clip.z > w) clip |= vertex_t::CLIP_F;
1016 c->arrays.cull &= clip;
1018 //c->arrays.perspective(c, v);
1024 // ----------------------------------------------------------------------------
1027 #pragma mark clippers
1030 static void clipVec4(vec4_t& nv,
1031 GLfixed t, const vec4_t& s, const vec4_t& p)
1033 for (int i=0; i<4 ; i++)
1034 nv.v[i] = gglMulAddx(t, s.v[i] - p.v[i], p.v[i], 28);
1037 static void clipVertex(ogles_context_t* c, vertex_t* nv,
1038 GLfixed t, const vertex_t* s, const vertex_t* p)
1040 clipVec4(nv->clip, t, s->clip, p->clip);
1041 nv->fog = gglMulAddx(t, s->fog - p->fog, p->fog, 28);
1042 ogles_vertex_project(c, nv);
1043 nv->flags |= vertex_t::LIT | vertex_t::EYE | vertex_t::TT;
1044 nv->flags &= ~vertex_t::CLIP_ALL;
1047 static void clipVertexC(ogles_context_t* c, vertex_t* nv,
1048 GLfixed t, const vertex_t* s, const vertex_t* p)
1050 clipVec4(nv->color, t, s->color, p->color);
1051 clipVertex(c, nv, t, s, p);
1054 static void clipVertexT(ogles_context_t* c, vertex_t* nv,
1055 GLfixed t, const vertex_t* s, const vertex_t* p)
1057 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
1058 if (c->rasterizer.state.texture[i].enable)
1059 clipVec4(nv->texture[i], t, s->texture[i], p->texture[i]);
1061 clipVertex(c, nv, t, s, p);
1064 static void clipVertexAll(ogles_context_t* c, vertex_t* nv,
1065 GLfixed t, const vertex_t* s, const vertex_t* p)
1067 clipVec4(nv->color, t, s->color, p->color);
1068 clipVertexT(c, nv, t, s, p);
1071 static void clipEye(ogles_context_t* c, vertex_t* nv,
1072 GLfixed t, const vertex_t* s, const vertex_t* p)
1075 c->arrays.clipVertex(c, nv, t, p, s);
1076 clipVec4(nv->eye, t, s->eye, p->eye);
1079 // ----------------------------------------------------------------------------
1084 void validate_arrays(ogles_context_t* c, GLenum mode)
1086 uint32_t enables = c->rasterizer.state.enables;
1088 // Perspective correction is not need if Ortho transform, but
1089 // the user can still provide the w coordinate manually, so we can't
1090 // automatically turn it off (in fact we could when the 4th coordinate
1091 // is not spcified in the vertex array).
1092 // W interpolation is never needed for points.
1093 GLboolean perspective =
1094 c->perspective && mode!=GL_POINTS && (enables & GGL_ENABLE_TMUS);
1095 c->rasterizer.procs.enableDisable(c, GGL_W_LERP, perspective);
1097 // set anti-aliasing
1098 GLboolean smooth = GL_FALSE;
1101 smooth = c->point.smooth;
1106 smooth = c->line.smooth;
1109 if (((enables & GGL_ENABLE_AA)?1:0) != smooth)
1110 c->rasterizer.procs.enableDisable(c, GGL_AA, smooth);
1112 // set the shade model for this primitive
1113 c->rasterizer.procs.shadeModel(c,
1114 (mode == GL_POINTS) ? GL_FLAT : c->lighting.shadeModel);
1116 // compute all the matrices we'll need...
1118 transform_state_t::MVP |
1119 transform_state_t::VIEWPORT;
1120 if (c->lighting.enable) { // needs normal transforms and eye coords
1121 want |= transform_state_t::MVUI;
1122 want |= transform_state_t::MODELVIEW;
1124 if (enables & GGL_ENABLE_TMUS) { // needs texture transforms
1125 want |= transform_state_t::TEXTURE;
1127 if (c->clipPlanes.enable || (enables & GGL_ENABLE_FOG)) {
1128 want |= transform_state_t::MODELVIEW; // needs eye coords
1130 ogles_validate_transform(c, want);
1133 if (enables & GGL_ENABLE_TMUS)
1134 ogles_validate_texture(c);
1137 c->arrays.compileElement = compileElement__generic;
1138 c->arrays.compileElements = compileElements__generic;
1141 c->arrays.mvp_transform =
1142 c->transforms.mvp.pointv[c->arrays.vertex.size - 2];
1144 c->arrays.mv_transform =
1145 c->transforms.modelview.transform.pointv[c->arrays.vertex.size - 2];
1148 * ***********************************************************************
1150 * ***********************************************************************
1153 array_machine_t& am = c->arrays;
1154 am.vertex.fetch = fetchNop;
1155 am.normal.fetch = currentNormal;
1156 am.color.fetch = currentColor;
1158 if (am.vertex.enable) {
1159 am.vertex.resolve();
1160 if (am.vertex.bo || am.vertex.pointer) {
1161 am.vertex.fetch = vertex_fct[am.vertex.size-2][am.vertex.type & 0xF];
1165 if (am.normal.enable) {
1166 am.normal.resolve();
1167 if (am.normal.bo || am.normal.pointer) {
1168 am.normal.fetch = normal_fct[am.normal.size-3][am.normal.type & 0xF];
1172 if (am.color.enable) {
1174 if (c->lighting.enable) {
1175 if (am.color.bo || am.color.pointer) {
1176 am.color.fetch = color_fct[am.color.size-3][am.color.type & 0xF];
1179 if (am.color.bo || am.color.pointer) {
1180 am.color.fetch = color_clamp_fct[am.color.size-3][am.color.type & 0xF];
1185 int activeTmuCount = 0;
1186 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
1187 am.texture[i].fetch = currentTexCoord;
1188 if (c->rasterizer.state.texture[i].enable) {
1190 // texture fetchers...
1191 if (am.texture[i].enable) {
1192 am.texture[i].resolve();
1193 if (am.texture[i].bo || am.texture[i].pointer) {
1194 am.texture[i].fetch = texture_fct[am.texture[i].size-2][am.texture[i].type & 0xF];
1198 // texture transform...
1199 const int index = c->arrays.texture[i].size - 2;
1200 c->arrays.tex_transform[i] =
1201 c->transforms.texture[i].transform.pointv[index];
1208 // pick the vertex-clipper
1209 uint32_t clipper = 0;
1210 // we must reload 'enables' here
1211 enables = c->rasterizer.state.enables;
1212 if (enables & GGL_ENABLE_SMOOTH)
1213 clipper |= 1; // we need to interpolate colors
1214 if (enables & GGL_ENABLE_TMUS)
1215 clipper |= 2; // we need to interpolate textures
1217 case 0: c->arrays.clipVertex = clipVertex; break;
1218 case 1: c->arrays.clipVertex = clipVertexC; break;
1219 case 2: c->arrays.clipVertex = clipVertexT; break;
1220 case 3: c->arrays.clipVertex = clipVertexAll; break;
1222 c->arrays.clipEye = clipEye;
1224 // pick the primitive rasterizer
1225 ogles_validate_primitives(c);
1228 // ----------------------------------------------------------------------------
1229 }; // namespace android
1230 // ----------------------------------------------------------------------------
1232 using namespace android;
1236 #pragma mark array API
1239 void glVertexPointer(
1240 GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
1242 ogles_context_t* c = ogles_context_t::get();
1243 if (size<2 || size>4 || stride<0) {
1244 ogles_error(c, GL_INVALID_VALUE);
1254 ogles_error(c, GL_INVALID_ENUM);
1257 c->arrays.vertex.init(size, type, stride, pointer, c->arrays.array_buffer, 0);
1260 void glColorPointer(
1261 GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
1263 ogles_context_t* c = ogles_context_t::get();
1264 if (size!=4 || stride<0) {
1265 ogles_error(c, GL_INVALID_VALUE);
1269 case GL_UNSIGNED_BYTE:
1274 ogles_error(c, GL_INVALID_ENUM);
1277 c->arrays.color.init(size, type, stride, pointer, c->arrays.array_buffer, 0);
1280 void glNormalPointer(
1281 GLenum type, GLsizei stride, const GLvoid *pointer)
1283 ogles_context_t* c = ogles_context_t::get();
1285 ogles_error(c, GL_INVALID_VALUE);
1295 ogles_error(c, GL_INVALID_ENUM);
1298 c->arrays.normal.init(3, type, stride, pointer, c->arrays.array_buffer, 0);
1301 void glTexCoordPointer(
1302 GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
1304 ogles_context_t* c = ogles_context_t::get();
1305 if (size<2 || size>4 || stride<0) {
1306 ogles_error(c, GL_INVALID_VALUE);
1316 ogles_error(c, GL_INVALID_ENUM);
1319 const int tmu = c->arrays.activeTexture;
1320 c->arrays.texture[tmu].init(size, type, stride, pointer,
1321 c->arrays.array_buffer, 0);
1325 void glEnableClientState(GLenum array) {
1326 ogles_context_t* c = ogles_context_t::get();
1327 enableDisableClientState(c, array, true);
1330 void glDisableClientState(GLenum array) {
1331 ogles_context_t* c = ogles_context_t::get();
1332 enableDisableClientState(c, array, false);
1335 void glClientActiveTexture(GLenum texture)
1337 ogles_context_t* c = ogles_context_t::get();
1338 if (texture<GL_TEXTURE0 || texture>=GL_TEXTURE0+GGL_TEXTURE_UNIT_COUNT) {
1339 ogles_error(c, GL_INVALID_ENUM);
1342 c->arrays.activeTexture = texture - GL_TEXTURE0;
1345 void glDrawArrays(GLenum mode, GLint first, GLsizei count)
1347 ogles_context_t* c = ogles_context_t::get();
1349 ogles_error(c, GL_INVALID_VALUE);
1357 case GL_TRIANGLE_STRIP:
1358 case GL_TRIANGLE_FAN:
1362 ogles_error(c, GL_INVALID_ENUM);
1366 if (count == 0 || !c->arrays.vertex.enable)
1368 if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK))
1369 return; // all triangles are culled
1372 validate_arrays(c, mode);
1374 const uint32_t enables = c->rasterizer.state.enables;
1375 if (enables & GGL_ENABLE_TMUS)
1376 ogles_lock_textures(c);
1378 drawArraysPrims[mode](c, first, count);
1380 if (enables & GGL_ENABLE_TMUS)
1381 ogles_unlock_textures(c);
1383 #if VC_CACHE_STATISTICS
1384 c->vc.total = count;
1385 c->vc.dump_stats(mode);
1389 void glDrawElements(
1390 GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
1392 ogles_context_t* c = ogles_context_t::get();
1394 ogles_error(c, GL_INVALID_VALUE);
1402 case GL_TRIANGLE_STRIP:
1403 case GL_TRIANGLE_FAN:
1407 ogles_error(c, GL_INVALID_ENUM);
1411 case GL_UNSIGNED_BYTE:
1412 case GL_UNSIGNED_SHORT:
1413 c->arrays.indicesType = type;
1416 ogles_error(c, GL_INVALID_ENUM);
1419 if (count == 0 || !c->arrays.vertex.enable)
1421 if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK))
1422 return; // all triangles are culled
1424 // clear the vertex-cache
1426 validate_arrays(c, mode);
1428 // if indices are in a buffer object, the pointer is treated as an
1429 // offset in that buffer.
1430 if (c->arrays.element_array_buffer) {
1431 indices = c->arrays.element_array_buffer->data + uintptr_t(indices);
1434 const uint32_t enables = c->rasterizer.state.enables;
1435 if (enables & GGL_ENABLE_TMUS)
1436 ogles_lock_textures(c);
1438 drawElementsPrims[mode](c, count, indices);
1440 if (enables & GGL_ENABLE_TMUS)
1441 ogles_unlock_textures(c);
1444 #if VC_CACHE_STATISTICS
1445 c->vc.total = count;
1446 c->vc.dump_stats(mode);
1450 // ----------------------------------------------------------------------------
1452 // ----------------------------------------------------------------------------
1454 void glBindBuffer(GLenum target, GLuint buffer)
1456 ogles_context_t* c = ogles_context_t::get();
1457 if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) {
1458 ogles_error(c, GL_INVALID_ENUM);
1461 // create a buffer object, or bind an existing one
1462 buffer_t const* bo = 0;
1464 bo = c->bufferObjectManager->bind(buffer);
1466 ogles_error(c, GL_OUT_OF_MEMORY);
1470 ((target == GL_ARRAY_BUFFER) ?
1471 c->arrays.array_buffer : c->arrays.element_array_buffer) = bo;
1474 void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
1476 ogles_context_t* c = ogles_context_t::get();
1477 if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) {
1478 ogles_error(c, GL_INVALID_ENUM);
1482 ogles_error(c, GL_INVALID_VALUE);
1485 if ((usage!=GL_STATIC_DRAW) && (usage!=GL_DYNAMIC_DRAW)) {
1486 ogles_error(c, GL_INVALID_ENUM);
1489 buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
1490 c->arrays.array_buffer : c->arrays.element_array_buffer);
1493 // can't modify buffer 0
1494 ogles_error(c, GL_INVALID_OPERATION);
1498 buffer_t* edit_bo = const_cast<buffer_t*>(bo);
1499 if (c->bufferObjectManager->allocateStore(edit_bo, size, usage) != 0) {
1500 ogles_error(c, GL_OUT_OF_MEMORY);
1504 memcpy(bo->data, data, size);
1508 void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
1510 ogles_context_t* c = ogles_context_t::get();
1511 if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) {
1512 ogles_error(c, GL_INVALID_ENUM);
1515 if (offset<0 || size<0 || data==0) {
1516 ogles_error(c, GL_INVALID_VALUE);
1519 buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
1520 c->arrays.array_buffer : c->arrays.element_array_buffer);
1523 // can't modify buffer 0
1524 ogles_error(c, GL_INVALID_OPERATION);
1527 if (offset+size > bo->size) {
1528 ogles_error(c, GL_INVALID_VALUE);
1531 memcpy(bo->data + offset, data, size);
1534 void glDeleteBuffers(GLsizei n, const GLuint* buffers)
1536 ogles_context_t* c = ogles_context_t::get();
1538 ogles_error(c, GL_INVALID_VALUE);
1542 for (int i=0 ; i<n ; i++) {
1543 GLuint name = buffers[i];
1545 // unbind bound deleted buffers...
1546 if (c->arrays.element_array_buffer) {
1547 if (c->arrays.element_array_buffer->name == name) {
1548 c->arrays.element_array_buffer = 0;
1551 if (c->arrays.array_buffer) {
1552 if (c->arrays.array_buffer->name == name) {
1553 c->arrays.array_buffer = 0;
1556 if (c->arrays.vertex.bo) {
1557 if (c->arrays.vertex.bo->name == name) {
1558 c->arrays.vertex.bo = 0;
1561 if (c->arrays.normal.bo) {
1562 if (c->arrays.normal.bo->name == name) {
1563 c->arrays.normal.bo = 0;
1566 if (c->arrays.color.bo) {
1567 if (c->arrays.color.bo->name == name) {
1568 c->arrays.color.bo = 0;
1571 for (int t=0 ; t<GGL_TEXTURE_UNIT_COUNT ; t++) {
1572 if (c->arrays.texture[t].bo) {
1573 if (c->arrays.texture[t].bo->name == name) {
1574 c->arrays.texture[t].bo = 0;
1580 c->bufferObjectManager->deleteBuffers(n, buffers);
1581 c->bufferObjectManager->recycleTokens(n, buffers);
1584 void glGenBuffers(GLsizei n, GLuint* buffers)
1586 ogles_context_t* c = ogles_context_t::get();
1588 ogles_error(c, GL_INVALID_VALUE);
1591 c->bufferObjectManager->getToken(n, buffers);