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