blob: 4878722f0bd48048355900a86a3e6b26dbe52165 [file] [log] [blame]
Mathias Agopian1473f462009-04-10 14:24:30 -07001/*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002** Copyright 2006, The Android Open Source Project
3**
Mathias Agopian1473f462009-04-10 14:24:30 -07004** 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007**
Mathias Agopian1473f462009-04-10 14:24:30 -07008** http://www.apache.org/licenses/LICENSE-2.0
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009**
Mathias Agopian1473f462009-04-10 14:24:30 -070010** 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014** limitations under the License.
15*/
16
17#include <stdlib.h>
18#include <stdio.h>
19
20#include "context.h"
21#include "fp.h"
22#include "state.h"
23#include "matrix.h"
24#include "vertex.h"
25#include "light.h"
26#include "primitives.h"
27#include "texture.h"
28#include "BufferObjectManager.h"
Mathias Agopian1473f462009-04-10 14:24:30 -070029#ifdef LIBAGL_USE_GRALLOC_COPYBITS
30#include "copybit.h"
31#endif // LIBAGL_USE_GRALLOC_COPYBITS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032
33// ----------------------------------------------------------------------------
34
35#define VC_CACHE_STATISTICS 0
36#define VC_CACHE_TYPE_NONE 0
37#define VC_CACHE_TYPE_INDEXED 1
38#define VC_CACHE_TYPE_LRU 2
39#define VC_CACHE_TYPE VC_CACHE_TYPE_INDEXED
40
41#if VC_CACHE_STATISTICS
42#include <utils/Timers.h>
43#endif
44
45// ----------------------------------------------------------------------------
46
47namespace android {
48
49static void validate_arrays(ogles_context_t* c, GLenum mode);
50
51static void compileElements__generic(ogles_context_t*,
52 vertex_t*, GLint, GLsizei);
53static void compileElement__generic(ogles_context_t*,
54 vertex_t*, GLint);
55
56static void drawPrimitivesPoints(ogles_context_t*, GLint, GLsizei);
57static void drawPrimitivesLineStrip(ogles_context_t*, GLint, GLsizei);
58static void drawPrimitivesLineLoop(ogles_context_t*, GLint, GLsizei);
59static void drawPrimitivesLines(ogles_context_t*, GLint, GLsizei);
60static void drawPrimitivesTriangleStrip(ogles_context_t*, GLint, GLsizei);
61static void drawPrimitivesTriangleFan(ogles_context_t*, GLint, GLsizei);
62static void drawPrimitivesTriangles(ogles_context_t*, GLint, GLsizei);
63
64static void drawIndexedPrimitivesPoints(ogles_context_t*,
65 GLsizei, const GLvoid*);
66static void drawIndexedPrimitivesLineStrip(ogles_context_t*,
67 GLsizei, const GLvoid*);
68static void drawIndexedPrimitivesLineLoop(ogles_context_t*,
69 GLsizei, const GLvoid*);
70static void drawIndexedPrimitivesLines(ogles_context_t*,
71 GLsizei, const GLvoid*);
72static void drawIndexedPrimitivesTriangleStrip(ogles_context_t*,
73 GLsizei, const GLvoid*);
74static void drawIndexedPrimitivesTriangleFan(ogles_context_t*,
75 GLsizei, const GLvoid*);
76static void drawIndexedPrimitivesTriangles(ogles_context_t*,
77 GLsizei, const GLvoid*);
78
79// ----------------------------------------------------------------------------
80
81typedef void (*arrays_prims_fct_t)(ogles_context_t*, GLint, GLsizei);
82static const arrays_prims_fct_t drawArraysPrims[] = {
83 drawPrimitivesPoints,
84 drawPrimitivesLines,
85 drawPrimitivesLineLoop,
86 drawPrimitivesLineStrip,
87 drawPrimitivesTriangles,
88 drawPrimitivesTriangleStrip,
89 drawPrimitivesTriangleFan
90};
91
92typedef void (*elements_prims_fct_t)(ogles_context_t*, GLsizei, const GLvoid*);
93static const elements_prims_fct_t drawElementsPrims[] = {
94 drawIndexedPrimitivesPoints,
95 drawIndexedPrimitivesLines,
96 drawIndexedPrimitivesLineLoop,
97 drawIndexedPrimitivesLineStrip,
98 drawIndexedPrimitivesTriangles,
99 drawIndexedPrimitivesTriangleStrip,
100 drawIndexedPrimitivesTriangleFan
101};
102
103// ----------------------------------------------------------------------------
104#if 0
105#pragma mark -
106#endif
107
108void ogles_init_array(ogles_context_t* c)
109{
110 c->arrays.vertex.size = 4;
111 c->arrays.vertex.type = GL_FLOAT;
112 c->arrays.color.size = 4;
113 c->arrays.color.type = GL_FLOAT;
114 c->arrays.normal.size = 4;
115 c->arrays.normal.type = GL_FLOAT;
116 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
117 c->arrays.texture[i].size = 4;
118 c->arrays.texture[i].type = GL_FLOAT;
119 }
120 c->vc.init();
121
122 if (!c->vc.vBuffer) {
123 // this could have failed
124 ogles_error(c, GL_OUT_OF_MEMORY);
125 }
126}
127
128void ogles_uninit_array(ogles_context_t* c)
129{
130 c->vc.uninit();
131}
132
133// ----------------------------------------------------------------------------
134#if 0
135#pragma mark -
136#pragma mark Array fetchers
137#endif
138
139static void currentColor(ogles_context_t* c, GLfixed* v, const GLvoid*) {
140 memcpy(v, c->current.color.v, sizeof(vec4_t));
141}
142static void currentColor_clamp(ogles_context_t* c, GLfixed* v, const GLvoid*) {
143 memcpy(v, c->currentColorClamped.v, sizeof(vec4_t));
144}
145static void currentNormal(ogles_context_t* c, GLfixed* v, const GLvoid*) {
146 memcpy(v, c->currentNormal.v, sizeof(vec3_t));
147}
148static void currentTexCoord(ogles_context_t* c, GLfixed* v, const GLvoid*) {
149 memcpy(v, c->current.texture[c->arrays.tmu].v, sizeof(vec4_t));
150}
151
152
153static void fetchNop(ogles_context_t*, GLfixed*, const GLvoid*) {
154}
155static void fetch2b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
156 v[0] = gglIntToFixed(p[0]);
157 v[1] = gglIntToFixed(p[1]);
158}
159static void fetch2s(ogles_context_t*, GLfixed* v, const GLshort* p) {
160 v[0] = gglIntToFixed(p[0]);
161 v[1] = gglIntToFixed(p[1]);
162}
163static void fetch2x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
164 memcpy(v, p, 2*sizeof(GLfixed));
165}
166static void fetch2f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
167 v[0] = gglFloatToFixed(p[0]);
168 v[1] = gglFloatToFixed(p[1]);
169}
170static void fetch3b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
171 v[0] = gglIntToFixed(p[0]);
172 v[1] = gglIntToFixed(p[1]);
173 v[2] = gglIntToFixed(p[2]);
174}
175static void fetch3s(ogles_context_t*, GLfixed* v, const GLshort* p) {
176 v[0] = gglIntToFixed(p[0]);
177 v[1] = gglIntToFixed(p[1]);
178 v[2] = gglIntToFixed(p[2]);
179}
180static void fetch3x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
181 memcpy(v, p, 3*sizeof(GLfixed));
182}
183static void fetch3f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
184 v[0] = gglFloatToFixed(p[0]);
185 v[1] = gglFloatToFixed(p[1]);
186 v[2] = gglFloatToFixed(p[2]);
187}
188static void fetch4b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
189 v[0] = gglIntToFixed(p[0]);
190 v[1] = gglIntToFixed(p[1]);
191 v[2] = gglIntToFixed(p[2]);
192 v[3] = gglIntToFixed(p[3]);
193}
194static void fetch4s(ogles_context_t*, GLfixed* v, const GLshort* p) {
195 v[0] = gglIntToFixed(p[0]);
196 v[1] = gglIntToFixed(p[1]);
197 v[2] = gglIntToFixed(p[2]);
198 v[3] = gglIntToFixed(p[3]);
199}
200static void fetch4x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
201 memcpy(v, p, 4*sizeof(GLfixed));
202}
203static void fetch4f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
204 v[0] = gglFloatToFixed(p[0]);
205 v[1] = gglFloatToFixed(p[1]);
206 v[2] = gglFloatToFixed(p[2]);
207 v[3] = gglFloatToFixed(p[3]);
208}
209static void fetchExpand4ub(ogles_context_t*, GLfixed* v, const GLubyte* p) {
210 v[0] = GGL_UB_TO_X(p[0]);
211 v[1] = GGL_UB_TO_X(p[1]);
212 v[2] = GGL_UB_TO_X(p[2]);
213 v[3] = GGL_UB_TO_X(p[3]);
214}
215static void fetchClamp4x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
216 v[0] = gglClampx(p[0]);
217 v[1] = gglClampx(p[1]);
218 v[2] = gglClampx(p[2]);
219 v[3] = gglClampx(p[3]);
220}
221static void fetchClamp4f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
222 v[0] = gglClampx(gglFloatToFixed(p[0]));
223 v[1] = gglClampx(gglFloatToFixed(p[1]));
224 v[2] = gglClampx(gglFloatToFixed(p[2]));
225 v[3] = gglClampx(gglFloatToFixed(p[3]));
226}
227static void fetchExpand3ub(ogles_context_t*, GLfixed* v, const GLubyte* p) {
228 v[0] = GGL_UB_TO_X(p[0]);
229 v[1] = GGL_UB_TO_X(p[1]);
230 v[2] = GGL_UB_TO_X(p[2]);
231 v[3] = 0x10000;
232}
233static void fetchClamp3x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
234 v[0] = gglClampx(p[0]);
235 v[1] = gglClampx(p[1]);
236 v[2] = gglClampx(p[2]);
237 v[3] = 0x10000;
238}
239static void fetchClamp3f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
240 v[0] = gglClampx(gglFloatToFixed(p[0]));
241 v[1] = gglClampx(gglFloatToFixed(p[1]));
242 v[2] = gglClampx(gglFloatToFixed(p[2]));
243 v[3] = 0x10000;
244}
245static void fetchExpand3b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
246 v[0] = GGL_B_TO_X(p[0]);
247 v[1] = GGL_B_TO_X(p[1]);
248 v[2] = GGL_B_TO_X(p[2]);
249}
250static void fetchExpand3s(ogles_context_t*, GLfixed* v, const GLshort* p) {
251 v[0] = GGL_S_TO_X(p[0]);
252 v[1] = GGL_S_TO_X(p[1]);
253 v[2] = GGL_S_TO_X(p[2]);
254}
255
Mathias Agopian1473f462009-04-10 14:24:30 -0700256typedef array_t::fetcher_t fn_t;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800257
258static const fn_t color_fct[2][16] = { // size={3,4}, type={ub,f,x}
259 { 0, (fn_t)fetchExpand3ub, 0, 0, 0, 0,
260 (fn_t)fetch3f, 0, 0, 0, 0, 0,
261 (fn_t)fetch3x },
262 { 0, (fn_t)fetchExpand4ub, 0, 0, 0, 0,
263 (fn_t)fetch4f, 0, 0, 0, 0, 0,
264 (fn_t)fetch4x },
265};
266static const fn_t color_clamp_fct[2][16] = { // size={3,4}, type={ub,f,x}
267 { 0, (fn_t)fetchExpand3ub, 0, 0, 0, 0,
268 (fn_t)fetchClamp3f, 0, 0, 0, 0, 0,
269 (fn_t)fetchClamp3x },
270 { 0, (fn_t)fetchExpand4ub, 0, 0, 0, 0,
271 (fn_t)fetchClamp4f, 0, 0, 0, 0, 0,
272 (fn_t)fetchClamp4x },
273};
274static const fn_t normal_fct[1][16] = { // size={3}, type={b,s,f,x}
275 { (fn_t)fetchExpand3b, 0,
276 (fn_t)fetchExpand3s, 0, 0, 0,
277 (fn_t)fetch3f, 0, 0, 0, 0, 0,
278 (fn_t)fetch3x },
279};
280static const fn_t vertex_fct[3][16] = { // size={2,3,4}, type={b,s,f,x}
281 { (fn_t)fetch2b, 0,
282 (fn_t)fetch2s, 0, 0, 0,
283 (fn_t)fetch2f, 0, 0, 0, 0, 0,
284 (fn_t)fetch3x },
285 { (fn_t)fetch3b, 0,
286 (fn_t)fetch3s, 0, 0, 0,
287 (fn_t)fetch3f, 0, 0, 0, 0, 0,
288 (fn_t)fetch3x },
289 { (fn_t)fetch4b, 0,
290 (fn_t)fetch4s, 0, 0, 0,
291 (fn_t)fetch4f, 0, 0, 0, 0, 0,
292 (fn_t)fetch4x }
293};
294static const fn_t texture_fct[3][16] = { // size={2,3,4}, type={b,s,f,x}
295 { (fn_t)fetch2b, 0,
296 (fn_t)fetch2s, 0, 0, 0,
297 (fn_t)fetch2f, 0, 0, 0, 0, 0,
298 (fn_t)fetch2x },
299 { (fn_t)fetch3b, 0,
300 (fn_t)fetch3s, 0, 0, 0,
301 (fn_t)fetch3f, 0, 0, 0, 0, 0,
302 (fn_t)fetch3x },
303 { (fn_t)fetch4b, 0,
304 (fn_t)fetch4s, 0, 0, 0,
305 (fn_t)fetch4f, 0, 0, 0, 0, 0,
306 (fn_t)fetch4x }
307};
308
309// ----------------------------------------------------------------------------
310#if 0
311#pragma mark -
312#pragma mark array_t
313#endif
314
315void array_t::init(
316 GLint size, GLenum type, GLsizei stride,
317 const GLvoid *pointer, const buffer_t* bo, GLsizei count)
318{
319 if (!stride) {
320 stride = size;
321 switch (type) {
322 case GL_SHORT:
323 case GL_UNSIGNED_SHORT:
324 stride *= 2;
325 break;
326 case GL_FLOAT:
327 case GL_FIXED:
328 stride *= 4;
329 break;
330 }
331 }
332 this->size = size;
333 this->type = type;
334 this->stride = stride;
335 this->pointer = pointer;
336 this->bo = bo;
337 this->bounds = count;
338}
339
Mathias Agopian1473f462009-04-10 14:24:30 -0700340inline void array_t::resolve()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341{
342 physical_pointer = (bo) ? (bo->data + uintptr_t(pointer)) : pointer;
343}
344
345// ----------------------------------------------------------------------------
346#if 0
347#pragma mark -
348#pragma mark vertex_cache_t
349#endif
350
351void vertex_cache_t::init()
352{
353 // make sure the size of vertex_t allows cache-line alignment
354 CTA<(sizeof(vertex_t) & 0x1F) == 0> assertAlignedSize;
355
356 const int align = 32;
357 const size_t s = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE;
358 const size_t size = s*sizeof(vertex_t) + align;
359 base = malloc(size);
360 if (base) {
361 memset(base, 0, size);
362 vBuffer = (vertex_t*)((size_t(base) + align - 1) & ~(align-1));
363 vCache = vBuffer + VERTEX_BUFFER_SIZE;
364 sequence = 0;
365 }
366}
367
368void vertex_cache_t::uninit()
369{
370 free(base);
371 base = vBuffer = vCache = 0;
372}
373
374void vertex_cache_t::clear()
375{
376#if VC_CACHE_STATISTICS
377 startTime = systemTime(SYSTEM_TIME_THREAD);
378 total = 0;
379 misses = 0;
380#endif
381
382#if VC_CACHE_TYPE == VC_CACHE_TYPE_LRU
383 vertex_t* v = vBuffer;
384 size_t count = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE;
385 do {
386 v->mru = 0;
387 v++;
388 } while (--count);
389#endif
390
391 sequence += INDEX_SEQ;
392 if (sequence >= 0x80000000LU) {
393 sequence = INDEX_SEQ;
394 vertex_t* v = vBuffer;
395 size_t count = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE;
396 do {
397 v->index = 0;
398 v++;
399 } while (--count);
400 }
401}
402
403void vertex_cache_t::dump_stats(GLenum mode)
404{
405#if VC_CACHE_STATISTICS
406 nsecs_t time = systemTime(SYSTEM_TIME_THREAD) - startTime;
407 uint32_t hits = total - misses;
408 uint32_t prim_count;
409 switch (mode) {
410 case GL_POINTS: prim_count = total; break;
411 case GL_LINE_STRIP: prim_count = total - 1; break;
412 case GL_LINE_LOOP: prim_count = total - 1; break;
413 case GL_LINES: prim_count = total / 2; break;
414 case GL_TRIANGLE_STRIP: prim_count = total - 2; break;
415 case GL_TRIANGLE_FAN: prim_count = total - 2; break;
416 case GL_TRIANGLES: prim_count = total / 3; break;
417 default: return;
418 }
419 printf( "total=%5u, hits=%5u, miss=%5u, hitrate=%3u%%,"
420 " prims=%5u, time=%6u us, prims/s=%d, v/t=%f\n",
421 total, hits, misses, (hits*100)/total,
422 prim_count, int(ns2us(time)), int(prim_count*float(seconds(1))/time),
423 float(misses) / prim_count);
424#endif
425}
426
427// ----------------------------------------------------------------------------
428#if 0
429#pragma mark -
430#endif
431
432static __attribute__((noinline))
433void enableDisableClientState(ogles_context_t* c, GLenum array, bool enable)
434{
435 const int tmu = c->arrays.activeTexture;
436 array_t* a;
437 switch (array) {
438 case GL_COLOR_ARRAY: a = &c->arrays.color; break;
439 case GL_NORMAL_ARRAY: a = &c->arrays.normal; break;
440 case GL_TEXTURE_COORD_ARRAY: a = &c->arrays.texture[tmu]; break;
441 case GL_VERTEX_ARRAY: a = &c->arrays.vertex; break;
442 default:
443 ogles_error(c, GL_INVALID_ENUM);
444 return;
445 }
446 a->enable = enable ? GL_TRUE : GL_FALSE;
447}
448
449// ----------------------------------------------------------------------------
450#if 0
451#pragma mark -
452#pragma mark Vertex Cache
453#endif
454
455static __attribute__((noinline))
456vertex_t* cache_vertex(ogles_context_t* c, vertex_t* v, uint32_t index)
457{
458 #if VC_CACHE_STATISTICS
459 c->vc.misses++;
460 #endif
461 if (ggl_unlikely(v->locked)) {
462 // we're just looking for an entry in the cache that is not locked.
463 // and we know that there cannot be more than 2 locked entries
464 // because a triangle needs at most 3 vertices.
465 // We never use the first and second entries because they might be in
466 // use by the striper or faner. Any other entry will do as long as
467 // it's not locked.
468 // We compute directly the index of a "free" entry from the locked
469 // state of v[2] and v[3].
470 v = c->vc.vBuffer + 2;
Mathias Agopian1473f462009-04-10 14:24:30 -0700471 v += v[0].locked | (v[1].locked<<1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472 }
473 // note: compileElement clears v->flags
474 c->arrays.compileElement(c, v, index);
475 v->locked = 1;
476 return v;
477}
478
479static __attribute__((noinline))
480vertex_t* fetch_vertex(ogles_context_t* c, size_t index)
481{
482 index |= c->vc.sequence;
483
484#if VC_CACHE_TYPE == VC_CACHE_TYPE_INDEXED
485
Mathias Agopian1473f462009-04-10 14:24:30 -0700486 vertex_t* const v = c->vc.vCache +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800487 (index & (vertex_cache_t::VERTEX_CACHE_SIZE-1));
488
489 if (ggl_likely(v->index == index)) {
490 v->locked = 1;
491 return v;
492 }
493 return cache_vertex(c, v, index);
494
495#elif VC_CACHE_TYPE == VC_CACHE_TYPE_LRU
496
Mathias Agopian1473f462009-04-10 14:24:30 -0700497 vertex_t* v = c->vc.vCache +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800498 (index & ((vertex_cache_t::VERTEX_CACHE_SIZE-1)>>1))*2;
499
500 // always record LRU in v[0]
501 if (ggl_likely(v[0].index == index)) {
502 v[0].locked = 1;
503 v[0].mru = 0;
504 return &v[0];
505 }
506
507 if (ggl_likely(v[1].index == index)) {
508 v[1].locked = 1;
509 v[0].mru = 1;
510 return &v[1];
511 }
512
513 const int lru = 1 - v[0].mru;
514 v[0].mru = lru;
515 return cache_vertex(c, &v[lru], index);
516
517#elif VC_CACHE_TYPE == VC_CACHE_TYPE_NONE
518
519 // just for debugging...
520 vertex_t* v = c->vc.vBuffer + 2;
521 return cache_vertex(c, v, index);
522
523#endif
524}
525
526// ----------------------------------------------------------------------------
527#if 0
528#pragma mark -
529#pragma mark Primitive Assembly
530#endif
531
532void drawPrimitivesPoints(ogles_context_t* c, GLint first, GLsizei count)
533{
534 if (ggl_unlikely(count < 1))
535 return;
536
537 // vertex cache size must be multiple of 1
Mathias Agopian1473f462009-04-10 14:24:30 -0700538 const GLsizei vcs =
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 (vertex_cache_t::VERTEX_BUFFER_SIZE +
540 vertex_cache_t::VERTEX_CACHE_SIZE);
541 do {
542 vertex_t* v = c->vc.vBuffer;
Mathias Agopian1473f462009-04-10 14:24:30 -0700543 GLsizei num = count > vcs ? vcs : count;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544 c->arrays.cull = vertex_t::CLIP_ALL;
545 c->arrays.compileElements(c, v, first, num);
546 first += num;
547 count -= num;
548 if (!c->arrays.cull) {
549 // quick/trivial reject of the whole batch
550 do {
551 const uint32_t cc = v[0].flags;
552 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
553 c->prims.renderPoint(c, v);
554 v++;
555 num--;
556 } while (num);
557 }
558 } while (count);
559}
560
561// ----------------------------------------------------------------------------
562
563void drawPrimitivesLineStrip(ogles_context_t* c, GLint first, GLsizei count)
564{
565 if (ggl_unlikely(count < 2))
566 return;
567
568 vertex_t *v, *v0, *v1;
569 c->arrays.cull = vertex_t::CLIP_ALL;
570 c->arrays.compileElement(c, c->vc.vBuffer, first);
571 first += 1;
572 count -= 1;
573
574 // vertex cache size must be multiple of 1
Mathias Agopian1473f462009-04-10 14:24:30 -0700575 const GLsizei vcs =
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576 (vertex_cache_t::VERTEX_BUFFER_SIZE +
577 vertex_cache_t::VERTEX_CACHE_SIZE - 1);
578 do {
Mathias Agopian1473f462009-04-10 14:24:30 -0700579 v0 = c->vc.vBuffer + 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580 v = c->vc.vBuffer + 1;
Mathias Agopian1473f462009-04-10 14:24:30 -0700581 GLsizei num = count > vcs ? vcs : count;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800582 c->arrays.compileElements(c, v, first, num);
583 first += num;
584 count -= num;
585 if (!c->arrays.cull) {
586 // quick/trivial reject of the whole batch
587 do {
588 v1 = v++;
589 const uint32_t cc = v0->flags & v1->flags;
590 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
591 c->prims.renderLine(c, v0, v1);
592 v0 = v1;
593 num--;
594 } while (num);
595 }
596 // copy back the last processed vertex
597 c->vc.vBuffer[0] = *v0;
598 c->arrays.cull = v0->flags & vertex_t::CLIP_ALL;
599 } while (count);
600}
601
602void drawPrimitivesLineLoop(ogles_context_t* c, GLint first, GLsizei count)
603{
604 if (ggl_unlikely(count < 2))
605 return;
606 drawPrimitivesLineStrip(c, first, count);
607 if (ggl_likely(count >= 3)) {
Mathias Agopian1473f462009-04-10 14:24:30 -0700608 vertex_t* v0 = c->vc.vBuffer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 vertex_t* v1 = c->vc.vBuffer + 1;
610 c->arrays.compileElement(c, v1, first);
611 const uint32_t cc = v0->flags & v1->flags;
612 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
613 c->prims.renderLine(c, v0, v1);
614 }
615}
616
617void drawPrimitivesLines(ogles_context_t* c, GLint first, GLsizei count)
618{
619 if (ggl_unlikely(count < 2))
620 return;
621
622 // vertex cache size must be multiple of 2
Mathias Agopian1473f462009-04-10 14:24:30 -0700623 const GLsizei vcs =
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800624 ((vertex_cache_t::VERTEX_BUFFER_SIZE +
625 vertex_cache_t::VERTEX_CACHE_SIZE) / 2) * 2;
626 do {
627 vertex_t* v = c->vc.vBuffer;
Mathias Agopian1473f462009-04-10 14:24:30 -0700628 GLsizei num = count > vcs ? vcs : count;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800629 c->arrays.cull = vertex_t::CLIP_ALL;
630 c->arrays.compileElements(c, v, first, num);
631 first += num;
632 count -= num;
633 if (!c->arrays.cull) {
634 // quick/trivial reject of the whole batch
635 num -= 2;
636 do {
637 const uint32_t cc = v[0].flags & v[1].flags;
638 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
639 c->prims.renderLine(c, v, v+1);
640 v += 2;
641 num -= 2;
642 } while (num >= 0);
643 }
644 } while (count >= 2);
645}
646
647// ----------------------------------------------------------------------------
648
649static void drawPrimitivesTriangleFanOrStrip(ogles_context_t* c,
650 GLint first, GLsizei count, int winding)
651{
652 // winding == 2 : fan
653 // winding == 1 : strip
654
655 if (ggl_unlikely(count < 3))
656 return;
657
658 vertex_t *v, *v0, *v1, *v2;
659 c->arrays.cull = vertex_t::CLIP_ALL;
660 c->arrays.compileElements(c, c->vc.vBuffer, first, 2);
661 first += 2;
662 count -= 2;
663
664 // vertex cache size must be multiple of 2. This is extremely important
665 // because it allows us to preserve the same winding when the whole
666 // batch is culled. We also need 2 extra vertices in the array, because
667 // we always keep the two first ones.
Mathias Agopian1473f462009-04-10 14:24:30 -0700668 const GLsizei vcs =
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800669 ((vertex_cache_t::VERTEX_BUFFER_SIZE +
670 vertex_cache_t::VERTEX_CACHE_SIZE - 2) / 2) * 2;
671 do {
Mathias Agopian1473f462009-04-10 14:24:30 -0700672 v0 = c->vc.vBuffer + 0;
673 v1 = c->vc.vBuffer + 1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800674 v = c->vc.vBuffer + 2;
Mathias Agopian1473f462009-04-10 14:24:30 -0700675 GLsizei num = count > vcs ? vcs : count;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800676 c->arrays.compileElements(c, v, first, num);
677 first += num;
678 count -= num;
679 if (!c->arrays.cull) {
680 // quick/trivial reject of the whole batch
681 do {
682 v2 = v++;
683 const uint32_t cc = v0->flags & v1->flags & v2->flags;
684 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
685 c->prims.renderTriangle(c, v0, v1, v2);
686 swap(((winding^=1) ? v1 : v0), v2);
687 num--;
688 } while (num);
689 }
690 if (count) {
691 v0 = c->vc.vBuffer + 2 + num - 2;
692 v1 = c->vc.vBuffer + 2 + num - 1;
693 if ((winding&2) == 0) {
694 // for strips copy back the two last compiled vertices
695 c->vc.vBuffer[0] = *v0;
696 }
697 c->vc.vBuffer[1] = *v1;
698 c->arrays.cull = v0->flags & v1->flags & vertex_t::CLIP_ALL;
699 }
700 } while (count > 0);
701}
702
Mathias Agopian1473f462009-04-10 14:24:30 -0700703void drawPrimitivesTriangleStrip(ogles_context_t* c,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800704 GLint first, GLsizei count) {
705 drawPrimitivesTriangleFanOrStrip(c, first, count, 1);
706}
707
708void drawPrimitivesTriangleFan(ogles_context_t* c,
709 GLint first, GLsizei count) {
Mathias Agopian1473f462009-04-10 14:24:30 -0700710#ifdef LIBAGL_USE_GRALLOC_COPYBITS
Mathias Agopian03a1b012009-06-17 21:18:56 -0700711 if (drawTriangleFanWithCopybit(c, first, count)) {
Mathias Agopian1473f462009-04-10 14:24:30 -0700712 return;
713 }
714#endif // LIBAGL_USE_GRALLOC_COPYBITS
715
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800716 drawPrimitivesTriangleFanOrStrip(c, first, count, 2);
717}
718
719void drawPrimitivesTriangles(ogles_context_t* c, GLint first, GLsizei count)
720{
721 if (ggl_unlikely(count < 3))
722 return;
723
724 // vertex cache size must be multiple of 3
Mathias Agopian1473f462009-04-10 14:24:30 -0700725 const GLsizei vcs =
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800726 ((vertex_cache_t::VERTEX_BUFFER_SIZE +
727 vertex_cache_t::VERTEX_CACHE_SIZE) / 3) * 3;
728 do {
729 vertex_t* v = c->vc.vBuffer;
Mathias Agopian1473f462009-04-10 14:24:30 -0700730 GLsizei num = count > vcs ? vcs : count;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800731 c->arrays.cull = vertex_t::CLIP_ALL;
732 c->arrays.compileElements(c, v, first, num);
733 first += num;
734 count -= num;
735 if (!c->arrays.cull) {
736 // quick/trivial reject of the whole batch
737 num -= 3;
738 do {
739 const uint32_t cc = v[0].flags & v[1].flags & v[2].flags;
740 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
741 c->prims.renderTriangle(c, v, v+1, v+2);
742 v += 3;
743 num -= 3;
744 } while (num >= 0);
745 }
746 } while (count >= 3);
747}
748
749// ----------------------------------------------------------------------------
750#if 0
751#pragma mark -
752#endif
753
754// this looks goofy, but gcc does a great job with this...
755static inline unsigned int read_index(int type, const GLvoid*& p) {
756 unsigned int r;
757 if (type) {
758 r = *(const GLubyte*)p;
759 p = (const GLubyte*)p + 1;
760 } else {
761 r = *(const GLushort*)p;
762 p = (const GLushort*)p + 1;
763 }
764 return r;
765}
766
767// ----------------------------------------------------------------------------
768
769void drawIndexedPrimitivesPoints(ogles_context_t* c,
770 GLsizei count, const GLvoid *indices)
771{
772 if (ggl_unlikely(count < 1))
773 return;
774 const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
775 do {
776 vertex_t * v = fetch_vertex(c, read_index(type, indices));
777 if (ggl_likely(!(v->flags & vertex_t::CLIP_ALL)))
778 c->prims.renderPoint(c, v);
779 v->locked = 0;
780 count--;
781 } while(count);
782}
783
784// ----------------------------------------------------------------------------
785
786void drawIndexedPrimitivesLineStrip(ogles_context_t* c,
787 GLsizei count, const GLvoid *indices)
788{
789 if (ggl_unlikely(count < 2))
790 return;
Mathias Agopian1473f462009-04-10 14:24:30 -0700791
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792 vertex_t * const v = c->vc.vBuffer;
793 vertex_t* v0 = v;
794 vertex_t* v1;
Mathias Agopian1473f462009-04-10 14:24:30 -0700795
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800796 const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
797 c->arrays.compileElement(c, v0, read_index(type, indices));
798 count -= 1;
799 do {
800 v1 = fetch_vertex(c, read_index(type, indices));
801 const uint32_t cc = v0->flags & v1->flags;
802 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
803 c->prims.renderLine(c, v0, v1);
804 v0->locked = 0;
805 v0 = v1;
806 count--;
807 } while (count);
808 v1->locked = 0;
809}
810
811void drawIndexedPrimitivesLineLoop(ogles_context_t* c,
812 GLsizei count, const GLvoid *indices)
813{
814 if (ggl_unlikely(count <= 2)) {
815 drawIndexedPrimitivesLines(c, count, indices);
816 return;
817 }
Mathias Agopian1473f462009-04-10 14:24:30 -0700818
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800819 vertex_t * const v = c->vc.vBuffer;
820 vertex_t* v0 = v;
821 vertex_t* v1;
Mathias Agopian1473f462009-04-10 14:24:30 -0700822
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823 const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
824 c->arrays.compileElement(c, v0, read_index(type, indices));
825 count -= 1;
826 do {
827 v1 = fetch_vertex(c, read_index(type, indices));
828 const uint32_t cc = v0->flags & v1->flags;
829 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
830 c->prims.renderLine(c, v0, v1);
831 v0->locked = 0;
832 v0 = v1;
833 count--;
834 } while (count);
835 v1->locked = 0;
836
Mathias Agopian1473f462009-04-10 14:24:30 -0700837 v1 = c->vc.vBuffer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800838 const uint32_t cc = v0->flags & v1->flags;
839 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
840 c->prims.renderLine(c, v0, v1);
841}
842
843void drawIndexedPrimitivesLines(ogles_context_t* c,
844 GLsizei count, const GLvoid *indices)
845{
846 if (ggl_unlikely(count < 2))
847 return;
848
849 count -= 2;
850 const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
851 do {
852 vertex_t* const v0 = fetch_vertex(c, read_index(type, indices));
853 vertex_t* const v1 = fetch_vertex(c, read_index(type, indices));
854 const uint32_t cc = v0->flags & v1->flags;
855 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
856 c->prims.renderLine(c, v0, v1);
857 v0->locked = 0;
858 v1->locked = 0;
859 count -= 2;
860 } while (count >= 0);
861}
862
863// ----------------------------------------------------------------------------
864
865static void drawIndexedPrimitivesTriangleFanOrStrip(ogles_context_t* c,
866 GLsizei count, const GLvoid *indices, int winding)
867{
868 // winding == 2 : fan
869 // winding == 1 : strip
870
871 if (ggl_unlikely(count < 3))
872 return;
Mathias Agopian1473f462009-04-10 14:24:30 -0700873
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800874 vertex_t * const v = c->vc.vBuffer;
875 vertex_t* v0 = v;
876 vertex_t* v1 = v+1;
877 vertex_t* v2;
878
879 const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
880 c->arrays.compileElement(c, v0, read_index(type, indices));
881 c->arrays.compileElement(c, v1, read_index(type, indices));
882 count -= 2;
883
884 // note: GCC 4.1.1 here makes a prety interesting optimization
885 // where it duplicates the loop below based on c->arrays.indicesType
886
887 do {
888 v2 = fetch_vertex(c, read_index(type, indices));
889 const uint32_t cc = v0->flags & v1->flags & v2->flags;
890 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
891 c->prims.renderTriangle(c, v0, v1, v2);
892 vertex_t* & consumed = ((winding^=1) ? v1 : v0);
893 consumed->locked = 0;
894 consumed = v2;
895 count--;
896 } while (count);
897 v0->locked = v1->locked = 0;
898 v2->locked = 0;
899}
900
901void drawIndexedPrimitivesTriangleStrip(ogles_context_t* c,
902 GLsizei count, const GLvoid *indices) {
903 drawIndexedPrimitivesTriangleFanOrStrip(c, count, indices, 1);
904}
905
906void drawIndexedPrimitivesTriangleFan(ogles_context_t* c,
907 GLsizei count, const GLvoid *indices) {
908 drawIndexedPrimitivesTriangleFanOrStrip(c, count, indices, 2);
909}
910
911void drawIndexedPrimitivesTriangles(ogles_context_t* c,
912 GLsizei count, const GLvoid *indices)
913{
914 if (ggl_unlikely(count < 3))
915 return;
916
917 count -= 3;
918 if (ggl_likely(c->arrays.indicesType == GL_UNSIGNED_SHORT)) {
919 // This case is probably our most common case...
920 uint16_t const * p = (uint16_t const *)indices;
921 do {
922 vertex_t* const v0 = fetch_vertex(c, *p++);
923 vertex_t* const v1 = fetch_vertex(c, *p++);
924 vertex_t* const v2 = fetch_vertex(c, *p++);
925 const uint32_t cc = v0->flags & v1->flags & v2->flags;
926 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
927 c->prims.renderTriangle(c, v0, v1, v2);
928 v0->locked = 0;
929 v1->locked = 0;
930 v2->locked = 0;
931 count -= 3;
932 } while (count >= 0);
933 } else {
934 uint8_t const * p = (uint8_t const *)indices;
935 do {
936 vertex_t* const v0 = fetch_vertex(c, *p++);
937 vertex_t* const v1 = fetch_vertex(c, *p++);
938 vertex_t* const v2 = fetch_vertex(c, *p++);
939 const uint32_t cc = v0->flags & v1->flags & v2->flags;
940 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
941 c->prims.renderTriangle(c, v0, v1, v2);
942 v0->locked = 0;
943 v1->locked = 0;
944 v2->locked = 0;
945 count -= 3;
946 } while (count >= 0);
947 }
948}
949
950// ----------------------------------------------------------------------------
951#if 0
952#pragma mark -
953#pragma mark Array compilers
954#endif
955
956void compileElement__generic(ogles_context_t* c,
957 vertex_t* v, GLint first)
958{
959 v->flags = 0;
960 v->index = first;
961 first &= vertex_cache_t::INDEX_MASK;
962 const GLubyte* vp = c->arrays.vertex.element(first);
Mathias Agopiancede1ed2009-06-02 22:05:04 -0700963 v->obj.z = 0;
964 v->obj.w = 0x10000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965 c->arrays.vertex.fetch(c, v->obj.v, vp);
966 c->arrays.mvp_transform(&c->transforms.mvp, &v->clip, &v->obj);
967 c->arrays.perspective(c, v);
968}
969
970void compileElements__generic(ogles_context_t* c,
971 vertex_t* v, GLint first, GLsizei count)
972{
973 const GLubyte* vp = c->arrays.vertex.element(
974 first & vertex_cache_t::INDEX_MASK);
975 const size_t stride = c->arrays.vertex.stride;
976 transform_t const* const mvp = &c->transforms.mvp;
977 do {
978 v->flags = 0;
979 v->index = first++;
Mathias Agopiancede1ed2009-06-02 22:05:04 -0700980 v->obj.z = 0;
981 v->obj.w = 0x10000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800982 c->arrays.vertex.fetch(c, v->obj.v, vp);
983 c->arrays.mvp_transform(mvp, &v->clip, &v->obj);
984 c->arrays.perspective(c, v);
985 vp += stride;
986 v++;
987 } while (--count);
988}
989
990/*
991void compileElements__3x_full(ogles_context_t* c,
992 vertex_t* v, GLint first, GLsizei count)
993{
994 const GLfixed* vp = (const GLfixed*)c->arrays.vertex.element(first);
995 const size_t stride = c->arrays.vertex.stride / 4;
996// const GLfixed* const& m = c->transforms.mvp.matrix.m;
Mathias Agopian1473f462009-04-10 14:24:30 -0700997
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 GLfixed m[16];
999 memcpy(&m, c->transforms.mvp.matrix.m, sizeof(m));
Mathias Agopian1473f462009-04-10 14:24:30 -07001000
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001001 do {
1002 const GLfixed rx = vp[0];
1003 const GLfixed ry = vp[1];
1004 const GLfixed rz = vp[2];
1005 vp += stride;
1006 v->index = first++;
Mathias Agopian1473f462009-04-10 14:24:30 -07001007 v->clip.x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001008 v->clip.y = mla3a(rx, m[ 1], ry, m[ 5], rz, m[ 9], m[13]);
1009 v->clip.z = mla3a(rx, m[ 2], ry, m[ 6], rz, m[10], m[14]);
1010 v->clip.w = mla3a(rx, m[ 3], ry, m[ 7], rz, m[11], m[15]);
1011
1012 const GLfixed w = v->clip.w;
1013 uint32_t clip = 0;
1014 if (v->clip.x < -w) clip |= vertex_t::CLIP_L;
1015 if (v->clip.x > w) clip |= vertex_t::CLIP_R;
1016 if (v->clip.y < -w) clip |= vertex_t::CLIP_B;
1017 if (v->clip.y > w) clip |= vertex_t::CLIP_T;
1018 if (v->clip.z < -w) clip |= vertex_t::CLIP_N;
1019 if (v->clip.z > w) clip |= vertex_t::CLIP_F;
1020 v->flags = clip;
1021 c->arrays.cull &= clip;
1022
1023 //c->arrays.perspective(c, v);
1024 v++;
1025 } while (--count);
1026}
1027*/
1028
1029// ----------------------------------------------------------------------------
1030#if 0
1031#pragma mark -
1032#pragma mark clippers
1033#endif
1034
Mathias Agopian1473f462009-04-10 14:24:30 -07001035static void clipVec4(vec4_t& nv,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001036 GLfixed t, const vec4_t& s, const vec4_t& p)
1037{
1038 for (int i=0; i<4 ; i++)
1039 nv.v[i] = gglMulAddx(t, s.v[i] - p.v[i], p.v[i], 28);
1040}
1041
1042static void clipVertex(ogles_context_t* c, vertex_t* nv,
1043 GLfixed t, const vertex_t* s, const vertex_t* p)
1044{
1045 clipVec4(nv->clip, t, s->clip, p->clip);
1046 nv->fog = gglMulAddx(t, s->fog - p->fog, p->fog, 28);
1047 ogles_vertex_project(c, nv);
1048 nv->flags |= vertex_t::LIT | vertex_t::EYE | vertex_t::TT;
1049 nv->flags &= ~vertex_t::CLIP_ALL;
1050}
1051
1052static void clipVertexC(ogles_context_t* c, vertex_t* nv,
1053 GLfixed t, const vertex_t* s, const vertex_t* p)
1054{
1055 clipVec4(nv->color, t, s->color, p->color);
1056 clipVertex(c, nv, t, s, p);
1057}
1058
1059static void clipVertexT(ogles_context_t* c, vertex_t* nv,
1060 GLfixed t, const vertex_t* s, const vertex_t* p)
1061{
1062 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
1063 if (c->rasterizer.state.texture[i].enable)
1064 clipVec4(nv->texture[i], t, s->texture[i], p->texture[i]);
1065 }
1066 clipVertex(c, nv, t, s, p);
1067}
1068
1069static void clipVertexAll(ogles_context_t* c, vertex_t* nv,
1070 GLfixed t, const vertex_t* s, const vertex_t* p)
1071{
1072 clipVec4(nv->color, t, s->color, p->color);
1073 clipVertexT(c, nv, t, s, p);
1074}
1075
1076static void clipEye(ogles_context_t* c, vertex_t* nv,
1077 GLfixed t, const vertex_t* s, const vertex_t* p)
1078{
1079 nv->clear();
1080 c->arrays.clipVertex(c, nv, t, p, s);
1081 clipVec4(nv->eye, t, s->eye, p->eye);
1082}
1083
1084// ----------------------------------------------------------------------------
1085#if 0
1086#pragma mark -
1087#endif
1088
1089void validate_arrays(ogles_context_t* c, GLenum mode)
1090{
1091 uint32_t enables = c->rasterizer.state.enables;
1092
1093 // Perspective correction is not need if Ortho transform, but
1094 // the user can still provide the w coordinate manually, so we can't
1095 // automatically turn it off (in fact we could when the 4th coordinate
1096 // is not spcified in the vertex array).
1097 // W interpolation is never needed for points.
Mathias Agopian1473f462009-04-10 14:24:30 -07001098 GLboolean perspective =
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001099 c->perspective && mode!=GL_POINTS && (enables & GGL_ENABLE_TMUS);
1100 c->rasterizer.procs.enableDisable(c, GGL_W_LERP, perspective);
Mathias Agopian1473f462009-04-10 14:24:30 -07001101
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001102 // set anti-aliasing
1103 GLboolean smooth = GL_FALSE;
1104 switch (mode) {
1105 case GL_POINTS:
1106 smooth = c->point.smooth;
1107 break;
1108 case GL_LINES:
1109 case GL_LINE_LOOP:
1110 case GL_LINE_STRIP:
1111 smooth = c->line.smooth;
1112 break;
1113 }
1114 if (((enables & GGL_ENABLE_AA)?1:0) != smooth)
1115 c->rasterizer.procs.enableDisable(c, GGL_AA, smooth);
1116
1117 // set the shade model for this primitive
1118 c->rasterizer.procs.shadeModel(c,
1119 (mode == GL_POINTS) ? GL_FLAT : c->lighting.shadeModel);
1120
1121 // compute all the matrices we'll need...
1122 uint32_t want =
1123 transform_state_t::MVP |
1124 transform_state_t::VIEWPORT;
1125 if (c->lighting.enable) { // needs normal transforms and eye coords
1126 want |= transform_state_t::MVUI;
1127 want |= transform_state_t::MODELVIEW;
1128 }
1129 if (enables & GGL_ENABLE_TMUS) { // needs texture transforms
1130 want |= transform_state_t::TEXTURE;
1131 }
Mathias Agopian1473f462009-04-10 14:24:30 -07001132 if (c->clipPlanes.enable || (enables & GGL_ENABLE_FOG)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001133 want |= transform_state_t::MODELVIEW; // needs eye coords
1134 }
1135 ogles_validate_transform(c, want);
1136
1137 // textures...
1138 if (enables & GGL_ENABLE_TMUS)
1139 ogles_validate_texture(c);
1140
1141 // vertex compilers
1142 c->arrays.compileElement = compileElement__generic;
1143 c->arrays.compileElements = compileElements__generic;
1144
1145 // vertex transform
1146 c->arrays.mvp_transform =
1147 c->transforms.mvp.pointv[c->arrays.vertex.size - 2];
1148
1149 c->arrays.mv_transform =
1150 c->transforms.modelview.transform.pointv[c->arrays.vertex.size - 2];
Mathias Agopian1473f462009-04-10 14:24:30 -07001151
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001152 /*
1153 * ***********************************************************************
1154 * pick fetchers
1155 * ***********************************************************************
1156 */
Mathias Agopian1473f462009-04-10 14:24:30 -07001157
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001158 array_machine_t& am = c->arrays;
1159 am.vertex.fetch = fetchNop;
1160 am.normal.fetch = currentNormal;
1161 am.color.fetch = currentColor;
Mathias Agopian1473f462009-04-10 14:24:30 -07001162
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001163 if (am.vertex.enable) {
1164 am.vertex.resolve();
1165 if (am.vertex.bo || am.vertex.pointer) {
1166 am.vertex.fetch = vertex_fct[am.vertex.size-2][am.vertex.type & 0xF];
1167 }
1168 }
1169
1170 if (am.normal.enable) {
1171 am.normal.resolve();
1172 if (am.normal.bo || am.normal.pointer) {
1173 am.normal.fetch = normal_fct[am.normal.size-3][am.normal.type & 0xF];
1174 }
1175 }
1176
1177 if (am.color.enable) {
1178 am.color.resolve();
1179 if (c->lighting.enable) {
1180 if (am.color.bo || am.color.pointer) {
1181 am.color.fetch = color_fct[am.color.size-3][am.color.type & 0xF];
1182 }
1183 } else {
1184 if (am.color.bo || am.color.pointer) {
1185 am.color.fetch = color_clamp_fct[am.color.size-3][am.color.type & 0xF];
1186 }
1187 }
1188 }
1189
1190 int activeTmuCount = 0;
1191 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
1192 am.texture[i].fetch = currentTexCoord;
1193 if (c->rasterizer.state.texture[i].enable) {
1194
1195 // texture fetchers...
1196 if (am.texture[i].enable) {
1197 am.texture[i].resolve();
1198 if (am.texture[i].bo || am.texture[i].pointer) {
1199 am.texture[i].fetch = texture_fct[am.texture[i].size-2][am.texture[i].type & 0xF];
1200 }
1201 }
1202
1203 // texture transform...
1204 const int index = c->arrays.texture[i].size - 2;
1205 c->arrays.tex_transform[i] =
1206 c->transforms.texture[i].transform.pointv[index];
1207
1208 am.tmu = i;
1209 activeTmuCount++;
1210 }
1211 }
1212
1213 // pick the vertex-clipper
1214 uint32_t clipper = 0;
1215 // we must reload 'enables' here
1216 enables = c->rasterizer.state.enables;
1217 if (enables & GGL_ENABLE_SMOOTH)
1218 clipper |= 1; // we need to interpolate colors
1219 if (enables & GGL_ENABLE_TMUS)
1220 clipper |= 2; // we need to interpolate textures
1221 switch (clipper) {
1222 case 0: c->arrays.clipVertex = clipVertex; break;
1223 case 1: c->arrays.clipVertex = clipVertexC; break;
1224 case 2: c->arrays.clipVertex = clipVertexT; break;
1225 case 3: c->arrays.clipVertex = clipVertexAll; break;
1226 }
1227 c->arrays.clipEye = clipEye;
1228
1229 // pick the primitive rasterizer
1230 ogles_validate_primitives(c);
1231}
1232
1233// ----------------------------------------------------------------------------
1234}; // namespace android
1235// ----------------------------------------------------------------------------
1236
1237using namespace android;
1238
1239#if 0
1240#pragma mark -
1241#pragma mark array API
1242#endif
1243
1244void glVertexPointer(
1245 GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
1246{
1247 ogles_context_t* c = ogles_context_t::get();
1248 if (size<2 || size>4 || stride<0) {
1249 ogles_error(c, GL_INVALID_VALUE);
1250 return;
1251 }
1252 switch (type) {
1253 case GL_BYTE:
1254 case GL_SHORT:
1255 case GL_FIXED:
1256 case GL_FLOAT:
1257 break;
1258 default:
1259 ogles_error(c, GL_INVALID_ENUM);
1260 return;
1261 }
1262 c->arrays.vertex.init(size, type, stride, pointer, c->arrays.array_buffer, 0);
1263}
1264
1265void glColorPointer(
1266 GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
1267{
1268 ogles_context_t* c = ogles_context_t::get();
Mathias Agopian2ddccd12009-09-24 14:22:29 -07001269 if (size!=4 || stride<0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001270 ogles_error(c, GL_INVALID_VALUE);
1271 return;
1272 }
1273 switch (type) {
1274 case GL_UNSIGNED_BYTE:
1275 case GL_FIXED:
1276 case GL_FLOAT:
1277 break;
1278 default:
1279 ogles_error(c, GL_INVALID_ENUM);
1280 return;
1281 }
1282 c->arrays.color.init(size, type, stride, pointer, c->arrays.array_buffer, 0);
1283}
1284
1285void glNormalPointer(
1286 GLenum type, GLsizei stride, const GLvoid *pointer)
1287{
1288 ogles_context_t* c = ogles_context_t::get();
1289 if (stride<0) {
1290 ogles_error(c, GL_INVALID_VALUE);
1291 return;
1292 }
1293 switch (type) {
1294 case GL_BYTE:
1295 case GL_SHORT:
1296 case GL_FIXED:
1297 case GL_FLOAT:
1298 break;
1299 default:
1300 ogles_error(c, GL_INVALID_ENUM);
1301 return;
1302 }
1303 c->arrays.normal.init(3, type, stride, pointer, c->arrays.array_buffer, 0);
1304}
1305
1306void glTexCoordPointer(
1307 GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
1308{
1309 ogles_context_t* c = ogles_context_t::get();
1310 if (size<2 || size>4 || stride<0) {
1311 ogles_error(c, GL_INVALID_VALUE);
1312 return;
1313 }
1314 switch (type) {
1315 case GL_BYTE:
1316 case GL_SHORT:
1317 case GL_FIXED:
1318 case GL_FLOAT:
1319 break;
1320 default:
1321 ogles_error(c, GL_INVALID_ENUM);
1322 return;
1323 }
1324 const int tmu = c->arrays.activeTexture;
1325 c->arrays.texture[tmu].init(size, type, stride, pointer,
1326 c->arrays.array_buffer, 0);
1327}
1328
1329
1330void glEnableClientState(GLenum array) {
1331 ogles_context_t* c = ogles_context_t::get();
1332 enableDisableClientState(c, array, true);
1333}
1334
1335void glDisableClientState(GLenum array) {
1336 ogles_context_t* c = ogles_context_t::get();
1337 enableDisableClientState(c, array, false);
1338}
1339
1340void glClientActiveTexture(GLenum texture)
1341{
1342 ogles_context_t* c = ogles_context_t::get();
1343 if (texture<GL_TEXTURE0 || texture>=GL_TEXTURE0+GGL_TEXTURE_UNIT_COUNT) {
1344 ogles_error(c, GL_INVALID_ENUM);
1345 return;
1346 }
1347 c->arrays.activeTexture = texture - GL_TEXTURE0;
1348}
1349
1350void glDrawArrays(GLenum mode, GLint first, GLsizei count)
1351{
1352 ogles_context_t* c = ogles_context_t::get();
1353 if (count<0) {
1354 ogles_error(c, GL_INVALID_VALUE);
1355 return;
1356 }
1357 switch (mode) {
1358 case GL_POINTS:
1359 case GL_LINE_STRIP:
1360 case GL_LINE_LOOP:
1361 case GL_LINES:
1362 case GL_TRIANGLE_STRIP:
1363 case GL_TRIANGLE_FAN:
1364 case GL_TRIANGLES:
1365 break;
1366 default:
1367 ogles_error(c, GL_INVALID_ENUM);
1368 return;
1369 }
1370
1371 if (count == 0 || !c->arrays.vertex.enable)
1372 return;
1373 if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK))
1374 return; // all triangles are culled
1375
Mathias Agopiandff8e582009-05-04 14:17:04 -07001376
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001377 validate_arrays(c, mode);
Mathias Agopiandff8e582009-05-04 14:17:04 -07001378
1379 const uint32_t enables = c->rasterizer.state.enables;
1380 if (enables & GGL_ENABLE_TMUS)
1381 ogles_lock_textures(c);
1382
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001383 drawArraysPrims[mode](c, first, count);
1384
Mathias Agopiandff8e582009-05-04 14:17:04 -07001385 if (enables & GGL_ENABLE_TMUS)
1386 ogles_unlock_textures(c);
1387
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001388#if VC_CACHE_STATISTICS
1389 c->vc.total = count;
1390 c->vc.dump_stats(mode);
1391#endif
1392}
1393
1394void glDrawElements(
1395 GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
1396{
1397 ogles_context_t* c = ogles_context_t::get();
1398 if (count<0) {
1399 ogles_error(c, GL_INVALID_VALUE);
1400 return;
1401 }
1402 switch (mode) {
1403 case GL_POINTS:
1404 case GL_LINE_STRIP:
1405 case GL_LINE_LOOP:
1406 case GL_LINES:
1407 case GL_TRIANGLE_STRIP:
1408 case GL_TRIANGLE_FAN:
1409 case GL_TRIANGLES:
1410 break;
1411 default:
1412 ogles_error(c, GL_INVALID_ENUM);
1413 return;
1414 }
1415 switch (type) {
1416 case GL_UNSIGNED_BYTE:
1417 case GL_UNSIGNED_SHORT:
1418 c->arrays.indicesType = type;
1419 break;
1420 default:
1421 ogles_error(c, GL_INVALID_ENUM);
1422 return;
1423 }
1424 if (count == 0 || !c->arrays.vertex.enable)
1425 return;
1426 if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK))
1427 return; // all triangles are culled
1428
1429 // clear the vertex-cache
1430 c->vc.clear();
1431 validate_arrays(c, mode);
Mathias Agopian1473f462009-04-10 14:24:30 -07001432
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001433 // if indices are in a buffer object, the pointer is treated as an
1434 // offset in that buffer.
1435 if (c->arrays.element_array_buffer) {
1436 indices = c->arrays.element_array_buffer->data + uintptr_t(indices);
1437 }
1438
Mathias Agopiandff8e582009-05-04 14:17:04 -07001439 const uint32_t enables = c->rasterizer.state.enables;
1440 if (enables & GGL_ENABLE_TMUS)
1441 ogles_lock_textures(c);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001442
Mathias Agopiandff8e582009-05-04 14:17:04 -07001443 drawElementsPrims[mode](c, count, indices);
1444
1445 if (enables & GGL_ENABLE_TMUS)
1446 ogles_unlock_textures(c);
1447
1448
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001449#if VC_CACHE_STATISTICS
1450 c->vc.total = count;
1451 c->vc.dump_stats(mode);
1452#endif
1453}
1454
1455// ----------------------------------------------------------------------------
1456// buffers
1457// ----------------------------------------------------------------------------
1458
1459void glBindBuffer(GLenum target, GLuint buffer)
1460{
1461 ogles_context_t* c = ogles_context_t::get();
1462 if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) {
1463 ogles_error(c, GL_INVALID_ENUM);
1464 return;
1465 }
1466 // create a buffer object, or bind an existing one
1467 buffer_t const* bo = 0;
1468 if (buffer) {
1469 bo = c->bufferObjectManager->bind(buffer);
1470 if (!bo) {
1471 ogles_error(c, GL_OUT_OF_MEMORY);
1472 return;
1473 }
1474 }
Mathias Agopian1473f462009-04-10 14:24:30 -07001475 ((target == GL_ARRAY_BUFFER) ?
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001476 c->arrays.array_buffer : c->arrays.element_array_buffer) = bo;
1477}
1478
1479void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
1480{
1481 ogles_context_t* c = ogles_context_t::get();
1482 if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) {
1483 ogles_error(c, GL_INVALID_ENUM);
1484 return;
1485 }
1486 if (size<0) {
1487 ogles_error(c, GL_INVALID_VALUE);
1488 return;
1489 }
1490 if ((usage!=GL_STATIC_DRAW) && (usage!=GL_DYNAMIC_DRAW)) {
1491 ogles_error(c, GL_INVALID_ENUM);
1492 return;
1493 }
Mathias Agopian1473f462009-04-10 14:24:30 -07001494 buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001495 c->arrays.array_buffer : c->arrays.element_array_buffer);
1496
1497 if (bo == 0) {
1498 // can't modify buffer 0
1499 ogles_error(c, GL_INVALID_OPERATION);
1500 return;
1501 }
1502
1503 buffer_t* edit_bo = const_cast<buffer_t*>(bo);
1504 if (c->bufferObjectManager->allocateStore(edit_bo, size, usage) != 0) {
1505 ogles_error(c, GL_OUT_OF_MEMORY);
1506 return;
1507 }
1508 if (data) {
1509 memcpy(bo->data, data, size);
1510 }
1511}
1512
1513void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
1514{
1515 ogles_context_t* c = ogles_context_t::get();
1516 if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) {
1517 ogles_error(c, GL_INVALID_ENUM);
1518 return;
1519 }
1520 if (offset<0 || size<0 || data==0) {
1521 ogles_error(c, GL_INVALID_VALUE);
1522 return;
1523 }
Mathias Agopian1473f462009-04-10 14:24:30 -07001524 buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001525 c->arrays.array_buffer : c->arrays.element_array_buffer);
1526
1527 if (bo == 0) {
1528 // can't modify buffer 0
1529 ogles_error(c, GL_INVALID_OPERATION);
1530 return;
1531 }
1532 if (offset+size > bo->size) {
1533 ogles_error(c, GL_INVALID_VALUE);
1534 return;
1535 }
1536 memcpy(bo->data + offset, data, size);
1537}
1538
1539void glDeleteBuffers(GLsizei n, const GLuint* buffers)
1540{
1541 ogles_context_t* c = ogles_context_t::get();
1542 if (n<0) {
1543 ogles_error(c, GL_INVALID_VALUE);
1544 return;
1545 }
1546
1547 for (int i=0 ; i<n ; i++) {
1548 GLuint name = buffers[i];
1549 if (name) {
1550 // unbind bound deleted buffers...
1551 if (c->arrays.element_array_buffer->name == name) {
1552 c->arrays.element_array_buffer = 0;
1553 }
1554 if (c->arrays.array_buffer->name == name) {
1555 c->arrays.array_buffer = 0;
1556 }
1557 if (c->arrays.vertex.bo->name == name) {
1558 c->arrays.vertex.bo = 0;
1559 }
1560 if (c->arrays.normal.bo->name == name) {
1561 c->arrays.normal.bo = 0;
1562 }
1563 if (c->arrays.color.bo->name == name) {
1564 c->arrays.color.bo = 0;
1565 }
1566 for (int t=0 ; t<GGL_TEXTURE_UNIT_COUNT ; t++) {
1567 if (c->arrays.texture[t].bo->name == name) {
1568 c->arrays.texture[t].bo = 0;
1569 }
1570 }
1571 }
Mathias Agopian1473f462009-04-10 14:24:30 -07001572 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001573 c->bufferObjectManager->deleteBuffers(n, buffers);
1574 c->bufferObjectManager->recycleTokens(n, buffers);
1575}
1576
1577void glGenBuffers(GLsizei n, GLuint* buffers)
1578{
1579 ogles_context_t* c = ogles_context_t::get();
1580 if (n<0) {
1581 ogles_error(c, GL_INVALID_VALUE);
1582 return;
1583 }
1584 c->bufferObjectManager->getToken(n, buffers);
1585}