diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:31:44 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:31:44 -0800 |
commit | 9066cfe9886ac131c34d59ed0e2d287b0e3c0087 (patch) | |
tree | d88beb88001f2482911e3d28e43833b50e4b4e97 /opengl/libagl/array.cpp | |
parent | d83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (diff) | |
download | frameworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.zip frameworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.tar.gz frameworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'opengl/libagl/array.cpp')
-rw-r--r-- | opengl/libagl/array.cpp | 1557 |
1 files changed, 1557 insertions, 0 deletions
diff --git a/opengl/libagl/array.cpp b/opengl/libagl/array.cpp new file mode 100644 index 0000000..8fa7566 --- /dev/null +++ b/opengl/libagl/array.cpp @@ -0,0 +1,1557 @@ +/* +** Copyright 2006, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include <stdlib.h> +#include <stdio.h> + +#include "context.h" +#include "fp.h" +#include "state.h" +#include "matrix.h" +#include "vertex.h" +#include "light.h" +#include "primitives.h" +#include "texture.h" +#include "BufferObjectManager.h" + +// ---------------------------------------------------------------------------- + +#define VC_CACHE_STATISTICS 0 +#define VC_CACHE_TYPE_NONE 0 +#define VC_CACHE_TYPE_INDEXED 1 +#define VC_CACHE_TYPE_LRU 2 +#define VC_CACHE_TYPE VC_CACHE_TYPE_INDEXED + +#if VC_CACHE_STATISTICS +#include <utils/Timers.h> +#endif + +// ---------------------------------------------------------------------------- + +namespace android { + +static void validate_arrays(ogles_context_t* c, GLenum mode); + +static void compileElements__generic(ogles_context_t*, + vertex_t*, GLint, GLsizei); +static void compileElement__generic(ogles_context_t*, + vertex_t*, GLint); + +static void drawPrimitivesPoints(ogles_context_t*, GLint, GLsizei); +static void drawPrimitivesLineStrip(ogles_context_t*, GLint, GLsizei); +static void drawPrimitivesLineLoop(ogles_context_t*, GLint, GLsizei); +static void drawPrimitivesLines(ogles_context_t*, GLint, GLsizei); +static void drawPrimitivesTriangleStrip(ogles_context_t*, GLint, GLsizei); +static void drawPrimitivesTriangleFan(ogles_context_t*, GLint, GLsizei); +static void drawPrimitivesTriangles(ogles_context_t*, GLint, GLsizei); + +static void drawIndexedPrimitivesPoints(ogles_context_t*, + GLsizei, const GLvoid*); +static void drawIndexedPrimitivesLineStrip(ogles_context_t*, + GLsizei, const GLvoid*); +static void drawIndexedPrimitivesLineLoop(ogles_context_t*, + GLsizei, const GLvoid*); +static void drawIndexedPrimitivesLines(ogles_context_t*, + GLsizei, const GLvoid*); +static void drawIndexedPrimitivesTriangleStrip(ogles_context_t*, + GLsizei, const GLvoid*); +static void drawIndexedPrimitivesTriangleFan(ogles_context_t*, + GLsizei, const GLvoid*); +static void drawIndexedPrimitivesTriangles(ogles_context_t*, + GLsizei, const GLvoid*); + +// ---------------------------------------------------------------------------- + +typedef void (*arrays_prims_fct_t)(ogles_context_t*, GLint, GLsizei); +static const arrays_prims_fct_t drawArraysPrims[] = { + drawPrimitivesPoints, + drawPrimitivesLines, + drawPrimitivesLineLoop, + drawPrimitivesLineStrip, + drawPrimitivesTriangles, + drawPrimitivesTriangleStrip, + drawPrimitivesTriangleFan +}; + +typedef void (*elements_prims_fct_t)(ogles_context_t*, GLsizei, const GLvoid*); +static const elements_prims_fct_t drawElementsPrims[] = { + drawIndexedPrimitivesPoints, + drawIndexedPrimitivesLines, + drawIndexedPrimitivesLineLoop, + drawIndexedPrimitivesLineStrip, + drawIndexedPrimitivesTriangles, + drawIndexedPrimitivesTriangleStrip, + drawIndexedPrimitivesTriangleFan +}; + +// ---------------------------------------------------------------------------- +#if 0 +#pragma mark - +#endif + +void ogles_init_array(ogles_context_t* c) +{ + c->arrays.vertex.size = 4; + c->arrays.vertex.type = GL_FLOAT; + c->arrays.color.size = 4; + c->arrays.color.type = GL_FLOAT; + c->arrays.normal.size = 4; + c->arrays.normal.type = GL_FLOAT; + for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) { + c->arrays.texture[i].size = 4; + c->arrays.texture[i].type = GL_FLOAT; + } + c->vc.init(); + + if (!c->vc.vBuffer) { + // this could have failed + ogles_error(c, GL_OUT_OF_MEMORY); + } +} + +void ogles_uninit_array(ogles_context_t* c) +{ + c->vc.uninit(); +} + +// ---------------------------------------------------------------------------- +#if 0 +#pragma mark - +#pragma mark Array fetchers +#endif + +static void currentColor(ogles_context_t* c, GLfixed* v, const GLvoid*) { + memcpy(v, c->current.color.v, sizeof(vec4_t)); +} +static void currentColor_clamp(ogles_context_t* c, GLfixed* v, const GLvoid*) { + memcpy(v, c->currentColorClamped.v, sizeof(vec4_t)); +} +static void currentNormal(ogles_context_t* c, GLfixed* v, const GLvoid*) { + memcpy(v, c->currentNormal.v, sizeof(vec3_t)); +} +static void currentTexCoord(ogles_context_t* c, GLfixed* v, const GLvoid*) { + memcpy(v, c->current.texture[c->arrays.tmu].v, sizeof(vec4_t)); +} + + +static void fetchNop(ogles_context_t*, GLfixed*, const GLvoid*) { +} +static void fetch2b(ogles_context_t*, GLfixed* v, const GLbyte* p) { + v[0] = gglIntToFixed(p[0]); + v[1] = gglIntToFixed(p[1]); +} +static void fetch2s(ogles_context_t*, GLfixed* v, const GLshort* p) { + v[0] = gglIntToFixed(p[0]); + v[1] = gglIntToFixed(p[1]); +} +static void fetch2x(ogles_context_t*, GLfixed* v, const GLfixed* p) { + memcpy(v, p, 2*sizeof(GLfixed)); +} +static void fetch2f(ogles_context_t*, GLfixed* v, const GLfloat* p) { + v[0] = gglFloatToFixed(p[0]); + v[1] = gglFloatToFixed(p[1]); +} +static void fetch3b(ogles_context_t*, GLfixed* v, const GLbyte* p) { + v[0] = gglIntToFixed(p[0]); + v[1] = gglIntToFixed(p[1]); + v[2] = gglIntToFixed(p[2]); +} +static void fetch3s(ogles_context_t*, GLfixed* v, const GLshort* p) { + v[0] = gglIntToFixed(p[0]); + v[1] = gglIntToFixed(p[1]); + v[2] = gglIntToFixed(p[2]); +} +static void fetch3x(ogles_context_t*, GLfixed* v, const GLfixed* p) { + memcpy(v, p, 3*sizeof(GLfixed)); +} +static void fetch3f(ogles_context_t*, GLfixed* v, const GLfloat* p) { + v[0] = gglFloatToFixed(p[0]); + v[1] = gglFloatToFixed(p[1]); + v[2] = gglFloatToFixed(p[2]); +} +static void fetch4b(ogles_context_t*, GLfixed* v, const GLbyte* p) { + v[0] = gglIntToFixed(p[0]); + v[1] = gglIntToFixed(p[1]); + v[2] = gglIntToFixed(p[2]); + v[3] = gglIntToFixed(p[3]); +} +static void fetch4s(ogles_context_t*, GLfixed* v, const GLshort* p) { + v[0] = gglIntToFixed(p[0]); + v[1] = gglIntToFixed(p[1]); + v[2] = gglIntToFixed(p[2]); + v[3] = gglIntToFixed(p[3]); +} +static void fetch4x(ogles_context_t*, GLfixed* v, const GLfixed* p) { + memcpy(v, p, 4*sizeof(GLfixed)); +} +static void fetch4f(ogles_context_t*, GLfixed* v, const GLfloat* p) { + v[0] = gglFloatToFixed(p[0]); + v[1] = gglFloatToFixed(p[1]); + v[2] = gglFloatToFixed(p[2]); + v[3] = gglFloatToFixed(p[3]); +} +static void fetchExpand4ub(ogles_context_t*, GLfixed* v, const GLubyte* p) { + v[0] = GGL_UB_TO_X(p[0]); + v[1] = GGL_UB_TO_X(p[1]); + v[2] = GGL_UB_TO_X(p[2]); + v[3] = GGL_UB_TO_X(p[3]); +} +static void fetchClamp4x(ogles_context_t*, GLfixed* v, const GLfixed* p) { + v[0] = gglClampx(p[0]); + v[1] = gglClampx(p[1]); + v[2] = gglClampx(p[2]); + v[3] = gglClampx(p[3]); +} +static void fetchClamp4f(ogles_context_t*, GLfixed* v, const GLfloat* p) { + v[0] = gglClampx(gglFloatToFixed(p[0])); + v[1] = gglClampx(gglFloatToFixed(p[1])); + v[2] = gglClampx(gglFloatToFixed(p[2])); + v[3] = gglClampx(gglFloatToFixed(p[3])); +} +static void fetchExpand3ub(ogles_context_t*, GLfixed* v, const GLubyte* p) { + v[0] = GGL_UB_TO_X(p[0]); + v[1] = GGL_UB_TO_X(p[1]); + v[2] = GGL_UB_TO_X(p[2]); + v[3] = 0x10000; +} +static void fetchClamp3x(ogles_context_t*, GLfixed* v, const GLfixed* p) { + v[0] = gglClampx(p[0]); + v[1] = gglClampx(p[1]); + v[2] = gglClampx(p[2]); + v[3] = 0x10000; +} +static void fetchClamp3f(ogles_context_t*, GLfixed* v, const GLfloat* p) { + v[0] = gglClampx(gglFloatToFixed(p[0])); + v[1] = gglClampx(gglFloatToFixed(p[1])); + v[2] = gglClampx(gglFloatToFixed(p[2])); + v[3] = 0x10000; +} +static void fetchExpand3b(ogles_context_t*, GLfixed* v, const GLbyte* p) { + v[0] = GGL_B_TO_X(p[0]); + v[1] = GGL_B_TO_X(p[1]); + v[2] = GGL_B_TO_X(p[2]); +} +static void fetchExpand3s(ogles_context_t*, GLfixed* v, const GLshort* p) { + v[0] = GGL_S_TO_X(p[0]); + v[1] = GGL_S_TO_X(p[1]); + v[2] = GGL_S_TO_X(p[2]); +} + +typedef array_t::fetcher_t fn_t; + +static const fn_t color_fct[2][16] = { // size={3,4}, type={ub,f,x} + { 0, (fn_t)fetchExpand3ub, 0, 0, 0, 0, + (fn_t)fetch3f, 0, 0, 0, 0, 0, + (fn_t)fetch3x }, + { 0, (fn_t)fetchExpand4ub, 0, 0, 0, 0, + (fn_t)fetch4f, 0, 0, 0, 0, 0, + (fn_t)fetch4x }, +}; +static const fn_t color_clamp_fct[2][16] = { // size={3,4}, type={ub,f,x} + { 0, (fn_t)fetchExpand3ub, 0, 0, 0, 0, + (fn_t)fetchClamp3f, 0, 0, 0, 0, 0, + (fn_t)fetchClamp3x }, + { 0, (fn_t)fetchExpand4ub, 0, 0, 0, 0, + (fn_t)fetchClamp4f, 0, 0, 0, 0, 0, + (fn_t)fetchClamp4x }, +}; +static const fn_t normal_fct[1][16] = { // size={3}, type={b,s,f,x} + { (fn_t)fetchExpand3b, 0, + (fn_t)fetchExpand3s, 0, 0, 0, + (fn_t)fetch3f, 0, 0, 0, 0, 0, + (fn_t)fetch3x }, +}; +static const fn_t vertex_fct[3][16] = { // size={2,3,4}, type={b,s,f,x} + { (fn_t)fetch2b, 0, + (fn_t)fetch2s, 0, 0, 0, + (fn_t)fetch2f, 0, 0, 0, 0, 0, + (fn_t)fetch3x }, + { (fn_t)fetch3b, 0, + (fn_t)fetch3s, 0, 0, 0, + (fn_t)fetch3f, 0, 0, 0, 0, 0, + (fn_t)fetch3x }, + { (fn_t)fetch4b, 0, + (fn_t)fetch4s, 0, 0, 0, + (fn_t)fetch4f, 0, 0, 0, 0, 0, + (fn_t)fetch4x } +}; +static const fn_t texture_fct[3][16] = { // size={2,3,4}, type={b,s,f,x} + { (fn_t)fetch2b, 0, + (fn_t)fetch2s, 0, 0, 0, + (fn_t)fetch2f, 0, 0, 0, 0, 0, + (fn_t)fetch2x }, + { (fn_t)fetch3b, 0, + (fn_t)fetch3s, 0, 0, 0, + (fn_t)fetch3f, 0, 0, 0, 0, 0, + (fn_t)fetch3x }, + { (fn_t)fetch4b, 0, + (fn_t)fetch4s, 0, 0, 0, + (fn_t)fetch4f, 0, 0, 0, 0, 0, + (fn_t)fetch4x } +}; + +// ---------------------------------------------------------------------------- +#if 0 +#pragma mark - +#pragma mark array_t +#endif + +void array_t::init( + GLint size, GLenum type, GLsizei stride, + const GLvoid *pointer, const buffer_t* bo, GLsizei count) +{ + if (!stride) { + stride = size; + switch (type) { + case GL_SHORT: + case GL_UNSIGNED_SHORT: + stride *= 2; + break; + case GL_FLOAT: + case GL_FIXED: + stride *= 4; + break; + } + } + this->size = size; + this->type = type; + this->stride = stride; + this->pointer = pointer; + this->bo = bo; + this->bounds = count; +} + +inline void array_t::resolve() +{ + physical_pointer = (bo) ? (bo->data + uintptr_t(pointer)) : pointer; +} + +// ---------------------------------------------------------------------------- +#if 0 +#pragma mark - +#pragma mark vertex_cache_t +#endif + +void vertex_cache_t::init() +{ + // make sure the size of vertex_t allows cache-line alignment + CTA<(sizeof(vertex_t) & 0x1F) == 0> assertAlignedSize; + + const int align = 32; + const size_t s = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE; + const size_t size = s*sizeof(vertex_t) + align; + base = malloc(size); + if (base) { + memset(base, 0, size); + vBuffer = (vertex_t*)((size_t(base) + align - 1) & ~(align-1)); + vCache = vBuffer + VERTEX_BUFFER_SIZE; + sequence = 0; + } +} + +void vertex_cache_t::uninit() +{ + free(base); + base = vBuffer = vCache = 0; +} + +void vertex_cache_t::clear() +{ +#if VC_CACHE_STATISTICS + startTime = systemTime(SYSTEM_TIME_THREAD); + total = 0; + misses = 0; +#endif + +#if VC_CACHE_TYPE == VC_CACHE_TYPE_LRU + vertex_t* v = vBuffer; + size_t count = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE; + do { + v->mru = 0; + v++; + } while (--count); +#endif + + sequence += INDEX_SEQ; + if (sequence >= 0x80000000LU) { + sequence = INDEX_SEQ; + vertex_t* v = vBuffer; + size_t count = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE; + do { + v->index = 0; + v++; + } while (--count); + } +} + +void vertex_cache_t::dump_stats(GLenum mode) +{ +#if VC_CACHE_STATISTICS + nsecs_t time = systemTime(SYSTEM_TIME_THREAD) - startTime; + uint32_t hits = total - misses; + uint32_t prim_count; + switch (mode) { + case GL_POINTS: prim_count = total; break; + case GL_LINE_STRIP: prim_count = total - 1; break; + case GL_LINE_LOOP: prim_count = total - 1; break; + case GL_LINES: prim_count = total / 2; break; + case GL_TRIANGLE_STRIP: prim_count = total - 2; break; + case GL_TRIANGLE_FAN: prim_count = total - 2; break; + case GL_TRIANGLES: prim_count = total / 3; break; + default: return; + } + printf( "total=%5u, hits=%5u, miss=%5u, hitrate=%3u%%," + " prims=%5u, time=%6u us, prims/s=%d, v/t=%f\n", + total, hits, misses, (hits*100)/total, + prim_count, int(ns2us(time)), int(prim_count*float(seconds(1))/time), + float(misses) / prim_count); +#endif +} + +// ---------------------------------------------------------------------------- +#if 0 +#pragma mark - +#endif + +static __attribute__((noinline)) +void enableDisableClientState(ogles_context_t* c, GLenum array, bool enable) +{ + const int tmu = c->arrays.activeTexture; + array_t* a; + switch (array) { + case GL_COLOR_ARRAY: a = &c->arrays.color; break; + case GL_NORMAL_ARRAY: a = &c->arrays.normal; break; + case GL_TEXTURE_COORD_ARRAY: a = &c->arrays.texture[tmu]; break; + case GL_VERTEX_ARRAY: a = &c->arrays.vertex; break; + default: + ogles_error(c, GL_INVALID_ENUM); + return; + } + a->enable = enable ? GL_TRUE : GL_FALSE; +} + +// ---------------------------------------------------------------------------- +#if 0 +#pragma mark - +#pragma mark Vertex Cache +#endif + +static __attribute__((noinline)) +vertex_t* cache_vertex(ogles_context_t* c, vertex_t* v, uint32_t index) +{ + #if VC_CACHE_STATISTICS + c->vc.misses++; + #endif + if (ggl_unlikely(v->locked)) { + // we're just looking for an entry in the cache that is not locked. + // and we know that there cannot be more than 2 locked entries + // because a triangle needs at most 3 vertices. + // We never use the first and second entries because they might be in + // use by the striper or faner. Any other entry will do as long as + // it's not locked. + // We compute directly the index of a "free" entry from the locked + // state of v[2] and v[3]. + v = c->vc.vBuffer + 2; + v += v[0].locked | (v[1].locked<<1); + } + // note: compileElement clears v->flags + c->arrays.compileElement(c, v, index); + v->locked = 1; + return v; +} + +static __attribute__((noinline)) +vertex_t* fetch_vertex(ogles_context_t* c, size_t index) +{ + index |= c->vc.sequence; + +#if VC_CACHE_TYPE == VC_CACHE_TYPE_INDEXED + + vertex_t* const v = c->vc.vCache + + (index & (vertex_cache_t::VERTEX_CACHE_SIZE-1)); + + if (ggl_likely(v->index == index)) { + v->locked = 1; + return v; + } + return cache_vertex(c, v, index); + +#elif VC_CACHE_TYPE == VC_CACHE_TYPE_LRU + + vertex_t* v = c->vc.vCache + + (index & ((vertex_cache_t::VERTEX_CACHE_SIZE-1)>>1))*2; + + // always record LRU in v[0] + if (ggl_likely(v[0].index == index)) { + v[0].locked = 1; + v[0].mru = 0; + return &v[0]; + } + + if (ggl_likely(v[1].index == index)) { + v[1].locked = 1; + v[0].mru = 1; + return &v[1]; + } + + const int lru = 1 - v[0].mru; + v[0].mru = lru; + return cache_vertex(c, &v[lru], index); + +#elif VC_CACHE_TYPE == VC_CACHE_TYPE_NONE + + // just for debugging... + vertex_t* v = c->vc.vBuffer + 2; + return cache_vertex(c, v, index); + +#endif +} + +// ---------------------------------------------------------------------------- +#if 0 +#pragma mark - +#pragma mark Primitive Assembly +#endif + +void drawPrimitivesPoints(ogles_context_t* c, GLint first, GLsizei count) +{ + if (ggl_unlikely(count < 1)) + return; + + // vertex cache size must be multiple of 1 + const GLsizei vcs = + (vertex_cache_t::VERTEX_BUFFER_SIZE + + vertex_cache_t::VERTEX_CACHE_SIZE); + do { + vertex_t* v = c->vc.vBuffer; + GLsizei num = count > vcs ? vcs : count; + c->arrays.cull = vertex_t::CLIP_ALL; + c->arrays.compileElements(c, v, first, num); + first += num; + count -= num; + if (!c->arrays.cull) { + // quick/trivial reject of the whole batch + do { + const uint32_t cc = v[0].flags; + if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) + c->prims.renderPoint(c, v); + v++; + num--; + } while (num); + } + } while (count); +} + +// ---------------------------------------------------------------------------- + +void drawPrimitivesLineStrip(ogles_context_t* c, GLint first, GLsizei count) +{ + if (ggl_unlikely(count < 2)) + return; + + vertex_t *v, *v0, *v1; + c->arrays.cull = vertex_t::CLIP_ALL; + c->arrays.compileElement(c, c->vc.vBuffer, first); + first += 1; + count -= 1; + + // vertex cache size must be multiple of 1 + const GLsizei vcs = + (vertex_cache_t::VERTEX_BUFFER_SIZE + + vertex_cache_t::VERTEX_CACHE_SIZE - 1); + do { + v0 = c->vc.vBuffer + 0; + v = c->vc.vBuffer + 1; + GLsizei num = count > vcs ? vcs : count; + c->arrays.compileElements(c, v, first, num); + first += num; + count -= num; + if (!c->arrays.cull) { + // quick/trivial reject of the whole batch + do { + v1 = v++; + const uint32_t cc = v0->flags & v1->flags; + if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) + c->prims.renderLine(c, v0, v1); + v0 = v1; + num--; + } while (num); + } + // copy back the last processed vertex + c->vc.vBuffer[0] = *v0; + c->arrays.cull = v0->flags & vertex_t::CLIP_ALL; + } while (count); +} + +void drawPrimitivesLineLoop(ogles_context_t* c, GLint first, GLsizei count) +{ + if (ggl_unlikely(count < 2)) + return; + drawPrimitivesLineStrip(c, first, count); + if (ggl_likely(count >= 3)) { + vertex_t* v0 = c->vc.vBuffer; + vertex_t* v1 = c->vc.vBuffer + 1; + c->arrays.compileElement(c, v1, first); + const uint32_t cc = v0->flags & v1->flags; + if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) + c->prims.renderLine(c, v0, v1); + } +} + +void drawPrimitivesLines(ogles_context_t* c, GLint first, GLsizei count) +{ + if (ggl_unlikely(count < 2)) + return; + + // vertex cache size must be multiple of 2 + const GLsizei vcs = + ((vertex_cache_t::VERTEX_BUFFER_SIZE + + vertex_cache_t::VERTEX_CACHE_SIZE) / 2) * 2; + do { + vertex_t* v = c->vc.vBuffer; + GLsizei num = count > vcs ? vcs : count; + c->arrays.cull = vertex_t::CLIP_ALL; + c->arrays.compileElements(c, v, first, num); + first += num; + count -= num; + if (!c->arrays.cull) { + // quick/trivial reject of the whole batch + num -= 2; + do { + const uint32_t cc = v[0].flags & v[1].flags; + if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) + c->prims.renderLine(c, v, v+1); + v += 2; + num -= 2; + } while (num >= 0); + } + } while (count >= 2); +} + +// ---------------------------------------------------------------------------- + +static void drawPrimitivesTriangleFanOrStrip(ogles_context_t* c, + GLint first, GLsizei count, int winding) +{ + // winding == 2 : fan + // winding == 1 : strip + + if (ggl_unlikely(count < 3)) + return; + + vertex_t *v, *v0, *v1, *v2; + c->arrays.cull = vertex_t::CLIP_ALL; + c->arrays.compileElements(c, c->vc.vBuffer, first, 2); + first += 2; + count -= 2; + + // vertex cache size must be multiple of 2. This is extremely important + // because it allows us to preserve the same winding when the whole + // batch is culled. We also need 2 extra vertices in the array, because + // we always keep the two first ones. + const GLsizei vcs = + ((vertex_cache_t::VERTEX_BUFFER_SIZE + + vertex_cache_t::VERTEX_CACHE_SIZE - 2) / 2) * 2; + do { + v0 = c->vc.vBuffer + 0; + v1 = c->vc.vBuffer + 1; + v = c->vc.vBuffer + 2; + GLsizei num = count > vcs ? vcs : count; + c->arrays.compileElements(c, v, first, num); + first += num; + count -= num; + if (!c->arrays.cull) { + // quick/trivial reject of the whole batch + do { + v2 = v++; + const uint32_t cc = v0->flags & v1->flags & v2->flags; + if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) + c->prims.renderTriangle(c, v0, v1, v2); + swap(((winding^=1) ? v1 : v0), v2); + num--; + } while (num); + } + if (count) { + v0 = c->vc.vBuffer + 2 + num - 2; + v1 = c->vc.vBuffer + 2 + num - 1; + if ((winding&2) == 0) { + // for strips copy back the two last compiled vertices + c->vc.vBuffer[0] = *v0; + } + c->vc.vBuffer[1] = *v1; + c->arrays.cull = v0->flags & v1->flags & vertex_t::CLIP_ALL; + } + } while (count > 0); +} + +void drawPrimitivesTriangleStrip(ogles_context_t* c, + GLint first, GLsizei count) { + drawPrimitivesTriangleFanOrStrip(c, first, count, 1); +} + +void drawPrimitivesTriangleFan(ogles_context_t* c, + GLint first, GLsizei count) { + drawPrimitivesTriangleFanOrStrip(c, first, count, 2); +} + +void drawPrimitivesTriangles(ogles_context_t* c, GLint first, GLsizei count) +{ + if (ggl_unlikely(count < 3)) + return; + + // vertex cache size must be multiple of 3 + const GLsizei vcs = + ((vertex_cache_t::VERTEX_BUFFER_SIZE + + vertex_cache_t::VERTEX_CACHE_SIZE) / 3) * 3; + do { + vertex_t* v = c->vc.vBuffer; + GLsizei num = count > vcs ? vcs : count; + c->arrays.cull = vertex_t::CLIP_ALL; + c->arrays.compileElements(c, v, first, num); + first += num; + count -= num; + if (!c->arrays.cull) { + // quick/trivial reject of the whole batch + num -= 3; + do { + const uint32_t cc = v[0].flags & v[1].flags & v[2].flags; + if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) + c->prims.renderTriangle(c, v, v+1, v+2); + v += 3; + num -= 3; + } while (num >= 0); + } + } while (count >= 3); +} + +// ---------------------------------------------------------------------------- +#if 0 +#pragma mark - +#endif + +// this looks goofy, but gcc does a great job with this... +static inline unsigned int read_index(int type, const GLvoid*& p) { + unsigned int r; + if (type) { + r = *(const GLubyte*)p; + p = (const GLubyte*)p + 1; + } else { + r = *(const GLushort*)p; + p = (const GLushort*)p + 1; + } + return r; +} + +// ---------------------------------------------------------------------------- + +void drawIndexedPrimitivesPoints(ogles_context_t* c, + GLsizei count, const GLvoid *indices) +{ + if (ggl_unlikely(count < 1)) + return; + const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE); + do { + vertex_t * v = fetch_vertex(c, read_index(type, indices)); + if (ggl_likely(!(v->flags & vertex_t::CLIP_ALL))) + c->prims.renderPoint(c, v); + v->locked = 0; + count--; + } while(count); +} + +// ---------------------------------------------------------------------------- + +void drawIndexedPrimitivesLineStrip(ogles_context_t* c, + GLsizei count, const GLvoid *indices) +{ + if (ggl_unlikely(count < 2)) + return; + + vertex_t * const v = c->vc.vBuffer; + vertex_t* v0 = v; + vertex_t* v1; + + const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE); + c->arrays.compileElement(c, v0, read_index(type, indices)); + count -= 1; + do { + v1 = fetch_vertex(c, read_index(type, indices)); + const uint32_t cc = v0->flags & v1->flags; + if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) + c->prims.renderLine(c, v0, v1); + v0->locked = 0; + v0 = v1; + count--; + } while (count); + v1->locked = 0; +} + +void drawIndexedPrimitivesLineLoop(ogles_context_t* c, + GLsizei count, const GLvoid *indices) +{ + if (ggl_unlikely(count <= 2)) { + drawIndexedPrimitivesLines(c, count, indices); + return; + } + + vertex_t * const v = c->vc.vBuffer; + vertex_t* v0 = v; + vertex_t* v1; + + const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE); + c->arrays.compileElement(c, v0, read_index(type, indices)); + count -= 1; + do { + v1 = fetch_vertex(c, read_index(type, indices)); + const uint32_t cc = v0->flags & v1->flags; + if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) + c->prims.renderLine(c, v0, v1); + v0->locked = 0; + v0 = v1; + count--; + } while (count); + v1->locked = 0; + + v1 = c->vc.vBuffer; + const uint32_t cc = v0->flags & v1->flags; + if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) + c->prims.renderLine(c, v0, v1); +} + +void drawIndexedPrimitivesLines(ogles_context_t* c, + GLsizei count, const GLvoid *indices) +{ + if (ggl_unlikely(count < 2)) + return; + + count -= 2; + const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE); + do { + vertex_t* const v0 = fetch_vertex(c, read_index(type, indices)); + vertex_t* const v1 = fetch_vertex(c, read_index(type, indices)); + const uint32_t cc = v0->flags & v1->flags; + if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) + c->prims.renderLine(c, v0, v1); + v0->locked = 0; + v1->locked = 0; + count -= 2; + } while (count >= 0); +} + +// ---------------------------------------------------------------------------- + +static void drawIndexedPrimitivesTriangleFanOrStrip(ogles_context_t* c, + GLsizei count, const GLvoid *indices, int winding) +{ + // winding == 2 : fan + // winding == 1 : strip + + if (ggl_unlikely(count < 3)) + return; + + vertex_t * const v = c->vc.vBuffer; + vertex_t* v0 = v; + vertex_t* v1 = v+1; + vertex_t* v2; + + const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE); + c->arrays.compileElement(c, v0, read_index(type, indices)); + c->arrays.compileElement(c, v1, read_index(type, indices)); + count -= 2; + + // note: GCC 4.1.1 here makes a prety interesting optimization + // where it duplicates the loop below based on c->arrays.indicesType + + do { + v2 = fetch_vertex(c, read_index(type, indices)); + const uint32_t cc = v0->flags & v1->flags & v2->flags; + if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) + c->prims.renderTriangle(c, v0, v1, v2); + vertex_t* & consumed = ((winding^=1) ? v1 : v0); + consumed->locked = 0; + consumed = v2; + count--; + } while (count); + v0->locked = v1->locked = 0; + v2->locked = 0; +} + +void drawIndexedPrimitivesTriangleStrip(ogles_context_t* c, + GLsizei count, const GLvoid *indices) { + drawIndexedPrimitivesTriangleFanOrStrip(c, count, indices, 1); +} + +void drawIndexedPrimitivesTriangleFan(ogles_context_t* c, + GLsizei count, const GLvoid *indices) { + drawIndexedPrimitivesTriangleFanOrStrip(c, count, indices, 2); +} + +void drawIndexedPrimitivesTriangles(ogles_context_t* c, + GLsizei count, const GLvoid *indices) +{ + if (ggl_unlikely(count < 3)) + return; + + count -= 3; + if (ggl_likely(c->arrays.indicesType == GL_UNSIGNED_SHORT)) { + // This case is probably our most common case... + uint16_t const * p = (uint16_t const *)indices; + do { + vertex_t* const v0 = fetch_vertex(c, *p++); + vertex_t* const v1 = fetch_vertex(c, *p++); + vertex_t* const v2 = fetch_vertex(c, *p++); + const uint32_t cc = v0->flags & v1->flags & v2->flags; + if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) + c->prims.renderTriangle(c, v0, v1, v2); + v0->locked = 0; + v1->locked = 0; + v2->locked = 0; + count -= 3; + } while (count >= 0); + } else { + uint8_t const * p = (uint8_t const *)indices; + do { + vertex_t* const v0 = fetch_vertex(c, *p++); + vertex_t* const v1 = fetch_vertex(c, *p++); + vertex_t* const v2 = fetch_vertex(c, *p++); + const uint32_t cc = v0->flags & v1->flags & v2->flags; + if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) + c->prims.renderTriangle(c, v0, v1, v2); + v0->locked = 0; + v1->locked = 0; + v2->locked = 0; + count -= 3; + } while (count >= 0); + } +} + +// ---------------------------------------------------------------------------- +#if 0 +#pragma mark - +#pragma mark Array compilers +#endif + +void compileElement__generic(ogles_context_t* c, + vertex_t* v, GLint first) +{ + v->flags = 0; + v->index = first; + first &= vertex_cache_t::INDEX_MASK; + const GLubyte* vp = c->arrays.vertex.element(first); + c->arrays.vertex.fetch(c, v->obj.v, vp); + c->arrays.mvp_transform(&c->transforms.mvp, &v->clip, &v->obj); + c->arrays.perspective(c, v); +} + +void compileElements__generic(ogles_context_t* c, + vertex_t* v, GLint first, GLsizei count) +{ + const GLubyte* vp = c->arrays.vertex.element( + first & vertex_cache_t::INDEX_MASK); + const size_t stride = c->arrays.vertex.stride; + transform_t const* const mvp = &c->transforms.mvp; + do { + v->flags = 0; + v->index = first++; + c->arrays.vertex.fetch(c, v->obj.v, vp); + c->arrays.mvp_transform(mvp, &v->clip, &v->obj); + c->arrays.perspective(c, v); + vp += stride; + v++; + } while (--count); +} + +/* +void compileElements__3x_full(ogles_context_t* c, + vertex_t* v, GLint first, GLsizei count) +{ + const GLfixed* vp = (const GLfixed*)c->arrays.vertex.element(first); + const size_t stride = c->arrays.vertex.stride / 4; +// const GLfixed* const& m = c->transforms.mvp.matrix.m; + + GLfixed m[16]; + memcpy(&m, c->transforms.mvp.matrix.m, sizeof(m)); + + do { + const GLfixed rx = vp[0]; + const GLfixed ry = vp[1]; + const GLfixed rz = vp[2]; + vp += stride; + v->index = first++; + v->clip.x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]); + v->clip.y = mla3a(rx, m[ 1], ry, m[ 5], rz, m[ 9], m[13]); + v->clip.z = mla3a(rx, m[ 2], ry, m[ 6], rz, m[10], m[14]); + v->clip.w = mla3a(rx, m[ 3], ry, m[ 7], rz, m[11], m[15]); + + const GLfixed w = v->clip.w; + uint32_t clip = 0; + if (v->clip.x < -w) clip |= vertex_t::CLIP_L; + if (v->clip.x > w) clip |= vertex_t::CLIP_R; + if (v->clip.y < -w) clip |= vertex_t::CLIP_B; + if (v->clip.y > w) clip |= vertex_t::CLIP_T; + if (v->clip.z < -w) clip |= vertex_t::CLIP_N; + if (v->clip.z > w) clip |= vertex_t::CLIP_F; + v->flags = clip; + c->arrays.cull &= clip; + + //c->arrays.perspective(c, v); + v++; + } while (--count); +} +*/ + +// ---------------------------------------------------------------------------- +#if 0 +#pragma mark - +#pragma mark clippers +#endif + +static void clipVec4(vec4_t& nv, + GLfixed t, const vec4_t& s, const vec4_t& p) +{ + for (int i=0; i<4 ; i++) + nv.v[i] = gglMulAddx(t, s.v[i] - p.v[i], p.v[i], 28); +} + +static void clipVertex(ogles_context_t* c, vertex_t* nv, + GLfixed t, const vertex_t* s, const vertex_t* p) +{ + clipVec4(nv->clip, t, s->clip, p->clip); + nv->fog = gglMulAddx(t, s->fog - p->fog, p->fog, 28); + ogles_vertex_project(c, nv); + nv->flags |= vertex_t::LIT | vertex_t::EYE | vertex_t::TT; + nv->flags &= ~vertex_t::CLIP_ALL; +} + +static void clipVertexC(ogles_context_t* c, vertex_t* nv, + GLfixed t, const vertex_t* s, const vertex_t* p) +{ + clipVec4(nv->color, t, s->color, p->color); + clipVertex(c, nv, t, s, p); +} + +static void clipVertexT(ogles_context_t* c, vertex_t* nv, + GLfixed t, const vertex_t* s, const vertex_t* p) +{ + for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) { + if (c->rasterizer.state.texture[i].enable) + clipVec4(nv->texture[i], t, s->texture[i], p->texture[i]); + } + clipVertex(c, nv, t, s, p); +} + +static void clipVertexAll(ogles_context_t* c, vertex_t* nv, + GLfixed t, const vertex_t* s, const vertex_t* p) +{ + clipVec4(nv->color, t, s->color, p->color); + clipVertexT(c, nv, t, s, p); +} + +static void clipEye(ogles_context_t* c, vertex_t* nv, + GLfixed t, const vertex_t* s, const vertex_t* p) +{ + nv->clear(); + c->arrays.clipVertex(c, nv, t, p, s); + clipVec4(nv->eye, t, s->eye, p->eye); +} + +// ---------------------------------------------------------------------------- +#if 0 +#pragma mark - +#endif + +void validate_arrays(ogles_context_t* c, GLenum mode) +{ + uint32_t enables = c->rasterizer.state.enables; + + // Perspective correction is not need if Ortho transform, but + // the user can still provide the w coordinate manually, so we can't + // automatically turn it off (in fact we could when the 4th coordinate + // is not spcified in the vertex array). + // W interpolation is never needed for points. + GLboolean perspective = + c->perspective && mode!=GL_POINTS && (enables & GGL_ENABLE_TMUS); + c->rasterizer.procs.enableDisable(c, GGL_W_LERP, perspective); + + // set anti-aliasing + GLboolean smooth = GL_FALSE; + switch (mode) { + case GL_POINTS: + smooth = c->point.smooth; + break; + case GL_LINES: + case GL_LINE_LOOP: + case GL_LINE_STRIP: + smooth = c->line.smooth; + break; + } + if (((enables & GGL_ENABLE_AA)?1:0) != smooth) + c->rasterizer.procs.enableDisable(c, GGL_AA, smooth); + + // set the shade model for this primitive + c->rasterizer.procs.shadeModel(c, + (mode == GL_POINTS) ? GL_FLAT : c->lighting.shadeModel); + + // compute all the matrices we'll need... + uint32_t want = + transform_state_t::MVP | + transform_state_t::VIEWPORT; + if (c->lighting.enable) { // needs normal transforms and eye coords + want |= transform_state_t::MVUI; + want |= transform_state_t::MODELVIEW; + } + if (enables & GGL_ENABLE_TMUS) { // needs texture transforms + want |= transform_state_t::TEXTURE; + } + if (c->clipPlanes.enable || (enables & GGL_ENABLE_FOG)) { + want |= transform_state_t::MODELVIEW; // needs eye coords + } + ogles_validate_transform(c, want); + + // textures... + if (enables & GGL_ENABLE_TMUS) + ogles_validate_texture(c); + + // vertex compilers + c->arrays.compileElement = compileElement__generic; + c->arrays.compileElements = compileElements__generic; + + // vertex transform + c->arrays.mvp_transform = + c->transforms.mvp.pointv[c->arrays.vertex.size - 2]; + + c->arrays.mv_transform = + c->transforms.modelview.transform.pointv[c->arrays.vertex.size - 2]; + + /* + * *********************************************************************** + * pick fetchers + * *********************************************************************** + */ + + array_machine_t& am = c->arrays; + am.vertex.fetch = fetchNop; + am.normal.fetch = currentNormal; + am.color.fetch = currentColor; + + if (am.vertex.enable) { + am.vertex.resolve(); + if (am.vertex.bo || am.vertex.pointer) { + am.vertex.fetch = vertex_fct[am.vertex.size-2][am.vertex.type & 0xF]; + } + } + + if (am.normal.enable) { + am.normal.resolve(); + if (am.normal.bo || am.normal.pointer) { + am.normal.fetch = normal_fct[am.normal.size-3][am.normal.type & 0xF]; + } + } + + if (am.color.enable) { + am.color.resolve(); + if (c->lighting.enable) { + if (am.color.bo || am.color.pointer) { + am.color.fetch = color_fct[am.color.size-3][am.color.type & 0xF]; + } + } else { + if (am.color.bo || am.color.pointer) { + am.color.fetch = color_clamp_fct[am.color.size-3][am.color.type & 0xF]; + } + } + } + + int activeTmuCount = 0; + for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) { + am.texture[i].fetch = currentTexCoord; + if (c->rasterizer.state.texture[i].enable) { + + // texture fetchers... + if (am.texture[i].enable) { + am.texture[i].resolve(); + if (am.texture[i].bo || am.texture[i].pointer) { + am.texture[i].fetch = texture_fct[am.texture[i].size-2][am.texture[i].type & 0xF]; + } + } + + // texture transform... + const int index = c->arrays.texture[i].size - 2; + c->arrays.tex_transform[i] = + c->transforms.texture[i].transform.pointv[index]; + + am.tmu = i; + activeTmuCount++; + } + } + + // pick the vertex-clipper + uint32_t clipper = 0; + // we must reload 'enables' here + enables = c->rasterizer.state.enables; + if (enables & GGL_ENABLE_SMOOTH) + clipper |= 1; // we need to interpolate colors + if (enables & GGL_ENABLE_TMUS) + clipper |= 2; // we need to interpolate textures + switch (clipper) { + case 0: c->arrays.clipVertex = clipVertex; break; + case 1: c->arrays.clipVertex = clipVertexC; break; + case 2: c->arrays.clipVertex = clipVertexT; break; + case 3: c->arrays.clipVertex = clipVertexAll; break; + } + c->arrays.clipEye = clipEye; + + // pick the primitive rasterizer + ogles_validate_primitives(c); +} + +// ---------------------------------------------------------------------------- +}; // namespace android +// ---------------------------------------------------------------------------- + +using namespace android; + +#if 0 +#pragma mark - +#pragma mark array API +#endif + +void glVertexPointer( + GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ + ogles_context_t* c = ogles_context_t::get(); + if (size<2 || size>4 || stride<0) { + ogles_error(c, GL_INVALID_VALUE); + return; + } + switch (type) { + case GL_BYTE: + case GL_SHORT: + case GL_FIXED: + case GL_FLOAT: + break; + default: + ogles_error(c, GL_INVALID_ENUM); + return; + } + c->arrays.vertex.init(size, type, stride, pointer, c->arrays.array_buffer, 0); +} + +void glColorPointer( + GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ + ogles_context_t* c = ogles_context_t::get(); + // in theory ogles doesn't allow color arrays of size 3 + // but it is very useful to 'visualize' the normal array. + if (size<3 || size>4 || stride<0) { + ogles_error(c, GL_INVALID_VALUE); + return; + } + switch (type) { + case GL_UNSIGNED_BYTE: + case GL_FIXED: + case GL_FLOAT: + break; + default: + ogles_error(c, GL_INVALID_ENUM); + return; + } + c->arrays.color.init(size, type, stride, pointer, c->arrays.array_buffer, 0); +} + +void glNormalPointer( + GLenum type, GLsizei stride, const GLvoid *pointer) +{ + ogles_context_t* c = ogles_context_t::get(); + if (stride<0) { + ogles_error(c, GL_INVALID_VALUE); + return; + } + switch (type) { + case GL_BYTE: + case GL_SHORT: + case GL_FIXED: + case GL_FLOAT: + break; + default: + ogles_error(c, GL_INVALID_ENUM); + return; + } + c->arrays.normal.init(3, type, stride, pointer, c->arrays.array_buffer, 0); +} + +void glTexCoordPointer( + GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ + ogles_context_t* c = ogles_context_t::get(); + if (size<2 || size>4 || stride<0) { + ogles_error(c, GL_INVALID_VALUE); + return; + } + switch (type) { + case GL_BYTE: + case GL_SHORT: + case GL_FIXED: + case GL_FLOAT: + break; + default: + ogles_error(c, GL_INVALID_ENUM); + return; + } + const int tmu = c->arrays.activeTexture; + c->arrays.texture[tmu].init(size, type, stride, pointer, + c->arrays.array_buffer, 0); +} + + +void glEnableClientState(GLenum array) { + ogles_context_t* c = ogles_context_t::get(); + enableDisableClientState(c, array, true); +} + +void glDisableClientState(GLenum array) { + ogles_context_t* c = ogles_context_t::get(); + enableDisableClientState(c, array, false); +} + +void glClientActiveTexture(GLenum texture) +{ + ogles_context_t* c = ogles_context_t::get(); + if (texture<GL_TEXTURE0 || texture>=GL_TEXTURE0+GGL_TEXTURE_UNIT_COUNT) { + ogles_error(c, GL_INVALID_ENUM); + return; + } + c->arrays.activeTexture = texture - GL_TEXTURE0; +} + +void glDrawArrays(GLenum mode, GLint first, GLsizei count) +{ + ogles_context_t* c = ogles_context_t::get(); + if (count<0) { + ogles_error(c, GL_INVALID_VALUE); + return; + } + switch (mode) { + case GL_POINTS: + case GL_LINE_STRIP: + case GL_LINE_LOOP: + case GL_LINES: + case GL_TRIANGLE_STRIP: + case GL_TRIANGLE_FAN: + case GL_TRIANGLES: + break; + default: + ogles_error(c, GL_INVALID_ENUM); + return; + } + + if (count == 0 || !c->arrays.vertex.enable) + return; + if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK)) + return; // all triangles are culled + + validate_arrays(c, mode); + drawArraysPrims[mode](c, first, count); + +#if VC_CACHE_STATISTICS + c->vc.total = count; + c->vc.dump_stats(mode); +#endif +} + +void glDrawElements( + GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) +{ + ogles_context_t* c = ogles_context_t::get(); + if (count<0) { + ogles_error(c, GL_INVALID_VALUE); + return; + } + switch (mode) { + case GL_POINTS: + case GL_LINE_STRIP: + case GL_LINE_LOOP: + case GL_LINES: + case GL_TRIANGLE_STRIP: + case GL_TRIANGLE_FAN: + case GL_TRIANGLES: + break; + default: + ogles_error(c, GL_INVALID_ENUM); + return; + } + switch (type) { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT: + c->arrays.indicesType = type; + break; + default: + ogles_error(c, GL_INVALID_ENUM); + return; + } + if (count == 0 || !c->arrays.vertex.enable) + return; + if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK)) + return; // all triangles are culled + + // clear the vertex-cache + c->vc.clear(); + validate_arrays(c, mode); + + // if indices are in a buffer object, the pointer is treated as an + // offset in that buffer. + if (c->arrays.element_array_buffer) { + indices = c->arrays.element_array_buffer->data + uintptr_t(indices); + } + + drawElementsPrims[mode](c, count, indices); + +#if VC_CACHE_STATISTICS + c->vc.total = count; + c->vc.dump_stats(mode); +#endif +} + +// ---------------------------------------------------------------------------- +// buffers +// ---------------------------------------------------------------------------- + +void glBindBuffer(GLenum target, GLuint buffer) +{ + ogles_context_t* c = ogles_context_t::get(); + if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) { + ogles_error(c, GL_INVALID_ENUM); + return; + } + // create a buffer object, or bind an existing one + buffer_t const* bo = 0; + if (buffer) { + bo = c->bufferObjectManager->bind(buffer); + if (!bo) { + ogles_error(c, GL_OUT_OF_MEMORY); + return; + } + } + ((target == GL_ARRAY_BUFFER) ? + c->arrays.array_buffer : c->arrays.element_array_buffer) = bo; +} + +void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) +{ + ogles_context_t* c = ogles_context_t::get(); + if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) { + ogles_error(c, GL_INVALID_ENUM); + return; + } + if (size<0) { + ogles_error(c, GL_INVALID_VALUE); + return; + } + if ((usage!=GL_STATIC_DRAW) && (usage!=GL_DYNAMIC_DRAW)) { + ogles_error(c, GL_INVALID_ENUM); + return; + } + buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ? + c->arrays.array_buffer : c->arrays.element_array_buffer); + + if (bo == 0) { + // can't modify buffer 0 + ogles_error(c, GL_INVALID_OPERATION); + return; + } + + buffer_t* edit_bo = const_cast<buffer_t*>(bo); + if (c->bufferObjectManager->allocateStore(edit_bo, size, usage) != 0) { + ogles_error(c, GL_OUT_OF_MEMORY); + return; + } + if (data) { + memcpy(bo->data, data, size); + } +} + +void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) +{ + ogles_context_t* c = ogles_context_t::get(); + if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) { + ogles_error(c, GL_INVALID_ENUM); + return; + } + if (offset<0 || size<0 || data==0) { + ogles_error(c, GL_INVALID_VALUE); + return; + } + buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ? + c->arrays.array_buffer : c->arrays.element_array_buffer); + + if (bo == 0) { + // can't modify buffer 0 + ogles_error(c, GL_INVALID_OPERATION); + return; + } + if (offset+size > bo->size) { + ogles_error(c, GL_INVALID_VALUE); + return; + } + memcpy(bo->data + offset, data, size); +} + +void glDeleteBuffers(GLsizei n, const GLuint* buffers) +{ + ogles_context_t* c = ogles_context_t::get(); + if (n<0) { + ogles_error(c, GL_INVALID_VALUE); + return; + } + + for (int i=0 ; i<n ; i++) { + GLuint name = buffers[i]; + if (name) { + // unbind bound deleted buffers... + if (c->arrays.element_array_buffer->name == name) { + c->arrays.element_array_buffer = 0; + } + if (c->arrays.array_buffer->name == name) { + c->arrays.array_buffer = 0; + } + if (c->arrays.vertex.bo->name == name) { + c->arrays.vertex.bo = 0; + } + if (c->arrays.normal.bo->name == name) { + c->arrays.normal.bo = 0; + } + if (c->arrays.color.bo->name == name) { + c->arrays.color.bo = 0; + } + for (int t=0 ; t<GGL_TEXTURE_UNIT_COUNT ; t++) { + if (c->arrays.texture[t].bo->name == name) { + c->arrays.texture[t].bo = 0; + } + } + } + } + c->bufferObjectManager->deleteBuffers(n, buffers); + c->bufferObjectManager->recycleTokens(n, buffers); +} + +void glGenBuffers(GLsizei n, GLuint* buffers) +{ + ogles_context_t* c = ogles_context_t::get(); + if (n<0) { + ogles_error(c, GL_INVALID_VALUE); + return; + } + c->bufferObjectManager->getToken(n, buffers); +} |