blob: 2d36c6194eea771acbc58c00ba731f35d7ab0260 [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}
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800139static void currentNormal(ogles_context_t* c, GLfixed* v, const GLvoid*) {
140 memcpy(v, c->currentNormal.v, sizeof(vec3_t));
141}
142static void currentTexCoord(ogles_context_t* c, GLfixed* v, const GLvoid*) {
143 memcpy(v, c->current.texture[c->arrays.tmu].v, sizeof(vec4_t));
144}
145
146
147static void fetchNop(ogles_context_t*, GLfixed*, const GLvoid*) {
148}
149static void fetch2b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
150 v[0] = gglIntToFixed(p[0]);
151 v[1] = gglIntToFixed(p[1]);
152}
153static void fetch2s(ogles_context_t*, GLfixed* v, const GLshort* p) {
154 v[0] = gglIntToFixed(p[0]);
155 v[1] = gglIntToFixed(p[1]);
156}
157static void fetch2x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
158 memcpy(v, p, 2*sizeof(GLfixed));
159}
160static void fetch2f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
161 v[0] = gglFloatToFixed(p[0]);
162 v[1] = gglFloatToFixed(p[1]);
163}
164static void fetch3b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
165 v[0] = gglIntToFixed(p[0]);
166 v[1] = gglIntToFixed(p[1]);
167 v[2] = gglIntToFixed(p[2]);
168}
169static void fetch3s(ogles_context_t*, GLfixed* v, const GLshort* p) {
170 v[0] = gglIntToFixed(p[0]);
171 v[1] = gglIntToFixed(p[1]);
172 v[2] = gglIntToFixed(p[2]);
173}
174static void fetch3x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
175 memcpy(v, p, 3*sizeof(GLfixed));
176}
177static void fetch3f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
178 v[0] = gglFloatToFixed(p[0]);
179 v[1] = gglFloatToFixed(p[1]);
180 v[2] = gglFloatToFixed(p[2]);
181}
182static void fetch4b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
183 v[0] = gglIntToFixed(p[0]);
184 v[1] = gglIntToFixed(p[1]);
185 v[2] = gglIntToFixed(p[2]);
186 v[3] = gglIntToFixed(p[3]);
187}
188static void fetch4s(ogles_context_t*, GLfixed* v, const GLshort* 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 fetch4x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
195 memcpy(v, p, 4*sizeof(GLfixed));
196}
197static void fetch4f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
198 v[0] = gglFloatToFixed(p[0]);
199 v[1] = gglFloatToFixed(p[1]);
200 v[2] = gglFloatToFixed(p[2]);
201 v[3] = gglFloatToFixed(p[3]);
202}
203static void fetchExpand4ub(ogles_context_t*, GLfixed* v, const GLubyte* p) {
204 v[0] = GGL_UB_TO_X(p[0]);
205 v[1] = GGL_UB_TO_X(p[1]);
206 v[2] = GGL_UB_TO_X(p[2]);
207 v[3] = GGL_UB_TO_X(p[3]);
208}
209static void fetchClamp4x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
210 v[0] = gglClampx(p[0]);
211 v[1] = gglClampx(p[1]);
212 v[2] = gglClampx(p[2]);
213 v[3] = gglClampx(p[3]);
214}
215static void fetchClamp4f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
216 v[0] = gglClampx(gglFloatToFixed(p[0]));
217 v[1] = gglClampx(gglFloatToFixed(p[1]));
218 v[2] = gglClampx(gglFloatToFixed(p[2]));
219 v[3] = gglClampx(gglFloatToFixed(p[3]));
220}
221static void fetchExpand3ub(ogles_context_t*, GLfixed* v, const GLubyte* p) {
222 v[0] = GGL_UB_TO_X(p[0]);
223 v[1] = GGL_UB_TO_X(p[1]);
224 v[2] = GGL_UB_TO_X(p[2]);
225 v[3] = 0x10000;
226}
227static void fetchClamp3x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
228 v[0] = gglClampx(p[0]);
229 v[1] = gglClampx(p[1]);
230 v[2] = gglClampx(p[2]);
231 v[3] = 0x10000;
232}
233static void fetchClamp3f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
234 v[0] = gglClampx(gglFloatToFixed(p[0]));
235 v[1] = gglClampx(gglFloatToFixed(p[1]));
236 v[2] = gglClampx(gglFloatToFixed(p[2]));
237 v[3] = 0x10000;
238}
239static void fetchExpand3b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
240 v[0] = GGL_B_TO_X(p[0]);
241 v[1] = GGL_B_TO_X(p[1]);
242 v[2] = GGL_B_TO_X(p[2]);
243}
244static void fetchExpand3s(ogles_context_t*, GLfixed* v, const GLshort* p) {
245 v[0] = GGL_S_TO_X(p[0]);
246 v[1] = GGL_S_TO_X(p[1]);
247 v[2] = GGL_S_TO_X(p[2]);
248}
249
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700250typedef array_t::fetcher_t fn_t;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800251
252static const fn_t color_fct[2][16] = { // size={3,4}, type={ub,f,x}
253 { 0, (fn_t)fetchExpand3ub, 0, 0, 0, 0,
254 (fn_t)fetch3f, 0, 0, 0, 0, 0,
255 (fn_t)fetch3x },
256 { 0, (fn_t)fetchExpand4ub, 0, 0, 0, 0,
257 (fn_t)fetch4f, 0, 0, 0, 0, 0,
258 (fn_t)fetch4x },
259};
260static const fn_t color_clamp_fct[2][16] = { // size={3,4}, type={ub,f,x}
261 { 0, (fn_t)fetchExpand3ub, 0, 0, 0, 0,
262 (fn_t)fetchClamp3f, 0, 0, 0, 0, 0,
263 (fn_t)fetchClamp3x },
264 { 0, (fn_t)fetchExpand4ub, 0, 0, 0, 0,
265 (fn_t)fetchClamp4f, 0, 0, 0, 0, 0,
266 (fn_t)fetchClamp4x },
267};
268static const fn_t normal_fct[1][16] = { // size={3}, type={b,s,f,x}
269 { (fn_t)fetchExpand3b, 0,
270 (fn_t)fetchExpand3s, 0, 0, 0,
271 (fn_t)fetch3f, 0, 0, 0, 0, 0,
272 (fn_t)fetch3x },
273};
274static const fn_t vertex_fct[3][16] = { // size={2,3,4}, type={b,s,f,x}
275 { (fn_t)fetch2b, 0,
276 (fn_t)fetch2s, 0, 0, 0,
277 (fn_t)fetch2f, 0, 0, 0, 0, 0,
278 (fn_t)fetch3x },
279 { (fn_t)fetch3b, 0,
280 (fn_t)fetch3s, 0, 0, 0,
281 (fn_t)fetch3f, 0, 0, 0, 0, 0,
282 (fn_t)fetch3x },
283 { (fn_t)fetch4b, 0,
284 (fn_t)fetch4s, 0, 0, 0,
285 (fn_t)fetch4f, 0, 0, 0, 0, 0,
286 (fn_t)fetch4x }
287};
288static const fn_t texture_fct[3][16] = { // size={2,3,4}, type={b,s,f,x}
289 { (fn_t)fetch2b, 0,
290 (fn_t)fetch2s, 0, 0, 0,
291 (fn_t)fetch2f, 0, 0, 0, 0, 0,
292 (fn_t)fetch2x },
293 { (fn_t)fetch3b, 0,
294 (fn_t)fetch3s, 0, 0, 0,
295 (fn_t)fetch3f, 0, 0, 0, 0, 0,
296 (fn_t)fetch3x },
297 { (fn_t)fetch4b, 0,
298 (fn_t)fetch4s, 0, 0, 0,
299 (fn_t)fetch4f, 0, 0, 0, 0, 0,
300 (fn_t)fetch4x }
301};
302
303// ----------------------------------------------------------------------------
304#if 0
305#pragma mark -
306#pragma mark array_t
307#endif
308
309void array_t::init(
310 GLint size, GLenum type, GLsizei stride,
311 const GLvoid *pointer, const buffer_t* bo, GLsizei count)
312{
313 if (!stride) {
314 stride = size;
315 switch (type) {
316 case GL_SHORT:
317 case GL_UNSIGNED_SHORT:
318 stride *= 2;
319 break;
320 case GL_FLOAT:
321 case GL_FIXED:
322 stride *= 4;
323 break;
324 }
325 }
326 this->size = size;
327 this->type = type;
328 this->stride = stride;
329 this->pointer = pointer;
330 this->bo = bo;
331 this->bounds = count;
332}
333
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700334inline void array_t::resolve()
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800335{
336 physical_pointer = (bo) ? (bo->data + uintptr_t(pointer)) : pointer;
337}
338
339// ----------------------------------------------------------------------------
340#if 0
341#pragma mark -
342#pragma mark vertex_cache_t
343#endif
344
345void vertex_cache_t::init()
346{
347 // make sure the size of vertex_t allows cache-line alignment
348 CTA<(sizeof(vertex_t) & 0x1F) == 0> assertAlignedSize;
Chih-Hung Hsieh1e02a622017-10-26 15:18:12 -0700349 (void)assertAlignedSize; // suppress unused warning.
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800350
351 const int align = 32;
352 const size_t s = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE;
353 const size_t size = s*sizeof(vertex_t) + align;
354 base = malloc(size);
355 if (base) {
356 memset(base, 0, size);
357 vBuffer = (vertex_t*)((size_t(base) + align - 1) & ~(align-1));
358 vCache = vBuffer + VERTEX_BUFFER_SIZE;
359 sequence = 0;
360 }
361}
362
363void vertex_cache_t::uninit()
364{
365 free(base);
366 base = vBuffer = vCache = 0;
367}
368
369void vertex_cache_t::clear()
370{
371#if VC_CACHE_STATISTICS
372 startTime = systemTime(SYSTEM_TIME_THREAD);
373 total = 0;
374 misses = 0;
375#endif
376
377#if VC_CACHE_TYPE == VC_CACHE_TYPE_LRU
378 vertex_t* v = vBuffer;
379 size_t count = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE;
380 do {
381 v->mru = 0;
382 v++;
383 } while (--count);
384#endif
385
386 sequence += INDEX_SEQ;
387 if (sequence >= 0x80000000LU) {
388 sequence = INDEX_SEQ;
389 vertex_t* v = vBuffer;
390 size_t count = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE;
391 do {
392 v->index = 0;
393 v++;
394 } while (--count);
395 }
396}
397
Mark Salyzyn92dc3fc2014-03-12 13:12:44 -0700398#if VC_CACHE_STATISTICS
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800399void vertex_cache_t::dump_stats(GLenum mode)
400{
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800401 nsecs_t time = systemTime(SYSTEM_TIME_THREAD) - startTime;
402 uint32_t hits = total - misses;
403 uint32_t prim_count;
404 switch (mode) {
405 case GL_POINTS: prim_count = total; break;
406 case GL_LINE_STRIP: prim_count = total - 1; break;
407 case GL_LINE_LOOP: prim_count = total - 1; break;
408 case GL_LINES: prim_count = total / 2; break;
409 case GL_TRIANGLE_STRIP: prim_count = total - 2; break;
410 case GL_TRIANGLE_FAN: prim_count = total - 2; break;
411 case GL_TRIANGLES: prim_count = total / 3; break;
412 default: return;
413 }
414 printf( "total=%5u, hits=%5u, miss=%5u, hitrate=%3u%%,"
415 " prims=%5u, time=%6u us, prims/s=%d, v/t=%f\n",
416 total, hits, misses, (hits*100)/total,
417 prim_count, int(ns2us(time)), int(prim_count*float(seconds(1))/time),
418 float(misses) / prim_count);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800419}
Mark Salyzyn92dc3fc2014-03-12 13:12:44 -0700420#else
421void vertex_cache_t::dump_stats(GLenum /*mode*/)
422{
423}
424#endif
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800425
426// ----------------------------------------------------------------------------
427#if 0
428#pragma mark -
429#endif
430
431static __attribute__((noinline))
432void enableDisableClientState(ogles_context_t* c, GLenum array, bool enable)
433{
434 const int tmu = c->arrays.activeTexture;
435 array_t* a;
436 switch (array) {
437 case GL_COLOR_ARRAY: a = &c->arrays.color; break;
438 case GL_NORMAL_ARRAY: a = &c->arrays.normal; break;
439 case GL_TEXTURE_COORD_ARRAY: a = &c->arrays.texture[tmu]; break;
440 case GL_VERTEX_ARRAY: a = &c->arrays.vertex; break;
441 default:
442 ogles_error(c, GL_INVALID_ENUM);
443 return;
444 }
445 a->enable = enable ? GL_TRUE : GL_FALSE;
446}
447
448// ----------------------------------------------------------------------------
449#if 0
450#pragma mark -
451#pragma mark Vertex Cache
452#endif
453
454static __attribute__((noinline))
455vertex_t* cache_vertex(ogles_context_t* c, vertex_t* v, uint32_t index)
456{
457 #if VC_CACHE_STATISTICS
458 c->vc.misses++;
459 #endif
460 if (ggl_unlikely(v->locked)) {
461 // we're just looking for an entry in the cache that is not locked.
462 // and we know that there cannot be more than 2 locked entries
463 // because a triangle needs at most 3 vertices.
464 // We never use the first and second entries because they might be in
465 // use by the striper or faner. Any other entry will do as long as
466 // it's not locked.
467 // We compute directly the index of a "free" entry from the locked
468 // state of v[2] and v[3].
469 v = c->vc.vBuffer + 2;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700470 v += v[0].locked | (v[1].locked<<1);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800471 }
472 // note: compileElement clears v->flags
473 c->arrays.compileElement(c, v, index);
474 v->locked = 1;
475 return v;
476}
477
478static __attribute__((noinline))
479vertex_t* fetch_vertex(ogles_context_t* c, size_t index)
480{
481 index |= c->vc.sequence;
482
483#if VC_CACHE_TYPE == VC_CACHE_TYPE_INDEXED
484
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700485 vertex_t* const v = c->vc.vCache +
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800486 (index & (vertex_cache_t::VERTEX_CACHE_SIZE-1));
487
488 if (ggl_likely(v->index == index)) {
489 v->locked = 1;
490 return v;
491 }
492 return cache_vertex(c, v, index);
493
494#elif VC_CACHE_TYPE == VC_CACHE_TYPE_LRU
495
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700496 vertex_t* v = c->vc.vCache +
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800497 (index & ((vertex_cache_t::VERTEX_CACHE_SIZE-1)>>1))*2;
498
499 // always record LRU in v[0]
500 if (ggl_likely(v[0].index == index)) {
501 v[0].locked = 1;
502 v[0].mru = 0;
503 return &v[0];
504 }
505
506 if (ggl_likely(v[1].index == index)) {
507 v[1].locked = 1;
508 v[0].mru = 1;
509 return &v[1];
510 }
511
512 const int lru = 1 - v[0].mru;
513 v[0].mru = lru;
514 return cache_vertex(c, &v[lru], index);
515
516#elif VC_CACHE_TYPE == VC_CACHE_TYPE_NONE
517
518 // just for debugging...
519 vertex_t* v = c->vc.vBuffer + 2;
520 return cache_vertex(c, v, index);
521
522#endif
523}
524
525// ----------------------------------------------------------------------------
526#if 0
527#pragma mark -
528#pragma mark Primitive Assembly
529#endif
530
531void drawPrimitivesPoints(ogles_context_t* c, GLint first, GLsizei count)
532{
533 if (ggl_unlikely(count < 1))
534 return;
535
536 // vertex cache size must be multiple of 1
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700537 const GLsizei vcs =
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800538 (vertex_cache_t::VERTEX_BUFFER_SIZE +
539 vertex_cache_t::VERTEX_CACHE_SIZE);
540 do {
541 vertex_t* v = c->vc.vBuffer;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700542 GLsizei num = count > vcs ? vcs : count;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800543 c->arrays.cull = vertex_t::CLIP_ALL;
544 c->arrays.compileElements(c, v, first, num);
545 first += num;
546 count -= num;
547 if (!c->arrays.cull) {
548 // quick/trivial reject of the whole batch
549 do {
550 const uint32_t cc = v[0].flags;
551 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
552 c->prims.renderPoint(c, v);
553 v++;
554 num--;
555 } while (num);
556 }
557 } while (count);
558}
559
560// ----------------------------------------------------------------------------
561
562void drawPrimitivesLineStrip(ogles_context_t* c, GLint first, GLsizei count)
563{
564 if (ggl_unlikely(count < 2))
565 return;
566
567 vertex_t *v, *v0, *v1;
568 c->arrays.cull = vertex_t::CLIP_ALL;
569 c->arrays.compileElement(c, c->vc.vBuffer, first);
570 first += 1;
571 count -= 1;
572
573 // vertex cache size must be multiple of 1
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700574 const GLsizei vcs =
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800575 (vertex_cache_t::VERTEX_BUFFER_SIZE +
576 vertex_cache_t::VERTEX_CACHE_SIZE - 1);
577 do {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700578 v0 = c->vc.vBuffer + 0;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800579 v = c->vc.vBuffer + 1;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700580 GLsizei num = count > vcs ? vcs : count;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800581 c->arrays.compileElements(c, v, first, num);
582 first += num;
583 count -= num;
584 if (!c->arrays.cull) {
585 // quick/trivial reject of the whole batch
586 do {
587 v1 = v++;
588 const uint32_t cc = v0->flags & v1->flags;
589 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
590 c->prims.renderLine(c, v0, v1);
591 v0 = v1;
592 num--;
593 } while (num);
594 }
595 // copy back the last processed vertex
596 c->vc.vBuffer[0] = *v0;
597 c->arrays.cull = v0->flags & vertex_t::CLIP_ALL;
598 } while (count);
599}
600
601void drawPrimitivesLineLoop(ogles_context_t* c, GLint first, GLsizei count)
602{
603 if (ggl_unlikely(count < 2))
604 return;
605 drawPrimitivesLineStrip(c, first, count);
606 if (ggl_likely(count >= 3)) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700607 vertex_t* v0 = c->vc.vBuffer;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800608 vertex_t* v1 = c->vc.vBuffer + 1;
609 c->arrays.compileElement(c, v1, first);
610 const uint32_t cc = v0->flags & v1->flags;
611 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
612 c->prims.renderLine(c, v0, v1);
613 }
614}
615
616void drawPrimitivesLines(ogles_context_t* c, GLint first, GLsizei count)
617{
618 if (ggl_unlikely(count < 2))
619 return;
620
621 // vertex cache size must be multiple of 2
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700622 const GLsizei vcs =
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800623 ((vertex_cache_t::VERTEX_BUFFER_SIZE +
624 vertex_cache_t::VERTEX_CACHE_SIZE) / 2) * 2;
625 do {
626 vertex_t* v = c->vc.vBuffer;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700627 GLsizei num = count > vcs ? vcs : count;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800628 c->arrays.cull = vertex_t::CLIP_ALL;
629 c->arrays.compileElements(c, v, first, num);
630 first += num;
631 count -= num;
632 if (!c->arrays.cull) {
633 // quick/trivial reject of the whole batch
634 num -= 2;
635 do {
636 const uint32_t cc = v[0].flags & v[1].flags;
637 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
638 c->prims.renderLine(c, v, v+1);
639 v += 2;
640 num -= 2;
641 } while (num >= 0);
642 }
643 } while (count >= 2);
644}
645
646// ----------------------------------------------------------------------------
647
648static void drawPrimitivesTriangleFanOrStrip(ogles_context_t* c,
649 GLint first, GLsizei count, int winding)
650{
651 // winding == 2 : fan
652 // winding == 1 : strip
653
654 if (ggl_unlikely(count < 3))
655 return;
656
657 vertex_t *v, *v0, *v1, *v2;
658 c->arrays.cull = vertex_t::CLIP_ALL;
659 c->arrays.compileElements(c, c->vc.vBuffer, first, 2);
660 first += 2;
661 count -= 2;
662
663 // vertex cache size must be multiple of 2. This is extremely important
664 // because it allows us to preserve the same winding when the whole
665 // batch is culled. We also need 2 extra vertices in the array, because
666 // we always keep the two first ones.
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700667 const GLsizei vcs =
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800668 ((vertex_cache_t::VERTEX_BUFFER_SIZE +
669 vertex_cache_t::VERTEX_CACHE_SIZE - 2) / 2) * 2;
670 do {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700671 v0 = c->vc.vBuffer + 0;
672 v1 = c->vc.vBuffer + 1;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800673 v = c->vc.vBuffer + 2;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700674 GLsizei num = count > vcs ? vcs : count;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800675 c->arrays.compileElements(c, v, first, num);
676 first += num;
677 count -= num;
678 if (!c->arrays.cull) {
679 // quick/trivial reject of the whole batch
680 do {
681 v2 = v++;
682 const uint32_t cc = v0->flags & v1->flags & v2->flags;
683 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
684 c->prims.renderTriangle(c, v0, v1, v2);
685 swap(((winding^=1) ? v1 : v0), v2);
686 num--;
687 } while (num);
688 }
689 if (count) {
Mathias Agopiane3586182010-08-18 20:06:34 -0700690 v0 = c->vc.vBuffer + 2 + vcs - 2;
691 v1 = c->vc.vBuffer + 2 + vcs - 1;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800692 if ((winding&2) == 0) {
693 // for strips copy back the two last compiled vertices
694 c->vc.vBuffer[0] = *v0;
695 }
696 c->vc.vBuffer[1] = *v1;
697 c->arrays.cull = v0->flags & v1->flags & vertex_t::CLIP_ALL;
698 }
699 } while (count > 0);
700}
701
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700702void drawPrimitivesTriangleStrip(ogles_context_t* c,
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800703 GLint first, GLsizei count) {
704 drawPrimitivesTriangleFanOrStrip(c, first, count, 1);
705}
706
707void drawPrimitivesTriangleFan(ogles_context_t* c,
708 GLint first, GLsizei count) {
709 drawPrimitivesTriangleFanOrStrip(c, first, count, 2);
710}
711
712void drawPrimitivesTriangles(ogles_context_t* c, GLint first, GLsizei count)
713{
714 if (ggl_unlikely(count < 3))
715 return;
716
717 // vertex cache size must be multiple of 3
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700718 const GLsizei vcs =
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800719 ((vertex_cache_t::VERTEX_BUFFER_SIZE +
720 vertex_cache_t::VERTEX_CACHE_SIZE) / 3) * 3;
721 do {
722 vertex_t* v = c->vc.vBuffer;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700723 GLsizei num = count > vcs ? vcs : count;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800724 c->arrays.cull = vertex_t::CLIP_ALL;
725 c->arrays.compileElements(c, v, first, num);
726 first += num;
727 count -= num;
728 if (!c->arrays.cull) {
729 // quick/trivial reject of the whole batch
730 num -= 3;
731 do {
732 const uint32_t cc = v[0].flags & v[1].flags & v[2].flags;
733 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
734 c->prims.renderTriangle(c, v, v+1, v+2);
735 v += 3;
736 num -= 3;
737 } while (num >= 0);
738 }
739 } while (count >= 3);
740}
741
742// ----------------------------------------------------------------------------
743#if 0
744#pragma mark -
745#endif
746
747// this looks goofy, but gcc does a great job with this...
748static inline unsigned int read_index(int type, const GLvoid*& p) {
749 unsigned int r;
750 if (type) {
751 r = *(const GLubyte*)p;
752 p = (const GLubyte*)p + 1;
753 } else {
754 r = *(const GLushort*)p;
755 p = (const GLushort*)p + 1;
756 }
757 return r;
758}
759
760// ----------------------------------------------------------------------------
761
762void drawIndexedPrimitivesPoints(ogles_context_t* c,
763 GLsizei count, const GLvoid *indices)
764{
765 if (ggl_unlikely(count < 1))
766 return;
767 const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
768 do {
769 vertex_t * v = fetch_vertex(c, read_index(type, indices));
770 if (ggl_likely(!(v->flags & vertex_t::CLIP_ALL)))
771 c->prims.renderPoint(c, v);
772 v->locked = 0;
773 count--;
774 } while(count);
775}
776
777// ----------------------------------------------------------------------------
778
779void drawIndexedPrimitivesLineStrip(ogles_context_t* c,
780 GLsizei count, const GLvoid *indices)
781{
782 if (ggl_unlikely(count < 2))
783 return;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700784
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800785 vertex_t * const v = c->vc.vBuffer;
786 vertex_t* v0 = v;
787 vertex_t* v1;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700788
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800789 const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
790 c->arrays.compileElement(c, v0, read_index(type, indices));
791 count -= 1;
792 do {
793 v1 = fetch_vertex(c, read_index(type, indices));
794 const uint32_t cc = v0->flags & v1->flags;
795 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
796 c->prims.renderLine(c, v0, v1);
797 v0->locked = 0;
798 v0 = v1;
799 count--;
800 } while (count);
801 v1->locked = 0;
802}
803
804void drawIndexedPrimitivesLineLoop(ogles_context_t* c,
805 GLsizei count, const GLvoid *indices)
806{
807 if (ggl_unlikely(count <= 2)) {
808 drawIndexedPrimitivesLines(c, count, indices);
809 return;
810 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700811
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800812 vertex_t * const v = c->vc.vBuffer;
813 vertex_t* v0 = v;
814 vertex_t* v1;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700815
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800816 const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
817 c->arrays.compileElement(c, v0, read_index(type, indices));
818 count -= 1;
819 do {
820 v1 = fetch_vertex(c, read_index(type, indices));
821 const uint32_t cc = v0->flags & v1->flags;
822 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
823 c->prims.renderLine(c, v0, v1);
824 v0->locked = 0;
825 v0 = v1;
826 count--;
827 } while (count);
828 v1->locked = 0;
829
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700830 v1 = c->vc.vBuffer;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800831 const uint32_t cc = v0->flags & v1->flags;
832 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
833 c->prims.renderLine(c, v0, v1);
834}
835
836void drawIndexedPrimitivesLines(ogles_context_t* c,
837 GLsizei count, const GLvoid *indices)
838{
839 if (ggl_unlikely(count < 2))
840 return;
841
842 count -= 2;
843 const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
844 do {
845 vertex_t* const v0 = fetch_vertex(c, read_index(type, indices));
846 vertex_t* const v1 = fetch_vertex(c, read_index(type, indices));
847 const uint32_t cc = v0->flags & v1->flags;
848 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
849 c->prims.renderLine(c, v0, v1);
850 v0->locked = 0;
851 v1->locked = 0;
852 count -= 2;
853 } while (count >= 0);
854}
855
856// ----------------------------------------------------------------------------
857
858static void drawIndexedPrimitivesTriangleFanOrStrip(ogles_context_t* c,
859 GLsizei count, const GLvoid *indices, int winding)
860{
861 // winding == 2 : fan
862 // winding == 1 : strip
863
864 if (ggl_unlikely(count < 3))
865 return;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700866
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800867 vertex_t * const v = c->vc.vBuffer;
868 vertex_t* v0 = v;
869 vertex_t* v1 = v+1;
870 vertex_t* v2;
871
872 const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
873 c->arrays.compileElement(c, v0, read_index(type, indices));
874 c->arrays.compileElement(c, v1, read_index(type, indices));
875 count -= 2;
876
877 // note: GCC 4.1.1 here makes a prety interesting optimization
878 // where it duplicates the loop below based on c->arrays.indicesType
879
880 do {
881 v2 = fetch_vertex(c, read_index(type, indices));
882 const uint32_t cc = v0->flags & v1->flags & v2->flags;
883 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
884 c->prims.renderTriangle(c, v0, v1, v2);
885 vertex_t* & consumed = ((winding^=1) ? v1 : v0);
886 consumed->locked = 0;
887 consumed = v2;
888 count--;
889 } while (count);
890 v0->locked = v1->locked = 0;
891 v2->locked = 0;
892}
893
894void drawIndexedPrimitivesTriangleStrip(ogles_context_t* c,
895 GLsizei count, const GLvoid *indices) {
896 drawIndexedPrimitivesTriangleFanOrStrip(c, count, indices, 1);
897}
898
899void drawIndexedPrimitivesTriangleFan(ogles_context_t* c,
900 GLsizei count, const GLvoid *indices) {
901 drawIndexedPrimitivesTriangleFanOrStrip(c, count, indices, 2);
902}
903
904void drawIndexedPrimitivesTriangles(ogles_context_t* c,
905 GLsizei count, const GLvoid *indices)
906{
907 if (ggl_unlikely(count < 3))
908 return;
909
910 count -= 3;
911 if (ggl_likely(c->arrays.indicesType == GL_UNSIGNED_SHORT)) {
912 // This case is probably our most common case...
913 uint16_t const * p = (uint16_t const *)indices;
914 do {
915 vertex_t* const v0 = fetch_vertex(c, *p++);
916 vertex_t* const v1 = fetch_vertex(c, *p++);
917 vertex_t* const v2 = fetch_vertex(c, *p++);
918 const uint32_t cc = v0->flags & v1->flags & v2->flags;
919 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
920 c->prims.renderTriangle(c, v0, v1, v2);
921 v0->locked = 0;
922 v1->locked = 0;
923 v2->locked = 0;
924 count -= 3;
925 } while (count >= 0);
926 } else {
927 uint8_t const * p = (uint8_t const *)indices;
928 do {
929 vertex_t* const v0 = fetch_vertex(c, *p++);
930 vertex_t* const v1 = fetch_vertex(c, *p++);
931 vertex_t* const v2 = fetch_vertex(c, *p++);
932 const uint32_t cc = v0->flags & v1->flags & v2->flags;
933 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
934 c->prims.renderTriangle(c, v0, v1, v2);
935 v0->locked = 0;
936 v1->locked = 0;
937 v2->locked = 0;
938 count -= 3;
939 } while (count >= 0);
940 }
941}
942
943// ----------------------------------------------------------------------------
944#if 0
945#pragma mark -
946#pragma mark Array compilers
947#endif
948
949void compileElement__generic(ogles_context_t* c,
950 vertex_t* v, GLint first)
951{
952 v->flags = 0;
953 v->index = first;
954 first &= vertex_cache_t::INDEX_MASK;
955 const GLubyte* vp = c->arrays.vertex.element(first);
Mathias Agopian69ca17a2009-06-02 22:05:04 -0700956 v->obj.z = 0;
957 v->obj.w = 0x10000;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800958 c->arrays.vertex.fetch(c, v->obj.v, vp);
959 c->arrays.mvp_transform(&c->transforms.mvp, &v->clip, &v->obj);
960 c->arrays.perspective(c, v);
961}
962
963void compileElements__generic(ogles_context_t* c,
964 vertex_t* v, GLint first, GLsizei count)
965{
966 const GLubyte* vp = c->arrays.vertex.element(
967 first & vertex_cache_t::INDEX_MASK);
968 const size_t stride = c->arrays.vertex.stride;
969 transform_t const* const mvp = &c->transforms.mvp;
970 do {
971 v->flags = 0;
972 v->index = first++;
Mathias Agopian69ca17a2009-06-02 22:05:04 -0700973 v->obj.z = 0;
974 v->obj.w = 0x10000;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800975 c->arrays.vertex.fetch(c, v->obj.v, vp);
976 c->arrays.mvp_transform(mvp, &v->clip, &v->obj);
977 c->arrays.perspective(c, v);
978 vp += stride;
979 v++;
980 } while (--count);
981}
982
983/*
984void compileElements__3x_full(ogles_context_t* c,
985 vertex_t* v, GLint first, GLsizei count)
986{
987 const GLfixed* vp = (const GLfixed*)c->arrays.vertex.element(first);
988 const size_t stride = c->arrays.vertex.stride / 4;
989// const GLfixed* const& m = c->transforms.mvp.matrix.m;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700990
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800991 GLfixed m[16];
992 memcpy(&m, c->transforms.mvp.matrix.m, sizeof(m));
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700993
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800994 do {
995 const GLfixed rx = vp[0];
996 const GLfixed ry = vp[1];
997 const GLfixed rz = vp[2];
998 vp += stride;
999 v->index = first++;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001000 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 -08001001 v->clip.y = mla3a(rx, m[ 1], ry, m[ 5], rz, m[ 9], m[13]);
1002 v->clip.z = mla3a(rx, m[ 2], ry, m[ 6], rz, m[10], m[14]);
1003 v->clip.w = mla3a(rx, m[ 3], ry, m[ 7], rz, m[11], m[15]);
1004
1005 const GLfixed w = v->clip.w;
1006 uint32_t clip = 0;
1007 if (v->clip.x < -w) clip |= vertex_t::CLIP_L;
1008 if (v->clip.x > w) clip |= vertex_t::CLIP_R;
1009 if (v->clip.y < -w) clip |= vertex_t::CLIP_B;
1010 if (v->clip.y > w) clip |= vertex_t::CLIP_T;
1011 if (v->clip.z < -w) clip |= vertex_t::CLIP_N;
1012 if (v->clip.z > w) clip |= vertex_t::CLIP_F;
1013 v->flags = clip;
1014 c->arrays.cull &= clip;
1015
1016 //c->arrays.perspective(c, v);
1017 v++;
1018 } while (--count);
1019}
1020*/
1021
1022// ----------------------------------------------------------------------------
1023#if 0
1024#pragma mark -
1025#pragma mark clippers
1026#endif
1027
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001028static void clipVec4(vec4_t& nv,
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001029 GLfixed t, const vec4_t& s, const vec4_t& p)
1030{
1031 for (int i=0; i<4 ; i++)
1032 nv.v[i] = gglMulAddx(t, s.v[i] - p.v[i], p.v[i], 28);
1033}
1034
1035static void clipVertex(ogles_context_t* c, vertex_t* nv,
1036 GLfixed t, const vertex_t* s, const vertex_t* p)
1037{
1038 clipVec4(nv->clip, t, s->clip, p->clip);
1039 nv->fog = gglMulAddx(t, s->fog - p->fog, p->fog, 28);
1040 ogles_vertex_project(c, nv);
1041 nv->flags |= vertex_t::LIT | vertex_t::EYE | vertex_t::TT;
1042 nv->flags &= ~vertex_t::CLIP_ALL;
1043}
1044
1045static void clipVertexC(ogles_context_t* c, vertex_t* nv,
1046 GLfixed t, const vertex_t* s, const vertex_t* p)
1047{
1048 clipVec4(nv->color, t, s->color, p->color);
1049 clipVertex(c, nv, t, s, p);
1050}
1051
1052static void clipVertexT(ogles_context_t* c, vertex_t* nv,
1053 GLfixed t, const vertex_t* s, const vertex_t* p)
1054{
1055 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
1056 if (c->rasterizer.state.texture[i].enable)
1057 clipVec4(nv->texture[i], t, s->texture[i], p->texture[i]);
1058 }
1059 clipVertex(c, nv, t, s, p);
1060}
1061
1062static void clipVertexAll(ogles_context_t* c, vertex_t* nv,
1063 GLfixed t, const vertex_t* s, const vertex_t* p)
1064{
1065 clipVec4(nv->color, t, s->color, p->color);
1066 clipVertexT(c, nv, t, s, p);
1067}
1068
1069static void clipEye(ogles_context_t* c, vertex_t* nv,
1070 GLfixed t, const vertex_t* s, const vertex_t* p)
1071{
1072 nv->clear();
1073 c->arrays.clipVertex(c, nv, t, p, s);
1074 clipVec4(nv->eye, t, s->eye, p->eye);
1075}
1076
1077// ----------------------------------------------------------------------------
1078#if 0
1079#pragma mark -
1080#endif
1081
1082void validate_arrays(ogles_context_t* c, GLenum mode)
1083{
1084 uint32_t enables = c->rasterizer.state.enables;
1085
1086 // Perspective correction is not need if Ortho transform, but
1087 // the user can still provide the w coordinate manually, so we can't
1088 // automatically turn it off (in fact we could when the 4th coordinate
1089 // is not spcified in the vertex array).
1090 // W interpolation is never needed for points.
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001091 GLboolean perspective =
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001092 c->perspective && mode!=GL_POINTS && (enables & GGL_ENABLE_TMUS);
1093 c->rasterizer.procs.enableDisable(c, GGL_W_LERP, perspective);
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001094
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001095 // set anti-aliasing
1096 GLboolean smooth = GL_FALSE;
1097 switch (mode) {
1098 case GL_POINTS:
1099 smooth = c->point.smooth;
1100 break;
1101 case GL_LINES:
1102 case GL_LINE_LOOP:
1103 case GL_LINE_STRIP:
1104 smooth = c->line.smooth;
1105 break;
1106 }
1107 if (((enables & GGL_ENABLE_AA)?1:0) != smooth)
1108 c->rasterizer.procs.enableDisable(c, GGL_AA, smooth);
1109
1110 // set the shade model for this primitive
1111 c->rasterizer.procs.shadeModel(c,
1112 (mode == GL_POINTS) ? GL_FLAT : c->lighting.shadeModel);
1113
1114 // compute all the matrices we'll need...
1115 uint32_t want =
1116 transform_state_t::MVP |
1117 transform_state_t::VIEWPORT;
1118 if (c->lighting.enable) { // needs normal transforms and eye coords
1119 want |= transform_state_t::MVUI;
1120 want |= transform_state_t::MODELVIEW;
1121 }
1122 if (enables & GGL_ENABLE_TMUS) { // needs texture transforms
1123 want |= transform_state_t::TEXTURE;
1124 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001125 if (c->clipPlanes.enable || (enables & GGL_ENABLE_FOG)) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001126 want |= transform_state_t::MODELVIEW; // needs eye coords
1127 }
1128 ogles_validate_transform(c, want);
1129
1130 // textures...
1131 if (enables & GGL_ENABLE_TMUS)
1132 ogles_validate_texture(c);
1133
1134 // vertex compilers
1135 c->arrays.compileElement = compileElement__generic;
1136 c->arrays.compileElements = compileElements__generic;
1137
1138 // vertex transform
1139 c->arrays.mvp_transform =
1140 c->transforms.mvp.pointv[c->arrays.vertex.size - 2];
1141
1142 c->arrays.mv_transform =
1143 c->transforms.modelview.transform.pointv[c->arrays.vertex.size - 2];
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001144
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001145 /*
1146 * ***********************************************************************
1147 * pick fetchers
1148 * ***********************************************************************
1149 */
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001150
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001151 array_machine_t& am = c->arrays;
1152 am.vertex.fetch = fetchNop;
1153 am.normal.fetch = currentNormal;
1154 am.color.fetch = currentColor;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001155
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001156 if (am.vertex.enable) {
1157 am.vertex.resolve();
1158 if (am.vertex.bo || am.vertex.pointer) {
1159 am.vertex.fetch = vertex_fct[am.vertex.size-2][am.vertex.type & 0xF];
1160 }
1161 }
1162
1163 if (am.normal.enable) {
1164 am.normal.resolve();
1165 if (am.normal.bo || am.normal.pointer) {
1166 am.normal.fetch = normal_fct[am.normal.size-3][am.normal.type & 0xF];
1167 }
1168 }
1169
1170 if (am.color.enable) {
1171 am.color.resolve();
1172 if (c->lighting.enable) {
1173 if (am.color.bo || am.color.pointer) {
1174 am.color.fetch = color_fct[am.color.size-3][am.color.type & 0xF];
1175 }
1176 } else {
1177 if (am.color.bo || am.color.pointer) {
1178 am.color.fetch = color_clamp_fct[am.color.size-3][am.color.type & 0xF];
1179 }
1180 }
1181 }
1182
1183 int activeTmuCount = 0;
1184 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
1185 am.texture[i].fetch = currentTexCoord;
1186 if (c->rasterizer.state.texture[i].enable) {
1187
1188 // texture fetchers...
1189 if (am.texture[i].enable) {
1190 am.texture[i].resolve();
1191 if (am.texture[i].bo || am.texture[i].pointer) {
1192 am.texture[i].fetch = texture_fct[am.texture[i].size-2][am.texture[i].type & 0xF];
1193 }
1194 }
1195
1196 // texture transform...
1197 const int index = c->arrays.texture[i].size - 2;
1198 c->arrays.tex_transform[i] =
1199 c->transforms.texture[i].transform.pointv[index];
1200
1201 am.tmu = i;
1202 activeTmuCount++;
1203 }
1204 }
1205
1206 // pick the vertex-clipper
1207 uint32_t clipper = 0;
1208 // we must reload 'enables' here
1209 enables = c->rasterizer.state.enables;
1210 if (enables & GGL_ENABLE_SMOOTH)
1211 clipper |= 1; // we need to interpolate colors
1212 if (enables & GGL_ENABLE_TMUS)
1213 clipper |= 2; // we need to interpolate textures
1214 switch (clipper) {
1215 case 0: c->arrays.clipVertex = clipVertex; break;
1216 case 1: c->arrays.clipVertex = clipVertexC; break;
1217 case 2: c->arrays.clipVertex = clipVertexT; break;
1218 case 3: c->arrays.clipVertex = clipVertexAll; break;
1219 }
1220 c->arrays.clipEye = clipEye;
1221
1222 // pick the primitive rasterizer
1223 ogles_validate_primitives(c);
1224}
1225
1226// ----------------------------------------------------------------------------
1227}; // namespace android
1228// ----------------------------------------------------------------------------
1229
1230using namespace android;
1231
1232#if 0
1233#pragma mark -
1234#pragma mark array API
1235#endif
1236
1237void glVertexPointer(
1238 GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
1239{
1240 ogles_context_t* c = ogles_context_t::get();
1241 if (size<2 || size>4 || stride<0) {
1242 ogles_error(c, GL_INVALID_VALUE);
1243 return;
1244 }
1245 switch (type) {
1246 case GL_BYTE:
1247 case GL_SHORT:
1248 case GL_FIXED:
1249 case GL_FLOAT:
1250 break;
1251 default:
1252 ogles_error(c, GL_INVALID_ENUM);
1253 return;
1254 }
1255 c->arrays.vertex.init(size, type, stride, pointer, c->arrays.array_buffer, 0);
1256}
1257
1258void glColorPointer(
1259 GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
1260{
1261 ogles_context_t* c = ogles_context_t::get();
Mathias Agopianc5f01552009-09-24 14:22:29 -07001262 if (size!=4 || stride<0) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001263 ogles_error(c, GL_INVALID_VALUE);
1264 return;
1265 }
1266 switch (type) {
1267 case GL_UNSIGNED_BYTE:
1268 case GL_FIXED:
1269 case GL_FLOAT:
1270 break;
1271 default:
1272 ogles_error(c, GL_INVALID_ENUM);
1273 return;
1274 }
1275 c->arrays.color.init(size, type, stride, pointer, c->arrays.array_buffer, 0);
1276}
1277
1278void glNormalPointer(
1279 GLenum type, GLsizei stride, const GLvoid *pointer)
1280{
1281 ogles_context_t* c = ogles_context_t::get();
1282 if (stride<0) {
1283 ogles_error(c, GL_INVALID_VALUE);
1284 return;
1285 }
1286 switch (type) {
1287 case GL_BYTE:
1288 case GL_SHORT:
1289 case GL_FIXED:
1290 case GL_FLOAT:
1291 break;
1292 default:
1293 ogles_error(c, GL_INVALID_ENUM);
1294 return;
1295 }
1296 c->arrays.normal.init(3, type, stride, pointer, c->arrays.array_buffer, 0);
1297}
1298
1299void glTexCoordPointer(
1300 GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
1301{
1302 ogles_context_t* c = ogles_context_t::get();
1303 if (size<2 || size>4 || stride<0) {
1304 ogles_error(c, GL_INVALID_VALUE);
1305 return;
1306 }
1307 switch (type) {
1308 case GL_BYTE:
1309 case GL_SHORT:
1310 case GL_FIXED:
1311 case GL_FLOAT:
1312 break;
1313 default:
1314 ogles_error(c, GL_INVALID_ENUM);
1315 return;
1316 }
1317 const int tmu = c->arrays.activeTexture;
1318 c->arrays.texture[tmu].init(size, type, stride, pointer,
1319 c->arrays.array_buffer, 0);
1320}
1321
1322
1323void glEnableClientState(GLenum array) {
1324 ogles_context_t* c = ogles_context_t::get();
1325 enableDisableClientState(c, array, true);
1326}
1327
1328void glDisableClientState(GLenum array) {
1329 ogles_context_t* c = ogles_context_t::get();
1330 enableDisableClientState(c, array, false);
1331}
1332
1333void glClientActiveTexture(GLenum texture)
1334{
1335 ogles_context_t* c = ogles_context_t::get();
1336 if (texture<GL_TEXTURE0 || texture>=GL_TEXTURE0+GGL_TEXTURE_UNIT_COUNT) {
1337 ogles_error(c, GL_INVALID_ENUM);
1338 return;
1339 }
1340 c->arrays.activeTexture = texture - GL_TEXTURE0;
1341}
1342
1343void glDrawArrays(GLenum mode, GLint first, GLsizei count)
1344{
1345 ogles_context_t* c = ogles_context_t::get();
1346 if (count<0) {
1347 ogles_error(c, GL_INVALID_VALUE);
1348 return;
1349 }
1350 switch (mode) {
1351 case GL_POINTS:
1352 case GL_LINE_STRIP:
1353 case GL_LINE_LOOP:
1354 case GL_LINES:
1355 case GL_TRIANGLE_STRIP:
1356 case GL_TRIANGLE_FAN:
1357 case GL_TRIANGLES:
1358 break;
1359 default:
1360 ogles_error(c, GL_INVALID_ENUM);
1361 return;
1362 }
1363
1364 if (count == 0 || !c->arrays.vertex.enable)
1365 return;
1366 if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK))
1367 return; // all triangles are culled
1368
Mathias Agopian0926f502009-05-04 14:17:04 -07001369
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001370 validate_arrays(c, mode);
Mathias Agopian0926f502009-05-04 14:17:04 -07001371
1372 const uint32_t enables = c->rasterizer.state.enables;
1373 if (enables & GGL_ENABLE_TMUS)
1374 ogles_lock_textures(c);
1375
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001376 drawArraysPrims[mode](c, first, count);
1377
Mathias Agopian0926f502009-05-04 14:17:04 -07001378 if (enables & GGL_ENABLE_TMUS)
1379 ogles_unlock_textures(c);
1380
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001381#if VC_CACHE_STATISTICS
1382 c->vc.total = count;
1383 c->vc.dump_stats(mode);
1384#endif
1385}
1386
1387void glDrawElements(
1388 GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
1389{
1390 ogles_context_t* c = ogles_context_t::get();
1391 if (count<0) {
1392 ogles_error(c, GL_INVALID_VALUE);
1393 return;
1394 }
1395 switch (mode) {
1396 case GL_POINTS:
1397 case GL_LINE_STRIP:
1398 case GL_LINE_LOOP:
1399 case GL_LINES:
1400 case GL_TRIANGLE_STRIP:
1401 case GL_TRIANGLE_FAN:
1402 case GL_TRIANGLES:
1403 break;
1404 default:
1405 ogles_error(c, GL_INVALID_ENUM);
1406 return;
1407 }
1408 switch (type) {
1409 case GL_UNSIGNED_BYTE:
1410 case GL_UNSIGNED_SHORT:
1411 c->arrays.indicesType = type;
1412 break;
1413 default:
1414 ogles_error(c, GL_INVALID_ENUM);
1415 return;
1416 }
1417 if (count == 0 || !c->arrays.vertex.enable)
1418 return;
1419 if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK))
1420 return; // all triangles are culled
1421
1422 // clear the vertex-cache
1423 c->vc.clear();
1424 validate_arrays(c, mode);
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001425
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001426 // if indices are in a buffer object, the pointer is treated as an
1427 // offset in that buffer.
1428 if (c->arrays.element_array_buffer) {
1429 indices = c->arrays.element_array_buffer->data + uintptr_t(indices);
1430 }
1431
Mathias Agopian0926f502009-05-04 14:17:04 -07001432 const uint32_t enables = c->rasterizer.state.enables;
1433 if (enables & GGL_ENABLE_TMUS)
1434 ogles_lock_textures(c);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001435
Mathias Agopian0926f502009-05-04 14:17:04 -07001436 drawElementsPrims[mode](c, count, indices);
1437
1438 if (enables & GGL_ENABLE_TMUS)
1439 ogles_unlock_textures(c);
1440
1441
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001442#if VC_CACHE_STATISTICS
1443 c->vc.total = count;
1444 c->vc.dump_stats(mode);
1445#endif
1446}
1447
1448// ----------------------------------------------------------------------------
1449// buffers
1450// ----------------------------------------------------------------------------
1451
1452void glBindBuffer(GLenum target, GLuint buffer)
1453{
1454 ogles_context_t* c = ogles_context_t::get();
1455 if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) {
1456 ogles_error(c, GL_INVALID_ENUM);
1457 return;
1458 }
1459 // create a buffer object, or bind an existing one
1460 buffer_t const* bo = 0;
1461 if (buffer) {
1462 bo = c->bufferObjectManager->bind(buffer);
1463 if (!bo) {
1464 ogles_error(c, GL_OUT_OF_MEMORY);
1465 return;
1466 }
1467 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001468 ((target == GL_ARRAY_BUFFER) ?
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001469 c->arrays.array_buffer : c->arrays.element_array_buffer) = bo;
1470}
1471
1472void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
1473{
1474 ogles_context_t* c = ogles_context_t::get();
1475 if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) {
1476 ogles_error(c, GL_INVALID_ENUM);
1477 return;
1478 }
1479 if (size<0) {
1480 ogles_error(c, GL_INVALID_VALUE);
1481 return;
1482 }
1483 if ((usage!=GL_STATIC_DRAW) && (usage!=GL_DYNAMIC_DRAW)) {
1484 ogles_error(c, GL_INVALID_ENUM);
1485 return;
1486 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001487 buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001488 c->arrays.array_buffer : c->arrays.element_array_buffer);
1489
1490 if (bo == 0) {
1491 // can't modify buffer 0
1492 ogles_error(c, GL_INVALID_OPERATION);
1493 return;
1494 }
1495
1496 buffer_t* edit_bo = const_cast<buffer_t*>(bo);
1497 if (c->bufferObjectManager->allocateStore(edit_bo, size, usage) != 0) {
1498 ogles_error(c, GL_OUT_OF_MEMORY);
1499 return;
1500 }
1501 if (data) {
1502 memcpy(bo->data, data, size);
1503 }
1504}
1505
1506void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
1507{
1508 ogles_context_t* c = ogles_context_t::get();
1509 if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) {
1510 ogles_error(c, GL_INVALID_ENUM);
1511 return;
1512 }
1513 if (offset<0 || size<0 || data==0) {
1514 ogles_error(c, GL_INVALID_VALUE);
1515 return;
1516 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001517 buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001518 c->arrays.array_buffer : c->arrays.element_array_buffer);
1519
1520 if (bo == 0) {
1521 // can't modify buffer 0
1522 ogles_error(c, GL_INVALID_OPERATION);
1523 return;
1524 }
1525 if (offset+size > bo->size) {
1526 ogles_error(c, GL_INVALID_VALUE);
1527 return;
1528 }
1529 memcpy(bo->data + offset, data, size);
1530}
1531
1532void glDeleteBuffers(GLsizei n, const GLuint* buffers)
1533{
1534 ogles_context_t* c = ogles_context_t::get();
1535 if (n<0) {
1536 ogles_error(c, GL_INVALID_VALUE);
1537 return;
1538 }
1539
1540 for (int i=0 ; i<n ; i++) {
1541 GLuint name = buffers[i];
1542 if (name) {
1543 // unbind bound deleted buffers...
Mathias Agopiana750fc02009-11-19 17:32:05 -08001544 if (c->arrays.element_array_buffer) {
1545 if (c->arrays.element_array_buffer->name == name) {
1546 c->arrays.element_array_buffer = 0;
1547 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001548 }
Mathias Agopiana750fc02009-11-19 17:32:05 -08001549 if (c->arrays.array_buffer) {
1550 if (c->arrays.array_buffer->name == name) {
1551 c->arrays.array_buffer = 0;
1552 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001553 }
Mathias Agopiana750fc02009-11-19 17:32:05 -08001554 if (c->arrays.vertex.bo) {
1555 if (c->arrays.vertex.bo->name == name) {
1556 c->arrays.vertex.bo = 0;
1557 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001558 }
Mathias Agopiana750fc02009-11-19 17:32:05 -08001559 if (c->arrays.normal.bo) {
1560 if (c->arrays.normal.bo->name == name) {
1561 c->arrays.normal.bo = 0;
1562 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001563 }
Mathias Agopiana750fc02009-11-19 17:32:05 -08001564 if (c->arrays.color.bo) {
1565 if (c->arrays.color.bo->name == name) {
1566 c->arrays.color.bo = 0;
1567 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001568 }
1569 for (int t=0 ; t<GGL_TEXTURE_UNIT_COUNT ; t++) {
Mathias Agopiana750fc02009-11-19 17:32:05 -08001570 if (c->arrays.texture[t].bo) {
1571 if (c->arrays.texture[t].bo->name == name) {
1572 c->arrays.texture[t].bo = 0;
1573 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001574 }
1575 }
1576 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001577 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001578 c->bufferObjectManager->deleteBuffers(n, buffers);
1579 c->bufferObjectManager->recycleTokens(n, buffers);
1580}
1581
1582void glGenBuffers(GLsizei n, GLuint* buffers)
1583{
1584 ogles_context_t* c = ogles_context_t::get();
1585 if (n<0) {
1586 ogles_error(c, GL_INVALID_VALUE);
1587 return;
1588 }
1589 c->bufferObjectManager->getToken(n, buffers);
1590}