blob: 6d2cc9111c84f8a1bf3af47b6fc1f7248717c288 [file] [log] [blame]
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001/*
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08002** Copyright 2006, The Android Open Source Project
3**
Mathias Agopian076b1cc2009-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 Projectedbf3b62009-03-03 19:31:44 -08007**
Mathias Agopian076b1cc2009-04-10 14:24:30 -07008** http://www.apache.org/licenses/LICENSE-2.0
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08009**
Mathias Agopian076b1cc2009-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 Projectedbf3b62009-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 Agopian076b1cc2009-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 Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700256typedef array_t::fetcher_t fn_t;
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700340inline void array_t::resolve()
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700471 v += v[0].locked | (v[1].locked<<1);
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700486 vertex_t* const v = c->vc.vCache +
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700497 vertex_t* v = c->vc.vCache +
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700538 const GLsizei vcs =
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700543 GLsizei num = count > vcs ? vcs : count;
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700575 const GLsizei vcs =
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800576 (vertex_cache_t::VERTEX_BUFFER_SIZE +
577 vertex_cache_t::VERTEX_CACHE_SIZE - 1);
578 do {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700579 v0 = c->vc.vBuffer + 0;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800580 v = c->vc.vBuffer + 1;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700581 GLsizei num = count > vcs ? vcs : count;
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700608 vertex_t* v0 = c->vc.vBuffer;
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700623 const GLsizei vcs =
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700628 GLsizei num = count > vcs ? vcs : count;
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700668 const GLsizei vcs =
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700672 v0 = c->vc.vBuffer + 0;
673 v1 = c->vc.vBuffer + 1;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800674 v = c->vc.vBuffer + 2;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700675 GLsizei num = count > vcs ? vcs : count;
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700703void drawPrimitivesTriangleStrip(ogles_context_t* c,
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700710#ifdef LIBAGL_USE_GRALLOC_COPYBITS
711 if (drawTrangleFanWithCopybit(c, first, count)) {
712 return;
713 }
714#endif // LIBAGL_USE_GRALLOC_COPYBITS
715
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700725 const GLsizei vcs =
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700730 GLsizei num = count > vcs ? vcs : count;
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700791
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800792 vertex_t * const v = c->vc.vBuffer;
793 vertex_t* v0 = v;
794 vertex_t* v1;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700795
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700818
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800819 vertex_t * const v = c->vc.vBuffer;
820 vertex_t* v0 = v;
821 vertex_t* v1;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700822
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700837 v1 = c->vc.vBuffer;
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700873
The Android Open Source Projectedbf3b62009-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);
963 c->arrays.vertex.fetch(c, v->obj.v, vp);
964 c->arrays.mvp_transform(&c->transforms.mvp, &v->clip, &v->obj);
965 c->arrays.perspective(c, v);
966}
967
968void compileElements__generic(ogles_context_t* c,
969 vertex_t* v, GLint first, GLsizei count)
970{
971 const GLubyte* vp = c->arrays.vertex.element(
972 first & vertex_cache_t::INDEX_MASK);
973 const size_t stride = c->arrays.vertex.stride;
974 transform_t const* const mvp = &c->transforms.mvp;
975 do {
976 v->flags = 0;
977 v->index = first++;
978 c->arrays.vertex.fetch(c, v->obj.v, vp);
979 c->arrays.mvp_transform(mvp, &v->clip, &v->obj);
980 c->arrays.perspective(c, v);
981 vp += stride;
982 v++;
983 } while (--count);
984}
985
986/*
987void compileElements__3x_full(ogles_context_t* c,
988 vertex_t* v, GLint first, GLsizei count)
989{
990 const GLfixed* vp = (const GLfixed*)c->arrays.vertex.element(first);
991 const size_t stride = c->arrays.vertex.stride / 4;
992// const GLfixed* const& m = c->transforms.mvp.matrix.m;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700993
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800994 GLfixed m[16];
995 memcpy(&m, c->transforms.mvp.matrix.m, sizeof(m));
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700996
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800997 do {
998 const GLfixed rx = vp[0];
999 const GLfixed ry = vp[1];
1000 const GLfixed rz = vp[2];
1001 vp += stride;
1002 v->index = first++;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001003 v->clip.x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001004 v->clip.y = mla3a(rx, m[ 1], ry, m[ 5], rz, m[ 9], m[13]);
1005 v->clip.z = mla3a(rx, m[ 2], ry, m[ 6], rz, m[10], m[14]);
1006 v->clip.w = mla3a(rx, m[ 3], ry, m[ 7], rz, m[11], m[15]);
1007
1008 const GLfixed w = v->clip.w;
1009 uint32_t clip = 0;
1010 if (v->clip.x < -w) clip |= vertex_t::CLIP_L;
1011 if (v->clip.x > w) clip |= vertex_t::CLIP_R;
1012 if (v->clip.y < -w) clip |= vertex_t::CLIP_B;
1013 if (v->clip.y > w) clip |= vertex_t::CLIP_T;
1014 if (v->clip.z < -w) clip |= vertex_t::CLIP_N;
1015 if (v->clip.z > w) clip |= vertex_t::CLIP_F;
1016 v->flags = clip;
1017 c->arrays.cull &= clip;
1018
1019 //c->arrays.perspective(c, v);
1020 v++;
1021 } while (--count);
1022}
1023*/
1024
1025// ----------------------------------------------------------------------------
1026#if 0
1027#pragma mark -
1028#pragma mark clippers
1029#endif
1030
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001031static void clipVec4(vec4_t& nv,
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001032 GLfixed t, const vec4_t& s, const vec4_t& p)
1033{
1034 for (int i=0; i<4 ; i++)
1035 nv.v[i] = gglMulAddx(t, s.v[i] - p.v[i], p.v[i], 28);
1036}
1037
1038static void clipVertex(ogles_context_t* c, vertex_t* nv,
1039 GLfixed t, const vertex_t* s, const vertex_t* p)
1040{
1041 clipVec4(nv->clip, t, s->clip, p->clip);
1042 nv->fog = gglMulAddx(t, s->fog - p->fog, p->fog, 28);
1043 ogles_vertex_project(c, nv);
1044 nv->flags |= vertex_t::LIT | vertex_t::EYE | vertex_t::TT;
1045 nv->flags &= ~vertex_t::CLIP_ALL;
1046}
1047
1048static void clipVertexC(ogles_context_t* c, vertex_t* nv,
1049 GLfixed t, const vertex_t* s, const vertex_t* p)
1050{
1051 clipVec4(nv->color, t, s->color, p->color);
1052 clipVertex(c, nv, t, s, p);
1053}
1054
1055static void clipVertexT(ogles_context_t* c, vertex_t* nv,
1056 GLfixed t, const vertex_t* s, const vertex_t* p)
1057{
1058 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
1059 if (c->rasterizer.state.texture[i].enable)
1060 clipVec4(nv->texture[i], t, s->texture[i], p->texture[i]);
1061 }
1062 clipVertex(c, nv, t, s, p);
1063}
1064
1065static void clipVertexAll(ogles_context_t* c, vertex_t* nv,
1066 GLfixed t, const vertex_t* s, const vertex_t* p)
1067{
1068 clipVec4(nv->color, t, s->color, p->color);
1069 clipVertexT(c, nv, t, s, p);
1070}
1071
1072static void clipEye(ogles_context_t* c, vertex_t* nv,
1073 GLfixed t, const vertex_t* s, const vertex_t* p)
1074{
1075 nv->clear();
1076 c->arrays.clipVertex(c, nv, t, p, s);
1077 clipVec4(nv->eye, t, s->eye, p->eye);
1078}
1079
1080// ----------------------------------------------------------------------------
1081#if 0
1082#pragma mark -
1083#endif
1084
1085void validate_arrays(ogles_context_t* c, GLenum mode)
1086{
1087 uint32_t enables = c->rasterizer.state.enables;
1088
1089 // Perspective correction is not need if Ortho transform, but
1090 // the user can still provide the w coordinate manually, so we can't
1091 // automatically turn it off (in fact we could when the 4th coordinate
1092 // is not spcified in the vertex array).
1093 // W interpolation is never needed for points.
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001094 GLboolean perspective =
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001095 c->perspective && mode!=GL_POINTS && (enables & GGL_ENABLE_TMUS);
1096 c->rasterizer.procs.enableDisable(c, GGL_W_LERP, perspective);
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001097
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001098 // set anti-aliasing
1099 GLboolean smooth = GL_FALSE;
1100 switch (mode) {
1101 case GL_POINTS:
1102 smooth = c->point.smooth;
1103 break;
1104 case GL_LINES:
1105 case GL_LINE_LOOP:
1106 case GL_LINE_STRIP:
1107 smooth = c->line.smooth;
1108 break;
1109 }
1110 if (((enables & GGL_ENABLE_AA)?1:0) != smooth)
1111 c->rasterizer.procs.enableDisable(c, GGL_AA, smooth);
1112
1113 // set the shade model for this primitive
1114 c->rasterizer.procs.shadeModel(c,
1115 (mode == GL_POINTS) ? GL_FLAT : c->lighting.shadeModel);
1116
1117 // compute all the matrices we'll need...
1118 uint32_t want =
1119 transform_state_t::MVP |
1120 transform_state_t::VIEWPORT;
1121 if (c->lighting.enable) { // needs normal transforms and eye coords
1122 want |= transform_state_t::MVUI;
1123 want |= transform_state_t::MODELVIEW;
1124 }
1125 if (enables & GGL_ENABLE_TMUS) { // needs texture transforms
1126 want |= transform_state_t::TEXTURE;
1127 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001128 if (c->clipPlanes.enable || (enables & GGL_ENABLE_FOG)) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001129 want |= transform_state_t::MODELVIEW; // needs eye coords
1130 }
1131 ogles_validate_transform(c, want);
1132
1133 // textures...
1134 if (enables & GGL_ENABLE_TMUS)
1135 ogles_validate_texture(c);
1136
1137 // vertex compilers
1138 c->arrays.compileElement = compileElement__generic;
1139 c->arrays.compileElements = compileElements__generic;
1140
1141 // vertex transform
1142 c->arrays.mvp_transform =
1143 c->transforms.mvp.pointv[c->arrays.vertex.size - 2];
1144
1145 c->arrays.mv_transform =
1146 c->transforms.modelview.transform.pointv[c->arrays.vertex.size - 2];
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001147
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001148 /*
1149 * ***********************************************************************
1150 * pick fetchers
1151 * ***********************************************************************
1152 */
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001153
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001154 array_machine_t& am = c->arrays;
1155 am.vertex.fetch = fetchNop;
1156 am.normal.fetch = currentNormal;
1157 am.color.fetch = currentColor;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001158
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001159 if (am.vertex.enable) {
1160 am.vertex.resolve();
1161 if (am.vertex.bo || am.vertex.pointer) {
1162 am.vertex.fetch = vertex_fct[am.vertex.size-2][am.vertex.type & 0xF];
1163 }
1164 }
1165
1166 if (am.normal.enable) {
1167 am.normal.resolve();
1168 if (am.normal.bo || am.normal.pointer) {
1169 am.normal.fetch = normal_fct[am.normal.size-3][am.normal.type & 0xF];
1170 }
1171 }
1172
1173 if (am.color.enable) {
1174 am.color.resolve();
1175 if (c->lighting.enable) {
1176 if (am.color.bo || am.color.pointer) {
1177 am.color.fetch = color_fct[am.color.size-3][am.color.type & 0xF];
1178 }
1179 } else {
1180 if (am.color.bo || am.color.pointer) {
1181 am.color.fetch = color_clamp_fct[am.color.size-3][am.color.type & 0xF];
1182 }
1183 }
1184 }
1185
1186 int activeTmuCount = 0;
1187 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
1188 am.texture[i].fetch = currentTexCoord;
1189 if (c->rasterizer.state.texture[i].enable) {
1190
1191 // texture fetchers...
1192 if (am.texture[i].enable) {
1193 am.texture[i].resolve();
1194 if (am.texture[i].bo || am.texture[i].pointer) {
1195 am.texture[i].fetch = texture_fct[am.texture[i].size-2][am.texture[i].type & 0xF];
1196 }
1197 }
1198
1199 // texture transform...
1200 const int index = c->arrays.texture[i].size - 2;
1201 c->arrays.tex_transform[i] =
1202 c->transforms.texture[i].transform.pointv[index];
1203
1204 am.tmu = i;
1205 activeTmuCount++;
1206 }
1207 }
1208
1209 // pick the vertex-clipper
1210 uint32_t clipper = 0;
1211 // we must reload 'enables' here
1212 enables = c->rasterizer.state.enables;
1213 if (enables & GGL_ENABLE_SMOOTH)
1214 clipper |= 1; // we need to interpolate colors
1215 if (enables & GGL_ENABLE_TMUS)
1216 clipper |= 2; // we need to interpolate textures
1217 switch (clipper) {
1218 case 0: c->arrays.clipVertex = clipVertex; break;
1219 case 1: c->arrays.clipVertex = clipVertexC; break;
1220 case 2: c->arrays.clipVertex = clipVertexT; break;
1221 case 3: c->arrays.clipVertex = clipVertexAll; break;
1222 }
1223 c->arrays.clipEye = clipEye;
1224
1225 // pick the primitive rasterizer
1226 ogles_validate_primitives(c);
1227}
1228
1229// ----------------------------------------------------------------------------
1230}; // namespace android
1231// ----------------------------------------------------------------------------
1232
1233using namespace android;
1234
1235#if 0
1236#pragma mark -
1237#pragma mark array API
1238#endif
1239
1240void glVertexPointer(
1241 GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
1242{
1243 ogles_context_t* c = ogles_context_t::get();
1244 if (size<2 || size>4 || stride<0) {
1245 ogles_error(c, GL_INVALID_VALUE);
1246 return;
1247 }
1248 switch (type) {
1249 case GL_BYTE:
1250 case GL_SHORT:
1251 case GL_FIXED:
1252 case GL_FLOAT:
1253 break;
1254 default:
1255 ogles_error(c, GL_INVALID_ENUM);
1256 return;
1257 }
1258 c->arrays.vertex.init(size, type, stride, pointer, c->arrays.array_buffer, 0);
1259}
1260
1261void glColorPointer(
1262 GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
1263{
1264 ogles_context_t* c = ogles_context_t::get();
1265 // in theory ogles doesn't allow color arrays of size 3
1266 // but it is very useful to 'visualize' the normal array.
1267 if (size<3 || size>4 || stride<0) {
1268 ogles_error(c, GL_INVALID_VALUE);
1269 return;
1270 }
1271 switch (type) {
1272 case GL_UNSIGNED_BYTE:
1273 case GL_FIXED:
1274 case GL_FLOAT:
1275 break;
1276 default:
1277 ogles_error(c, GL_INVALID_ENUM);
1278 return;
1279 }
1280 c->arrays.color.init(size, type, stride, pointer, c->arrays.array_buffer, 0);
1281}
1282
1283void glNormalPointer(
1284 GLenum type, GLsizei stride, const GLvoid *pointer)
1285{
1286 ogles_context_t* c = ogles_context_t::get();
1287 if (stride<0) {
1288 ogles_error(c, GL_INVALID_VALUE);
1289 return;
1290 }
1291 switch (type) {
1292 case GL_BYTE:
1293 case GL_SHORT:
1294 case GL_FIXED:
1295 case GL_FLOAT:
1296 break;
1297 default:
1298 ogles_error(c, GL_INVALID_ENUM);
1299 return;
1300 }
1301 c->arrays.normal.init(3, type, stride, pointer, c->arrays.array_buffer, 0);
1302}
1303
1304void glTexCoordPointer(
1305 GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
1306{
1307 ogles_context_t* c = ogles_context_t::get();
1308 if (size<2 || size>4 || stride<0) {
1309 ogles_error(c, GL_INVALID_VALUE);
1310 return;
1311 }
1312 switch (type) {
1313 case GL_BYTE:
1314 case GL_SHORT:
1315 case GL_FIXED:
1316 case GL_FLOAT:
1317 break;
1318 default:
1319 ogles_error(c, GL_INVALID_ENUM);
1320 return;
1321 }
1322 const int tmu = c->arrays.activeTexture;
1323 c->arrays.texture[tmu].init(size, type, stride, pointer,
1324 c->arrays.array_buffer, 0);
1325}
1326
1327
1328void glEnableClientState(GLenum array) {
1329 ogles_context_t* c = ogles_context_t::get();
1330 enableDisableClientState(c, array, true);
1331}
1332
1333void glDisableClientState(GLenum array) {
1334 ogles_context_t* c = ogles_context_t::get();
1335 enableDisableClientState(c, array, false);
1336}
1337
1338void glClientActiveTexture(GLenum texture)
1339{
1340 ogles_context_t* c = ogles_context_t::get();
1341 if (texture<GL_TEXTURE0 || texture>=GL_TEXTURE0+GGL_TEXTURE_UNIT_COUNT) {
1342 ogles_error(c, GL_INVALID_ENUM);
1343 return;
1344 }
1345 c->arrays.activeTexture = texture - GL_TEXTURE0;
1346}
1347
1348void glDrawArrays(GLenum mode, GLint first, GLsizei count)
1349{
1350 ogles_context_t* c = ogles_context_t::get();
1351 if (count<0) {
1352 ogles_error(c, GL_INVALID_VALUE);
1353 return;
1354 }
1355 switch (mode) {
1356 case GL_POINTS:
1357 case GL_LINE_STRIP:
1358 case GL_LINE_LOOP:
1359 case GL_LINES:
1360 case GL_TRIANGLE_STRIP:
1361 case GL_TRIANGLE_FAN:
1362 case GL_TRIANGLES:
1363 break;
1364 default:
1365 ogles_error(c, GL_INVALID_ENUM);
1366 return;
1367 }
1368
1369 if (count == 0 || !c->arrays.vertex.enable)
1370 return;
1371 if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK))
1372 return; // all triangles are culled
1373
Mathias Agopian0926f502009-05-04 14:17:04 -07001374
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001375 validate_arrays(c, mode);
Mathias Agopian0926f502009-05-04 14:17:04 -07001376
1377 const uint32_t enables = c->rasterizer.state.enables;
1378 if (enables & GGL_ENABLE_TMUS)
1379 ogles_lock_textures(c);
1380
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001381 drawArraysPrims[mode](c, first, count);
1382
Mathias Agopian0926f502009-05-04 14:17:04 -07001383 if (enables & GGL_ENABLE_TMUS)
1384 ogles_unlock_textures(c);
1385
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001386#if VC_CACHE_STATISTICS
1387 c->vc.total = count;
1388 c->vc.dump_stats(mode);
1389#endif
1390}
1391
1392void glDrawElements(
1393 GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
1394{
1395 ogles_context_t* c = ogles_context_t::get();
1396 if (count<0) {
1397 ogles_error(c, GL_INVALID_VALUE);
1398 return;
1399 }
1400 switch (mode) {
1401 case GL_POINTS:
1402 case GL_LINE_STRIP:
1403 case GL_LINE_LOOP:
1404 case GL_LINES:
1405 case GL_TRIANGLE_STRIP:
1406 case GL_TRIANGLE_FAN:
1407 case GL_TRIANGLES:
1408 break;
1409 default:
1410 ogles_error(c, GL_INVALID_ENUM);
1411 return;
1412 }
1413 switch (type) {
1414 case GL_UNSIGNED_BYTE:
1415 case GL_UNSIGNED_SHORT:
1416 c->arrays.indicesType = type;
1417 break;
1418 default:
1419 ogles_error(c, GL_INVALID_ENUM);
1420 return;
1421 }
1422 if (count == 0 || !c->arrays.vertex.enable)
1423 return;
1424 if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK))
1425 return; // all triangles are culled
1426
1427 // clear the vertex-cache
1428 c->vc.clear();
1429 validate_arrays(c, mode);
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001430
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001431 // if indices are in a buffer object, the pointer is treated as an
1432 // offset in that buffer.
1433 if (c->arrays.element_array_buffer) {
1434 indices = c->arrays.element_array_buffer->data + uintptr_t(indices);
1435 }
1436
Mathias Agopian0926f502009-05-04 14:17:04 -07001437 const uint32_t enables = c->rasterizer.state.enables;
1438 if (enables & GGL_ENABLE_TMUS)
1439 ogles_lock_textures(c);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001440
Mathias Agopian0926f502009-05-04 14:17:04 -07001441 drawElementsPrims[mode](c, count, indices);
1442
1443 if (enables & GGL_ENABLE_TMUS)
1444 ogles_unlock_textures(c);
1445
1446
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001447#if VC_CACHE_STATISTICS
1448 c->vc.total = count;
1449 c->vc.dump_stats(mode);
1450#endif
1451}
1452
1453// ----------------------------------------------------------------------------
1454// buffers
1455// ----------------------------------------------------------------------------
1456
1457void glBindBuffer(GLenum target, GLuint buffer)
1458{
1459 ogles_context_t* c = ogles_context_t::get();
1460 if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) {
1461 ogles_error(c, GL_INVALID_ENUM);
1462 return;
1463 }
1464 // create a buffer object, or bind an existing one
1465 buffer_t const* bo = 0;
1466 if (buffer) {
1467 bo = c->bufferObjectManager->bind(buffer);
1468 if (!bo) {
1469 ogles_error(c, GL_OUT_OF_MEMORY);
1470 return;
1471 }
1472 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001473 ((target == GL_ARRAY_BUFFER) ?
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001474 c->arrays.array_buffer : c->arrays.element_array_buffer) = bo;
1475}
1476
1477void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
1478{
1479 ogles_context_t* c = ogles_context_t::get();
1480 if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) {
1481 ogles_error(c, GL_INVALID_ENUM);
1482 return;
1483 }
1484 if (size<0) {
1485 ogles_error(c, GL_INVALID_VALUE);
1486 return;
1487 }
1488 if ((usage!=GL_STATIC_DRAW) && (usage!=GL_DYNAMIC_DRAW)) {
1489 ogles_error(c, GL_INVALID_ENUM);
1490 return;
1491 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001492 buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001493 c->arrays.array_buffer : c->arrays.element_array_buffer);
1494
1495 if (bo == 0) {
1496 // can't modify buffer 0
1497 ogles_error(c, GL_INVALID_OPERATION);
1498 return;
1499 }
1500
1501 buffer_t* edit_bo = const_cast<buffer_t*>(bo);
1502 if (c->bufferObjectManager->allocateStore(edit_bo, size, usage) != 0) {
1503 ogles_error(c, GL_OUT_OF_MEMORY);
1504 return;
1505 }
1506 if (data) {
1507 memcpy(bo->data, data, size);
1508 }
1509}
1510
1511void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
1512{
1513 ogles_context_t* c = ogles_context_t::get();
1514 if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) {
1515 ogles_error(c, GL_INVALID_ENUM);
1516 return;
1517 }
1518 if (offset<0 || size<0 || data==0) {
1519 ogles_error(c, GL_INVALID_VALUE);
1520 return;
1521 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001522 buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001523 c->arrays.array_buffer : c->arrays.element_array_buffer);
1524
1525 if (bo == 0) {
1526 // can't modify buffer 0
1527 ogles_error(c, GL_INVALID_OPERATION);
1528 return;
1529 }
1530 if (offset+size > bo->size) {
1531 ogles_error(c, GL_INVALID_VALUE);
1532 return;
1533 }
1534 memcpy(bo->data + offset, data, size);
1535}
1536
1537void glDeleteBuffers(GLsizei n, const GLuint* buffers)
1538{
1539 ogles_context_t* c = ogles_context_t::get();
1540 if (n<0) {
1541 ogles_error(c, GL_INVALID_VALUE);
1542 return;
1543 }
1544
1545 for (int i=0 ; i<n ; i++) {
1546 GLuint name = buffers[i];
1547 if (name) {
1548 // unbind bound deleted buffers...
1549 if (c->arrays.element_array_buffer->name == name) {
1550 c->arrays.element_array_buffer = 0;
1551 }
1552 if (c->arrays.array_buffer->name == name) {
1553 c->arrays.array_buffer = 0;
1554 }
1555 if (c->arrays.vertex.bo->name == name) {
1556 c->arrays.vertex.bo = 0;
1557 }
1558 if (c->arrays.normal.bo->name == name) {
1559 c->arrays.normal.bo = 0;
1560 }
1561 if (c->arrays.color.bo->name == name) {
1562 c->arrays.color.bo = 0;
1563 }
1564 for (int t=0 ; t<GGL_TEXTURE_UNIT_COUNT ; t++) {
1565 if (c->arrays.texture[t].bo->name == name) {
1566 c->arrays.texture[t].bo = 0;
1567 }
1568 }
1569 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001570 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001571 c->bufferObjectManager->deleteBuffers(n, buffers);
1572 c->bufferObjectManager->recycleTokens(n, buffers);
1573}
1574
1575void glGenBuffers(GLsizei n, GLuint* buffers)
1576{
1577 ogles_context_t* c = ogles_context_t::get();
1578 if (n<0) {
1579 ogles_error(c, GL_INVALID_VALUE);
1580 return;
1581 }
1582 c->bufferObjectManager->getToken(n, buffers);
1583}