summaryrefslogtreecommitdiffstats
path: root/opengl/libagl
diff options
context:
space:
mode:
Diffstat (limited to 'opengl/libagl')
-rw-r--r--opengl/libagl/Android.mk39
-rw-r--r--opengl/libagl/BufferObjectManager.cpp103
-rw-r--r--opengl/libagl/BufferObjectManager.h85
-rw-r--r--opengl/libagl/TextureObjectManager.cpp309
-rw-r--r--opengl/libagl/TextureObjectManager.h140
-rw-r--r--opengl/libagl/TokenManager.cpp62
-rw-r--r--opengl/libagl/TokenManager.h53
-rw-r--r--opengl/libagl/Tokenizer.cpp173
-rw-r--r--opengl/libagl/Tokenizer.h59
-rw-r--r--opengl/libagl/array.cpp1557
-rw-r--r--opengl/libagl/array.h37
-rw-r--r--opengl/libagl/context.h20
-rw-r--r--opengl/libagl/dxt.cpp636
-rw-r--r--opengl/libagl/dxt.h33
-rw-r--r--opengl/libagl/egl.cpp1543
-rw-r--r--opengl/libagl/fixed_asm.S65
-rw-r--r--opengl/libagl/fp.cpp87
-rw-r--r--opengl/libagl/fp.h243
-rw-r--r--opengl/libagl/iterators.S88
-rw-r--r--opengl/libagl/light.cpp852
-rw-r--r--opengl/libagl/light.h38
-rw-r--r--opengl/libagl/matrix.cpp1145
-rw-r--r--opengl/libagl/matrix.h355
-rw-r--r--opengl/libagl/mipmap.cpp192
-rw-r--r--opengl/libagl/primitives.cpp1111
-rw-r--r--opengl/libagl/primitives.h37
-rw-r--r--opengl/libagl/state.cpp586
-rw-r--r--opengl/libagl/state.h54
-rw-r--r--opengl/libagl/texture.cpp1421
-rw-r--r--opengl/libagl/texture.h45
-rw-r--r--opengl/libagl/vertex.cpp247
-rw-r--r--opengl/libagl/vertex.h48
32 files changed, 11463 insertions, 0 deletions
diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk
new file mode 100644
index 0000000..99efe4c
--- /dev/null
+++ b/opengl/libagl/Android.mk
@@ -0,0 +1,39 @@
+LOCAL_PATH:= $(call my-dir)
+
+#
+# Build the software OpenGL ES library
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ egl.cpp \
+ state.cpp \
+ texture.cpp \
+ Tokenizer.cpp \
+ TokenManager.cpp \
+ TextureObjectManager.cpp \
+ BufferObjectManager.cpp \
+ array.cpp.arm \
+ fp.cpp.arm \
+ light.cpp.arm \
+ matrix.cpp.arm \
+ mipmap.cpp.arm \
+ primitives.cpp.arm \
+ vertex.cpp.arm
+
+ifeq ($(TARGET_ARCH),arm)
+ LOCAL_SRC_FILES += fixed_asm.S iterators.S
+ LOCAL_CFLAGS += -fstrict-aliasing
+endif
+
+ifneq ($(TARGET_SIMULATOR),true)
+ # we need to access the private Bionic header <bionic_tls.h>
+ LOCAL_CFLAGS += -I$(LOCAL_PATH)/../../../../bionic/libc/private
+endif
+
+LOCAL_SHARED_LIBRARIES := libcutils libutils libpixelflinger
+LOCAL_LDLIBS := -lpthread -ldl
+LOCAL_MODULE:= libagl
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/libagl/BufferObjectManager.cpp b/opengl/libagl/BufferObjectManager.cpp
new file mode 100644
index 0000000..6bf28ee
--- /dev/null
+++ b/opengl/libagl/BufferObjectManager.cpp
@@ -0,0 +1,103 @@
+/*
+ ** Copyright 2008, 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 <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <utils/Atomic.h>
+#include <utils/RefBase.h>
+#include <utils/KeyedVector.h>
+#include <utils/Errors.h>
+
+#include <GLES/gl.h>
+
+#include "BufferObjectManager.h"
+
+
+namespace android {
+
+using namespace gl;
+
+// ----------------------------------------------------------------------------
+
+EGLBufferObjectManager::EGLBufferObjectManager()
+: TokenManager(), mCount(0)
+{
+}
+
+EGLBufferObjectManager::~EGLBufferObjectManager()
+{
+ // destroy all the buffer objects and their storage
+ GLsizei n = mBuffers.size();
+ for (GLsizei i=0 ; i<n ; i++) {
+ buffer_t* bo = mBuffers.valueAt(i);
+ free(bo->data);
+ delete bo;
+ }
+}
+
+buffer_t const* EGLBufferObjectManager::bind(GLuint buffer)
+{
+ Mutex::Autolock _l(mLock);
+ int32_t i = mBuffers.indexOfKey(buffer);
+ if (i >= 0) {
+ return mBuffers.valueAt(i);
+ }
+ buffer_t* bo = new buffer_t;
+ bo->data = 0;
+ bo->usage = GL_STATIC_DRAW;
+ bo->size = 0;
+ bo->name = buffer;
+ mBuffers.add(buffer, bo);
+ return bo;
+}
+
+int EGLBufferObjectManager::allocateStore(buffer_t* bo,
+ GLsizeiptr size, GLenum usage)
+{
+ Mutex::Autolock _l(mLock);
+ if (size != bo->size) {
+ uint8_t* data = (uint8_t*)malloc(size);
+ if (data == 0)
+ return -1;
+ free(bo->data);
+ bo->data = data;
+ bo->size = size;
+ }
+ bo->usage = usage;
+ return 0;
+}
+
+void EGLBufferObjectManager::deleteBuffers(GLsizei n, const GLuint* buffers)
+{
+ Mutex::Autolock _l(mLock);
+ while (n--) {
+ const GLuint t = *buffers++;
+ if (t) {
+ int32_t index = mBuffers.indexOfKey(t);
+ if (index >= 0) {
+ buffer_t* bo = mBuffers.valueAt(index);
+ free(bo->data);
+ mBuffers.removeItemsAt(index);
+ delete bo;
+ }
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
diff --git a/opengl/libagl/BufferObjectManager.h b/opengl/libagl/BufferObjectManager.h
new file mode 100644
index 0000000..9e9340a
--- /dev/null
+++ b/opengl/libagl/BufferObjectManager.h
@@ -0,0 +1,85 @@
+/*
+ **
+ ** 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.
+ */
+
+#ifndef ANDROID_OPENGLES_BUFFER_OBJECT_MANAGER_H
+#define ANDROID_OPENGLES_BUFFER_OBJECT_MANAGER_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <utils/Atomic.h>
+#include <utils/RefBase.h>
+#include <utils/KeyedVector.h>
+#include <utils/Errors.h>
+
+#include <GLES/gl.h>
+
+#include "Tokenizer.h"
+#include "TokenManager.h"
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+namespace gl {
+
+struct buffer_t {
+ GLsizeiptr size;
+ GLenum usage;
+ uint8_t* data;
+ uint32_t name;
+};
+
+};
+
+class EGLBufferObjectManager : public TokenManager
+{
+public:
+ EGLBufferObjectManager();
+ ~EGLBufferObjectManager();
+
+ // protocol for sp<>
+ inline void incStrong(const void* id) const;
+ inline void decStrong(const void* id) const;
+ typedef void weakref_type;
+
+ gl::buffer_t const* bind(GLuint buffer);
+ int allocateStore(gl::buffer_t* bo, GLsizeiptr size, GLenum usage);
+ void deleteBuffers(GLsizei n, const GLuint* buffers);
+
+private:
+ mutable volatile int32_t mCount;
+ mutable Mutex mLock;
+ KeyedVector<GLuint, gl::buffer_t*> mBuffers;
+};
+
+void EGLBufferObjectManager::incStrong(const void* id) const {
+ android_atomic_inc(&mCount);
+}
+void EGLBufferObjectManager::decStrong(const void* id) const {
+ if (android_atomic_dec(&mCount) == 1) {
+ delete this;
+ }
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_BUFFER_OBJECT_MANAGER_H
+
diff --git a/opengl/libagl/TextureObjectManager.cpp b/opengl/libagl/TextureObjectManager.cpp
new file mode 100644
index 0000000..ce31854
--- /dev/null
+++ b/opengl/libagl/TextureObjectManager.cpp
@@ -0,0 +1,309 @@
+/*
+ ** 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 <stdio.h>
+#include <stdlib.h>
+#include "context.h"
+#include "TextureObjectManager.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+EGLTextureObject::EGLTextureObject()
+ : mCount(0), mSize(0)
+{
+ init();
+}
+
+EGLTextureObject::~EGLTextureObject()
+{
+ if (!direct) {
+ if (mSize && surface.data)
+ free(surface.data);
+ if (mMipmaps)
+ freeMipmaps();
+ }
+}
+
+void EGLTextureObject::init()
+{
+ memset(&surface, 0, sizeof(surface));
+ surface.version = sizeof(surface);
+ mMipmaps = 0;
+ mNumExtraLod = 0;
+ mIsComplete = false;
+ wraps = GL_REPEAT;
+ wrapt = GL_REPEAT;
+ min_filter = GL_LINEAR;
+ mag_filter = GL_LINEAR;
+ internalformat = 0;
+ memset(crop_rect, 0, sizeof(crop_rect));
+ generate_mipmap = GL_FALSE;
+ direct = GL_FALSE;
+}
+
+void EGLTextureObject::copyParameters(const sp<EGLTextureObject>& old)
+{
+ wraps = old->wraps;
+ wrapt = old->wrapt;
+ min_filter = old->min_filter;
+ mag_filter = old->mag_filter;
+ memcpy(crop_rect, old->crop_rect, sizeof(crop_rect));
+ generate_mipmap = old->generate_mipmap;
+ direct = old->direct;
+}
+
+status_t EGLTextureObject::allocateMipmaps()
+{
+ // here, by construction, mMipmaps=0 && mNumExtraLod=0
+
+ if (!surface.data)
+ return NO_INIT;
+
+ int w = surface.width;
+ int h = surface.height;
+ const int numLods = 31 - gglClz(max(w,h));
+ if (numLods <= 0)
+ return NO_ERROR;
+
+ mMipmaps = (GGLSurface*)malloc(numLods * sizeof(GGLSurface));
+ if (!mMipmaps)
+ return NO_MEMORY;
+
+ memset(mMipmaps, 0, numLods * sizeof(GGLSurface));
+ mNumExtraLod = numLods;
+ return NO_ERROR;
+}
+
+void EGLTextureObject::freeMipmaps()
+{
+ if (mMipmaps) {
+ for (int i=0 ; i<mNumExtraLod ; i++) {
+ if (mMipmaps[i].data) {
+ free(mMipmaps[i].data);
+ }
+ }
+ free(mMipmaps);
+ mMipmaps = 0;
+ mNumExtraLod = 0;
+ }
+}
+
+const GGLSurface& EGLTextureObject::mip(int lod) const
+{
+ if (lod<=0 || !mMipmaps)
+ return surface;
+ lod = min(lod-1, mNumExtraLod-1);
+ return mMipmaps[lod];
+}
+
+GGLSurface& EGLTextureObject::editMip(int lod)
+{
+ return const_cast<GGLSurface&>(mip(lod));
+}
+
+status_t EGLTextureObject::setSurface(GGLSurface const* s)
+{
+ // XXX: glFlush() on 's'
+ if (mSize && surface.data) {
+ free(surface.data);
+ }
+ surface = *s;
+ internalformat = 0;
+
+ // we should keep the crop_rect, but it's delicate because
+ // the new size of the surface could make it invalid.
+ // so for now, we just loose it.
+ memset(crop_rect, 0, sizeof(crop_rect));
+
+ // it would be nice if we could keep the generate_mipmap flag,
+ // we would have to generate them right now though.
+ generate_mipmap = GL_FALSE;
+
+ direct = GL_TRUE;
+ mSize = 0; // we don't own this surface
+ if (mMipmaps)
+ freeMipmaps();
+ mIsComplete = true;
+ return NO_ERROR;
+}
+
+status_t EGLTextureObject::reallocate(
+ GLint level, int w, int h, int s,
+ int format, int compressedFormat, int bpr)
+{
+ const size_t size = h * bpr;
+ if (level == 0)
+ {
+ if (size!=mSize || !surface.data) {
+ if (mSize && surface.data) {
+ free(surface.data);
+ }
+ surface.data = (GGLubyte*)malloc(size);
+ if (!surface.data) {
+ mSize = 0;
+ mIsComplete = false;
+ return NO_MEMORY;
+ }
+ mSize = size;
+ }
+ surface.version = sizeof(GGLSurface);
+ surface.width = w;
+ surface.height = h;
+ surface.stride = s;
+ surface.format = format;
+ surface.compressedFormat = compressedFormat;
+ if (mMipmaps)
+ freeMipmaps();
+ mIsComplete = true;
+ }
+ else
+ {
+ if (!mMipmaps) {
+ if (allocateMipmaps() != NO_ERROR)
+ return NO_MEMORY;
+ }
+
+ LOGW_IF(level-1 >= mNumExtraLod,
+ "specifying mipmap level %d, but # of level is %d",
+ level, mNumExtraLod+1);
+
+ GGLSurface& mipmap = editMip(level);
+ if (mipmap.data)
+ free(mipmap.data);
+
+ mipmap.data = (GGLubyte*)malloc(size);
+ if (!mipmap.data) {
+ memset(&mipmap, 0, sizeof(GGLSurface));
+ mIsComplete = false;
+ return NO_MEMORY;
+ }
+
+ mipmap.version = sizeof(GGLSurface);
+ mipmap.width = w;
+ mipmap.height = h;
+ mipmap.stride = s;
+ mipmap.format = format;
+ mipmap.compressedFormat = compressedFormat;
+
+ // check if the texture is complete
+ mIsComplete = true;
+ const GGLSurface* prev = &surface;
+ for (int i=0 ; i<mNumExtraLod ; i++) {
+ const GGLSurface* curr = mMipmaps + i;
+ if (curr->format != surface.format) {
+ mIsComplete = false;
+ break;
+ }
+
+ uint32_t w = (prev->width >> 1) ? : 1;
+ uint32_t h = (prev->height >> 1) ? : 1;
+ if (w != curr->width || h != curr->height) {
+ mIsComplete = false;
+ break;
+ }
+ prev = curr;
+ }
+ }
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+EGLSurfaceManager::EGLSurfaceManager()
+ : TokenManager(), mCount(0)
+{
+}
+
+EGLSurfaceManager::~EGLSurfaceManager()
+{
+ // everything gets freed automatically here...
+}
+
+sp<EGLTextureObject> EGLSurfaceManager::createTexture(GLuint name)
+{
+ sp<EGLTextureObject> result;
+
+ Mutex::Autolock _l(mLock);
+ if (mTextures.indexOfKey(name) >= 0)
+ return result; // already exists!
+
+ result = new EGLTextureObject();
+
+ status_t err = mTextures.add(name, result);
+ if (err < 0)
+ result.clear();
+
+ return result;
+}
+
+sp<EGLTextureObject> EGLSurfaceManager::removeTexture(GLuint name)
+{
+ Mutex::Autolock _l(mLock);
+ const ssize_t index = mTextures.indexOfKey(name);
+ if (index >= 0) {
+ sp<EGLTextureObject> result(mTextures.valueAt(index));
+ mTextures.removeItemsAt(index);
+ return result;
+ }
+ return 0;
+}
+
+sp<EGLTextureObject> EGLSurfaceManager::replaceTexture(GLuint name)
+{
+ sp<EGLTextureObject> tex;
+ Mutex::Autolock _l(mLock);
+ const ssize_t index = mTextures.indexOfKey(name);
+ if (index >= 0) {
+ const sp<EGLTextureObject>& old = mTextures.valueAt(index);
+ const uint32_t refs = old->getStrongCount();
+ if (ggl_likely(refs == 1)) {
+ // we're the only owner
+ tex = old;
+ } else {
+ // keep the texture's parameters
+ tex = new EGLTextureObject();
+ tex->copyParameters(old);
+ mTextures.removeItemsAt(index);
+ mTextures.add(name, tex);
+ }
+ }
+ return tex;
+}
+
+void EGLSurfaceManager::deleteTextures(GLsizei n, const GLuint *tokens)
+{
+ // free all textures
+ Mutex::Autolock _l(mLock);
+ for (GLsizei i=0 ; i<n ; i++) {
+ const GLuint t(*tokens++);
+ if (t) {
+ mTextures.removeItem(t);
+ }
+ }
+}
+
+sp<EGLTextureObject> EGLSurfaceManager::texture(GLuint name)
+{
+ Mutex::Autolock _l(mLock);
+ const ssize_t index = mTextures.indexOfKey(name);
+ if (index >= 0)
+ return mTextures.valueAt(index);
+ return 0;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
diff --git a/opengl/libagl/TextureObjectManager.h b/opengl/libagl/TextureObjectManager.h
new file mode 100644
index 0000000..74ed1a4
--- /dev/null
+++ b/opengl/libagl/TextureObjectManager.h
@@ -0,0 +1,140 @@
+/*
+** 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.
+*/
+
+#ifndef ANDROID_OPENGLES_SURFACE_H
+#define ANDROID_OPENGLES_SURFACE_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <utils/Atomic.h>
+#include <utils/threads.h>
+#include <utils/RefBase.h>
+#include <utils/KeyedVector.h>
+#include <utils/Errors.h>
+
+#include <private/pixelflinger/ggl_context.h>
+
+#include <GLES/gl.h>
+
+#include "Tokenizer.h"
+#include "TokenManager.h"
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class EGLTextureObject
+{
+public:
+ EGLTextureObject();
+ ~EGLTextureObject();
+
+ // protocol for sp<>
+ inline void incStrong(const void* id) const;
+ inline void decStrong(const void* id) const;
+ inline uint32_t getStrongCount() const;
+
+ status_t setSurface(GGLSurface const* s);
+ status_t reallocate(GLint level,
+ int w, int h, int s,
+ int format, int compressedFormat, int bpr);
+ inline size_t size() const;
+ const GGLSurface& mip(int lod) const;
+ GGLSurface& editMip(int lod);
+ bool hasMipmaps() const { return mMipmaps!=0; }
+ bool isComplete() const { return mIsComplete; }
+ void copyParameters(const sp<EGLTextureObject>& old);
+
+private:
+ status_t allocateMipmaps();
+ void freeMipmaps();
+ void init();
+ mutable int32_t mCount;
+ size_t mSize;
+ GGLSurface *mMipmaps;
+ int mNumExtraLod;
+ bool mIsComplete;
+
+public:
+ GGLSurface surface;
+ GLenum wraps;
+ GLenum wrapt;
+ GLenum min_filter;
+ GLenum mag_filter;
+ GLenum internalformat;
+ GLint crop_rect[4];
+ GLint generate_mipmap;
+ GLint direct;
+};
+
+void EGLTextureObject::incStrong(const void* id) const {
+ android_atomic_inc(&mCount);
+}
+void EGLTextureObject::decStrong(const void* id) const {
+ if (android_atomic_dec(&mCount) == 1) {
+ delete this;
+ }
+}
+uint32_t EGLTextureObject::getStrongCount() const {
+ return mCount;
+}
+size_t EGLTextureObject::size() const {
+ return mSize;
+}
+
+// ----------------------------------------------------------------------------
+
+class EGLSurfaceManager : public TokenManager
+{
+public:
+ EGLSurfaceManager();
+ ~EGLSurfaceManager();
+
+ // protocol for sp<>
+ inline void incStrong(const void* id) const;
+ inline void decStrong(const void* id) const;
+ typedef void weakref_type;
+
+ sp<EGLTextureObject> createTexture(GLuint name);
+ sp<EGLTextureObject> removeTexture(GLuint name);
+ sp<EGLTextureObject> replaceTexture(GLuint name);
+ void deleteTextures(GLsizei n, const GLuint *tokens);
+ sp<EGLTextureObject> texture(GLuint name);
+
+private:
+ mutable int32_t mCount;
+ mutable Mutex mLock;
+ KeyedVector< GLuint, sp<EGLTextureObject> > mTextures;
+};
+
+void EGLSurfaceManager::incStrong(const void* id) const {
+ android_atomic_inc(&mCount);
+}
+void EGLSurfaceManager::decStrong(const void* id) const {
+ if (android_atomic_dec(&mCount) == 1) {
+ delete this;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_SURFACE_H
+
diff --git a/opengl/libagl/TokenManager.cpp b/opengl/libagl/TokenManager.cpp
new file mode 100644
index 0000000..eea6025
--- /dev/null
+++ b/opengl/libagl/TokenManager.cpp
@@ -0,0 +1,62 @@
+/* libs/opengles/surface.cpp
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+#include "TokenManager.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+TokenManager::TokenManager()
+{
+ // token 0 is always reserved
+ mTokenizer.reserve(0);
+}
+
+TokenManager::~TokenManager()
+{
+}
+
+status_t TokenManager::getToken(GLsizei n, GLuint *tokens)
+{
+ Mutex::Autolock _l(mLock);
+ for (GLsizei i=0 ; i<n ; i++)
+ *tokens++ = mTokenizer.acquire();
+ return NO_ERROR;
+}
+
+void TokenManager::recycleTokens(GLsizei n, const GLuint *tokens)
+{
+ Mutex::Autolock _l(mLock);
+ for (int i=0 ; i<n ; i++) {
+ const GLuint token = *tokens++;
+ if (token) {
+ mTokenizer.release(token);
+ }
+ }
+}
+
+bool TokenManager::isTokenValid(GLuint token) const
+{
+ Mutex::Autolock _l(mLock);
+ return mTokenizer.isAcquired(token);
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/opengl/libagl/TokenManager.h b/opengl/libagl/TokenManager.h
new file mode 100644
index 0000000..49c1469
--- /dev/null
+++ b/opengl/libagl/TokenManager.h
@@ -0,0 +1,53 @@
+/*
+** 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.
+*/
+
+#ifndef ANDROID_OPENGLES_TOKEN_MANAGER_H
+#define ANDROID_OPENGLES_TOKEN_MANAGER_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+
+#include <GLES/gl.h>
+
+#include "Tokenizer.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class TokenManager
+{
+public:
+ TokenManager();
+ ~TokenManager();
+
+ status_t getToken(GLsizei n, GLuint *tokens);
+ void recycleTokens(GLsizei n, const GLuint *tokens);
+ bool isTokenValid(GLuint token) const;
+
+private:
+ mutable Mutex mLock;
+ Tokenizer mTokenizer;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_TOKEN_MANAGER_H
+
diff --git a/opengl/libagl/Tokenizer.cpp b/opengl/libagl/Tokenizer.cpp
new file mode 100644
index 0000000..9b3ea1a
--- /dev/null
+++ b/opengl/libagl/Tokenizer.cpp
@@ -0,0 +1,173 @@
+/* libs/opengles/Tokenizer.cpp
+**
+** 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 <stdio.h>
+
+#include "Tokenizer.h"
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+ANDROID_BASIC_TYPES_TRAITS(Tokenizer::run_t)
+
+Tokenizer::Tokenizer()
+{
+}
+
+Tokenizer::Tokenizer(const Tokenizer& other)
+ : mRanges(other.mRanges)
+{
+}
+
+Tokenizer::~Tokenizer()
+{
+}
+
+uint32_t Tokenizer::acquire()
+{
+ if (!mRanges.size() || mRanges[0].first) {
+ _insertTokenAt(0,0);
+ return 0;
+ }
+
+ // just extend the first run
+ const run_t& run = mRanges[0];
+ uint32_t token = run.first + run.length;
+ _insertTokenAt(token, 1);
+ return token;
+}
+
+bool Tokenizer::isAcquired(uint32_t token) const
+{
+ return (_indexOrderOf(token) >= 0);
+}
+
+status_t Tokenizer::reserve(uint32_t token)
+{
+ size_t o;
+ const ssize_t i = _indexOrderOf(token, &o);
+ if (i >= 0) {
+ return BAD_VALUE; // this token is already taken
+ }
+ ssize_t err = _insertTokenAt(token, o);
+ return (err<0) ? err : status_t(NO_ERROR);
+}
+
+status_t Tokenizer::release(uint32_t token)
+{
+ const ssize_t i = _indexOrderOf(token);
+ if (i >= 0) {
+ const run_t& run = mRanges[i];
+ if ((token >= run.first) && (token < run.first+run.length)) {
+ // token in this range, we need to split
+ run_t& run = mRanges.editItemAt(i);
+ if ((token == run.first) || (token == run.first+run.length-1)) {
+ if (token == run.first) {
+ run.first += 1;
+ }
+ run.length -= 1;
+ if (run.length == 0) {
+ // XXX: should we systematically remove a run that's empty?
+ mRanges.removeItemsAt(i);
+ }
+ } else {
+ // split the run
+ run_t new_run;
+ new_run.first = token+1;
+ new_run.length = run.first+run.length - new_run.first;
+ run.length = token - run.first;
+ mRanges.insertAt(new_run, i+1);
+ }
+ return NO_ERROR;
+ }
+ }
+ return NAME_NOT_FOUND;
+}
+
+ssize_t Tokenizer::_indexOrderOf(uint32_t token, size_t* order) const
+{
+ // binary search
+ ssize_t err = NAME_NOT_FOUND;
+ ssize_t l = 0;
+ ssize_t h = mRanges.size()-1;
+ ssize_t mid;
+ const run_t* a = mRanges.array();
+ while (l <= h) {
+ mid = l + (h - l)/2;
+ const run_t* const curr = a + mid;
+ int c = 0;
+ if (token < curr->first) c = 1;
+ else if (token >= curr->first+curr->length) c = -1;
+ if (c == 0) {
+ err = l = mid;
+ break;
+ } else if (c < 0) {
+ l = mid + 1;
+ } else {
+ h = mid - 1;
+ }
+ }
+ if (order) *order = l;
+ return err;
+}
+
+ssize_t Tokenizer::_insertTokenAt(uint32_t token, size_t index)
+{
+ const size_t c = mRanges.size();
+
+ if (index >= 1) {
+ // do we need to merge with the previous run?
+ run_t& p = mRanges.editItemAt(index-1);
+ if (p.first+p.length == token) {
+ p.length += 1;
+ if (index < c) {
+ const run_t& n = mRanges[index];
+ if (token+1 == n.first) {
+ p.length += n.length;
+ mRanges.removeItemsAt(index);
+ }
+ }
+ return index;
+ }
+ }
+
+ if (index < c) {
+ // do we need to merge with the next run?
+ run_t& n = mRanges.editItemAt(index);
+ if (token+1 == n.first) {
+ n.first -= 1;
+ n.length += 1;
+ return index;
+ }
+ }
+
+ return mRanges.insertAt(run_t(token,1), index);
+}
+
+void Tokenizer::dump() const
+{
+ const run_t* ranges = mRanges.array();
+ const size_t c = mRanges.size();
+ LOGD("Tokenizer (%p, size = %u)\n", this, c);
+ for (size_t i=0 ; i<c ; i++) {
+ LOGD("%u: (%u, %u)\n", i, ranges[i].first, ranges[i].length);
+ }
+}
+
+}; // namespace android
+
diff --git a/opengl/libagl/Tokenizer.h b/opengl/libagl/Tokenizer.h
new file mode 100644
index 0000000..ac555cb
--- /dev/null
+++ b/opengl/libagl/Tokenizer.h
@@ -0,0 +1,59 @@
+/* libs/opengles/Tokenizer.h
+**
+** 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.
+*/
+
+
+#ifndef ANDROID_OPENGLES_TOKENIZER_H
+#define ANDROID_OPENGLES_TOKENIZER_H
+
+#include <utils/Vector.h>
+#include <utils/Errors.h>
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+class Tokenizer
+{
+public:
+ Tokenizer();
+ Tokenizer(const Tokenizer& other);
+ ~Tokenizer();
+
+ uint32_t acquire();
+ status_t reserve(uint32_t token);
+ status_t release(uint32_t token);
+ bool isAcquired(uint32_t token) const;
+
+ void dump() const;
+
+ struct run_t {
+ run_t() {};
+ run_t(uint32_t f, uint32_t l) : first(f), length(l) {}
+ uint32_t first;
+ uint32_t length;
+ };
+private:
+ ssize_t _indexOrderOf(uint32_t token, size_t* order=0) const;
+ ssize_t _insertTokenAt(uint32_t token, size_t index);
+ Vector<run_t> mRanges;
+};
+
+}; // namespace android
+
+// ----------------------------------------------------------------------------
+
+#endif // ANDROID_OPENGLES_TOKENIZER_H
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);
+}
diff --git a/opengl/libagl/array.h b/opengl/libagl/array.h
new file mode 100644
index 0000000..e156978
--- /dev/null
+++ b/opengl/libagl/array.h
@@ -0,0 +1,37 @@
+/* libs/opengles/array.h
+**
+** 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.
+*/
+
+#ifndef ANDROID_OPENGLES_ARRAY_H
+#define ANDROID_OPENGLES_ARRAY_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+namespace android {
+
+namespace gl {
+struct ogles_context_t;
+};
+
+void ogles_init_array(ogles_context_t* c);
+void ogles_uninit_array(ogles_context_t* c);
+
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_ARRAY_H
+
diff --git a/opengl/libagl/context.h b/opengl/libagl/context.h
new file mode 100644
index 0000000..ef36b56
--- /dev/null
+++ b/opengl/libagl/context.h
@@ -0,0 +1,20 @@
+/* libs/opengles/context.h
+**
+** 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 <private/opengles/gl_context.h>
+
+using namespace android::gl;
diff --git a/opengl/libagl/dxt.cpp b/opengl/libagl/dxt.cpp
new file mode 100644
index 0000000..238c81f
--- /dev/null
+++ b/opengl/libagl/dxt.cpp
@@ -0,0 +1,636 @@
+/* libs/opengles/dxt.cpp
+**
+** Copyright 2007, 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.
+*/
+
+#define TIMING 0
+
+#if TIMING
+#include <sys/time.h> // for optimization timing
+#include <stdio.h>
+#include <stdlib.h>
+#endif
+
+#include <GLES/gl.h>
+#include <utils/Endian.h>
+
+#include "context.h"
+
+#define TIMING 0
+
+namespace android {
+
+static uint8_t avg23tab[64*64];
+static volatile int tables_initialized = 0;
+
+// Definitions below are equivalent to these over the valid range of arguments
+// #define div5(x) ((x)/5)
+// #define div7(x) ((x)/7)
+
+// Use fixed-point to divide by 5 and 7
+// 3277 = 2^14/5 + 1
+// 2341 = 2^14/7 + 1
+#define div5(x) (((x)*3277) >> 14)
+#define div7(x) (((x)*2341) >> 14)
+
+// Table with entry [a << 6 | b] = (2*a + b)/3 for 0 <= a,b < 64
+#define avg23(x0,x1) avg23tab[((x0) << 6) | (x1)]
+
+// Extract 5/6/5 RGB
+#define red(x) (((x) >> 11) & 0x1f)
+#define green(x) (((x) >> 5) & 0x3f)
+#define blue(x) ( (x) & 0x1f)
+
+/*
+ * Convert 5/6/5 RGB (as 3 ints) to 8/8/8
+ *
+ * Operation count: 8 <<, 0 &, 5 |
+ */
+inline static int rgb565SepTo888(int r, int g, int b)
+
+{
+ return ((((r << 3) | (r >> 2)) << 16) |
+ (((g << 2) | (g >> 4)) << 8) |
+ ((b << 3) | (b >> 2)));
+}
+
+/*
+ * Convert 5/6/5 RGB (as a single 16-bit word) to 8/8/8
+ *
+ * r4r3r2r1 r0g5g4g3 g2g1g0b4 b3b2b1b0 rgb
+ * r4r3r2 r1r0g5g4 g3g2g1g0 b4b3b2b1 b0 0 0 0 rgb << 3
+ * r4r3r2r1 r0r4r3r2 g5g4g3g2 g1g0g5g4 b4b3b2b1 b0b4b3b2 desired result
+ *
+ * Construct the 24-bit RGB word as:
+ *
+ * r4r3r2r1 r0------ -------- -------- -------- -------- (rgb << 8) & 0xf80000
+ * r4r3r2 -------- -------- -------- -------- (rgb << 3) & 0x070000
+ * g5g4g3g2 g1g0---- -------- -------- (rgb << 5) & 0x00fc00
+ * g5g4 -------- -------- (rgb >> 1) & 0x000300
+ * b4b3b2b1 b0------ (rgb << 3) & 0x0000f8
+ * b4b3b2 (rgb >> 2) & 0x000007
+ *
+ * Operation count: 5 <<, 6 &, 5 | (n.b. rgb >> 3 is used twice)
+ */
+inline static int rgb565To888(int rgb)
+
+{
+ int rgb3 = rgb >> 3;
+ return (((rgb << 8) & 0xf80000) |
+ ( rgb3 & 0x070000) |
+ ((rgb << 5) & 0x00fc00) |
+ ((rgb >> 1) & 0x000300) |
+ ( rgb3 & 0x0000f8) |
+ ((rgb >> 2) & 0x000007));
+}
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+static uint32_t swap(uint32_t x) {
+ int b0 = (x >> 24) & 0xff;
+ int b1 = (x >> 16) & 0xff;
+ int b2 = (x >> 8) & 0xff;
+ int b3 = (x ) & 0xff;
+
+ return (uint32_t)((b3 << 24) | (b2 << 16) | (b1 << 8) | b0);
+}
+#endif
+
+static void
+init_tables()
+{
+ if (tables_initialized) {
+ return;
+ }
+
+ for (int i = 0; i < 64; i++) {
+ for (int j = 0; j < 64; j++) {
+ int avg = (2*i + j)/3;
+ avg23tab[(i << 6) | j] = avg;
+ }
+ }
+
+ asm volatile ("" : : : "memory");
+ tables_initialized = 1;
+}
+
+/*
+ * Utility to scan a DXT1 compressed texture to determine whether it
+ * contains a transparent pixel (color0 < color1, code == 3). This
+ * may be useful if the application lacks information as to whether
+ * the true format is GL_COMPRESSED_RGB_S3TC_DXT1_EXT or
+ * GL_COMPRESSED_RGBA_S3TC_DXT1_EXT.
+ */
+bool
+DXT1HasAlpha(const GLvoid *data, int width, int height) {
+#if TIMING
+ struct timeval start_t, end_t;
+ struct timezone tz;
+
+ gettimeofday(&start_t, &tz);
+#endif
+
+ bool hasAlpha = false;
+
+ int xblocks = (width + 3)/4;
+ int yblocks = (height + 3)/4;
+ int numblocks = xblocks*yblocks;
+
+ uint32_t const *d32 = (uint32_t *)data;
+ for (int b = 0; b < numblocks; b++) {
+ uint32_t colors = *d32++;
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+ colors = swap(colors);
+#endif
+
+ uint16_t color0 = colors & 0xffff;
+ uint16_t color1 = colors >> 16;
+
+ if (color0 < color1) {
+ // There's no need to endian-swap within 'bits'
+ // since we don't care which pixel is the transparent one
+ uint32_t bits = *d32++;
+
+ // Detect if any (odd, even) pair of bits are '11'
+ // bits: b31 b30 b29 ... b3 b2 b1 b0
+ // bits >> 1: b31 b31 b30 ... b4 b3 b2 b1
+ // &: b31 (b31 & b30) (b29 & b28) ... (b2 & b1) (b1 & b0)
+ // & 0x55..: 0 (b31 & b30) 0 ... 0 (b1 & b0)
+ if (((bits & (bits >> 1)) & 0x55555555) != 0) {
+ hasAlpha = true;
+ goto done;
+ }
+ } else {
+ // Skip 4 bytes
+ ++d32;
+ }
+ }
+
+ done:
+#if TIMING
+ gettimeofday(&end_t, &tz);
+ long usec = (end_t.tv_sec - start_t.tv_sec)*1000000 +
+ (end_t.tv_usec - start_t.tv_usec);
+
+ printf("Scanned w=%d h=%d in %ld usec\n", width, height, usec);
+#endif
+
+ return hasAlpha;
+}
+
+static void
+decodeDXT1(const GLvoid *data, int width, int height,
+ void *surface, int stride,
+ bool hasAlpha)
+
+{
+ init_tables();
+
+ uint32_t const *d32 = (uint32_t *)data;
+
+ // Color table for the current block
+ uint16_t c[4];
+ c[0] = c[1] = c[2] = c[3] = 0;
+
+ // Specified colors from the previous block
+ uint16_t prev_color0 = 0x0000;
+ uint16_t prev_color1 = 0x0000;
+
+ uint16_t* rowPtr = (uint16_t*)surface;
+ for (int base_y = 0; base_y < height; base_y += 4, rowPtr += 4*stride) {
+ uint16_t *blockPtr = rowPtr;
+ for (int base_x = 0; base_x < width; base_x += 4, blockPtr += 4) {
+ uint32_t colors = *d32++;
+ uint32_t bits = *d32++;
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+ colors = swap(colors);
+ bits = swap(bits);
+#endif
+
+ // Raw colors
+ uint16_t color0 = colors & 0xffff;
+ uint16_t color1 = colors >> 16;
+
+ // If the new block has the same base colors as the
+ // previous one, we don't need to recompute the color
+ // table c[]
+ if (color0 != prev_color0 || color1 != prev_color1) {
+ // Store raw colors for comparison with next block
+ prev_color0 = color0;
+ prev_color1 = color1;
+
+ int r0 = red(color0);
+ int g0 = green(color0);
+ int b0 = blue(color0);
+
+ int r1 = red(color1);
+ int g1 = green(color1);
+ int b1 = blue(color1);
+
+ if (hasAlpha) {
+ c[0] = (r0 << 11) | ((g0 >> 1) << 6) | (b0 << 1) | 0x1;
+ c[1] = (r1 << 11) | ((g1 >> 1) << 6) | (b1 << 1) | 0x1;
+ } else {
+ c[0] = color0;
+ c[1] = color1;
+ }
+
+ int r2, g2, b2, r3, g3, b3, a3;
+
+ int bbits = bits >> 1;
+ bool has2 = ((bbits & ~bits) & 0x55555555) != 0;
+ bool has3 = ((bbits & bits) & 0x55555555) != 0;
+
+ if (has2 || has3) {
+ if (color0 > color1) {
+ r2 = avg23(r0, r1);
+ g2 = avg23(g0, g1);
+ b2 = avg23(b0, b1);
+
+ r3 = avg23(r1, r0);
+ g3 = avg23(g1, g0);
+ b3 = avg23(b1, b0);
+ a3 = 1;
+ } else {
+ r2 = (r0 + r1) >> 1;
+ g2 = (g0 + g1) >> 1;
+ b2 = (b0 + b1) >> 1;
+
+ r3 = g3 = b3 = a3 = 0;
+ }
+ if (hasAlpha) {
+ c[2] = (r2 << 11) | ((g2 >> 1) << 6) |
+ (b2 << 1) | 0x1;
+ c[3] = (r3 << 11) | ((g3 >> 1) << 6) |
+ (b3 << 1) | a3;
+ } else {
+ c[2] = (r2 << 11) | (g2 << 5) | b2;
+ c[3] = (r3 << 11) | (g3 << 5) | b3;
+ }
+ }
+ }
+
+ uint16_t* blockRowPtr = blockPtr;
+ for (int y = 0; y < 4; y++, blockRowPtr += stride) {
+ // Don't process rows past the botom
+ if (base_y + y >= height) {
+ break;
+ }
+
+ int w = min(width - base_x, 4);
+ for (int x = 0; x < w; x++) {
+ int code = bits & 0x3;
+ bits >>= 2;
+
+ blockRowPtr[x] = c[code];
+ }
+ }
+ }
+ }
+}
+
+// Output data as internalformat=GL_RGBA, type=GL_UNSIGNED_BYTE
+static void
+decodeDXT3(const GLvoid *data, int width, int height,
+ void *surface, int stride)
+
+{
+ init_tables();
+
+ uint32_t const *d32 = (uint32_t *)data;
+
+ // Specified colors from the previous block
+ uint16_t prev_color0 = 0x0000;
+ uint16_t prev_color1 = 0x0000;
+
+ // Color table for the current block
+ uint32_t c[4];
+ c[0] = c[1] = c[2] = c[3] = 0;
+
+ uint32_t* rowPtr = (uint32_t*)surface;
+ for (int base_y = 0; base_y < height; base_y += 4, rowPtr += 4*stride) {
+ uint32_t *blockPtr = rowPtr;
+ for (int base_x = 0; base_x < width; base_x += 4, blockPtr += 4) {
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+ uint32_t alphahi = *d32++;
+ uint32_t alphalo = *d32++;
+ alphahi = swap(alphahi);
+ alphalo = swap(alphalo);
+#else
+ uint32_t alphalo = *d32++;
+ uint32_t alphahi = *d32++;
+#endif
+
+ uint32_t colors = *d32++;
+ uint32_t bits = *d32++;
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+ colors = swap(colors);
+ bits = swap(bits);
+#endif
+
+ uint64_t alpha = ((uint64_t)alphahi << 32) | alphalo;
+
+ // Raw colors
+ uint16_t color0 = colors & 0xffff;
+ uint16_t color1 = colors >> 16;
+
+ // If the new block has the same base colors as the
+ // previous one, we don't need to recompute the color
+ // table c[]
+ if (color0 != prev_color0 || color1 != prev_color1) {
+ // Store raw colors for comparison with next block
+ prev_color0 = color0;
+ prev_color1 = color1;
+
+ int bbits = bits >> 1;
+ bool has2 = ((bbits & ~bits) & 0x55555555) != 0;
+ bool has3 = ((bbits & bits) & 0x55555555) != 0;
+
+ if (has2 || has3) {
+ int r0 = red(color0);
+ int g0 = green(color0);
+ int b0 = blue(color0);
+
+ int r1 = red(color1);
+ int g1 = green(color1);
+ int b1 = blue(color1);
+
+ int r2 = avg23(r0, r1);
+ int g2 = avg23(g0, g1);
+ int b2 = avg23(b0, b1);
+
+ int r3 = avg23(r1, r0);
+ int g3 = avg23(g1, g0);
+ int b3 = avg23(b1, b0);
+
+ c[0] = rgb565SepTo888(r0, g0, b0);
+ c[1] = rgb565SepTo888(r1, g1, b1);
+ c[2] = rgb565SepTo888(r2, g2, b2);
+ c[3] = rgb565SepTo888(r3, g3, b3);
+ } else {
+ // Convert to 8 bits
+ c[0] = rgb565To888(color0);
+ c[1] = rgb565To888(color1);
+ }
+ }
+
+ uint32_t* blockRowPtr = blockPtr;
+ for (int y = 0; y < 4; y++, blockRowPtr += stride) {
+ // Don't process rows past the botom
+ if (base_y + y >= height) {
+ break;
+ }
+
+ int w = min(width - base_x, 4);
+ for (int x = 0; x < w; x++) {
+ int a = alpha & 0xf;
+ alpha >>= 4;
+
+ int code = bits & 0x3;
+ bits >>= 2;
+
+ blockRowPtr[x] = c[code] | (a << 28) | (a << 24);
+ }
+ }
+ }
+ }
+}
+
+// Output data as internalformat=GL_RGBA, type=GL_UNSIGNED_BYTE
+static void
+decodeDXT5(const GLvoid *data, int width, int height,
+ void *surface, int stride)
+
+{
+ init_tables();
+
+ uint32_t const *d32 = (uint32_t *)data;
+
+ // Specified alphas from the previous block
+ uint8_t prev_alpha0 = 0x00;
+ uint8_t prev_alpha1 = 0x00;
+
+ // Specified colors from the previous block
+ uint16_t prev_color0 = 0x0000;
+ uint16_t prev_color1 = 0x0000;
+
+ // Alpha table for the current block
+ uint8_t a[8];
+ a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = 0;
+
+ // Color table for the current block
+ uint32_t c[4];
+ c[0] = c[1] = c[2] = c[3] = 0;
+
+ int good_a5 = 0;
+ int bad_a5 = 0;
+ int good_a6 = 0;
+ int bad_a6 = 0;
+ int good_a7 = 0;
+ int bad_a7 = 0;
+
+ uint32_t* rowPtr = (uint32_t*)surface;
+ for (int base_y = 0; base_y < height; base_y += 4, rowPtr += 4*stride) {
+ uint32_t *blockPtr = rowPtr;
+ for (int base_x = 0; base_x < width; base_x += 4, blockPtr += 4) {
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+ uint32_t alphahi = *d32++;
+ uint32_t alphalo = *d32++;
+ alphahi = swap(alphahi);
+ alphalo = swap(alphalo);
+#else
+ uint32_t alphalo = *d32++;
+ uint32_t alphahi = *d32++;
+#endif
+
+ uint32_t colors = *d32++;
+ uint32_t bits = *d32++;
+
+#if __BYTE_ORDER == __BIG_ENDIANx
+ colors = swap(colors);
+ bits = swap(bits);
+#endif
+
+ uint64_t alpha = ((uint64_t)alphahi << 32) | alphalo;
+ uint64_t alpha0 = alpha & 0xff;
+ alpha >>= 8;
+ uint64_t alpha1 = alpha & 0xff;
+ alpha >>= 8;
+
+ if (alpha0 != prev_alpha0 || alpha1 != prev_alpha1) {
+ prev_alpha0 = alpha0;
+ prev_alpha1 = alpha1;
+
+ a[0] = alpha0;
+ a[1] = alpha1;
+ int a01 = alpha0 + alpha1 - 1;
+ if (alpha0 > alpha1) {
+ a[2] = div7(6*alpha0 + alpha1);
+ a[4] = div7(4*alpha0 + 3*alpha1);
+ a[6] = div7(2*alpha0 + 5*alpha1);
+
+ // Use symmetry to derive half of the values
+ // A few values will be off by 1 (~.5%)
+ // Alternate which values are computed directly
+ // and which are derived to try to reduce bias
+ a[3] = a01 - a[6];
+ a[5] = a01 - a[4];
+ a[7] = a01 - a[2];
+ } else {
+ a[2] = div5(4*alpha0 + alpha1);
+ a[4] = div5(2*alpha0 + 3*alpha1);
+ a[3] = a01 - a[4];
+ a[5] = a01 - a[2];
+ a[6] = 0x00;
+ a[7] = 0xff;
+ }
+ }
+
+ // Raw colors
+ uint16_t color0 = colors & 0xffff;
+ uint16_t color1 = colors >> 16;
+
+ // If the new block has the same base colors as the
+ // previous one, we don't need to recompute the color
+ // table c[]
+ if (color0 != prev_color0 || color1 != prev_color1) {
+ // Store raw colors for comparison with next block
+ prev_color0 = color0;
+ prev_color1 = color1;
+
+ int bbits = bits >> 1;
+ bool has2 = ((bbits & ~bits) & 0x55555555) != 0;
+ bool has3 = ((bbits & bits) & 0x55555555) != 0;
+
+ if (has2 || has3) {
+ int r0 = red(color0);
+ int g0 = green(color0);
+ int b0 = blue(color0);
+
+ int r1 = red(color1);
+ int g1 = green(color1);
+ int b1 = blue(color1);
+
+ int r2 = avg23(r0, r1);
+ int g2 = avg23(g0, g1);
+ int b2 = avg23(b0, b1);
+
+ int r3 = avg23(r1, r0);
+ int g3 = avg23(g1, g0);
+ int b3 = avg23(b1, b0);
+
+ c[0] = rgb565SepTo888(r0, g0, b0);
+ c[1] = rgb565SepTo888(r1, g1, b1);
+ c[2] = rgb565SepTo888(r2, g2, b2);
+ c[3] = rgb565SepTo888(r3, g3, b3);
+ } else {
+ // Convert to 8 bits
+ c[0] = rgb565To888(color0);
+ c[1] = rgb565To888(color1);
+ }
+ }
+
+ uint32_t* blockRowPtr = blockPtr;
+ for (int y = 0; y < 4; y++, blockRowPtr += stride) {
+ // Don't process rows past the botom
+ if (base_y + y >= height) {
+ break;
+ }
+
+ int w = min(width - base_x, 4);
+ for (int x = 0; x < w; x++) {
+ int acode = alpha & 0x7;
+ alpha >>= 3;
+
+ int code = bits & 0x3;
+ bits >>= 2;
+
+ blockRowPtr[x] = c[code] | (a[acode] << 24);
+ }
+ }
+ }
+ }
+}
+
+/*
+ * Decode a DXT-compressed texture into memory. DXT textures consist of
+ * a series of 4x4 pixel blocks in left-to-right, top-down order.
+ * The number of blocks is given by ceil(width/4)*ceil(height/4).
+ *
+ * 'data' points to the texture data. 'width' and 'height' indicate the
+ * dimensions of the texture. We assume width and height are >= 0 but
+ * do not require them to be powers of 2 or divisible by any factor.
+ *
+ * The output is written to 'surface' with each scanline separated by
+ * 'stride' 2- or 4-byte words.
+ *
+ * 'format' indicates the type of compression and must be one of the following:
+ *
+ * GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ * The output is written as 5/6/5 opaque RGB (16 bit words).
+ * 8 bytes are read from 'data' for each block.
+ *
+ * GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
+ * The output is written as 5/5/5/1 RGBA (16 bit words)
+ * 8 bytes are read from 'data' for each block.
+ *
+ * GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
+ * GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
+ * The output is written as 8/8/8/8 ARGB (32 bit words)
+ * 16 bytes are read from 'data' for each block.
+ */
+void
+decodeDXT(const GLvoid *data, int width, int height,
+ void *surface, int stride, int format)
+{
+#if TIMING
+ struct timeval start_t, end_t;
+ struct timezone tz;
+
+ gettimeofday(&start_t, &tz);
+#endif
+
+ switch (format) {
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ decodeDXT1(data, width, height, surface, stride, false);
+ break;
+
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ decodeDXT1(data, width, height, surface, stride, true);
+ break;
+
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+ decodeDXT3(data, width, height, surface, stride);
+ break;
+
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+ decodeDXT5(data, width, height, surface, stride);
+ break;
+ }
+
+#if TIMING
+ gettimeofday(&end_t, &tz);
+ long usec = (end_t.tv_sec - start_t.tv_sec)*1000000 +
+ (end_t.tv_usec - start_t.tv_usec);
+
+ printf("Loaded w=%d h=%d in %ld usec\n", width, height, usec);
+#endif
+}
+
+} // namespace android
diff --git a/opengl/libagl/dxt.h b/opengl/libagl/dxt.h
new file mode 100644
index 0000000..d95a36c
--- /dev/null
+++ b/opengl/libagl/dxt.h
@@ -0,0 +1,33 @@
+/* libs/opengles/dxt.h
+**
+** Copyright 2007, 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.
+*/
+
+#ifndef ANDROID_OPENGLES_TEXTURE_H
+#define ANDROID_OPENGLES_TEXTURE_H
+
+#include <stdlib.h>
+
+#include <GLES/gl.h>
+
+namespace android {
+
+ bool DXT1HasAlpha(const GLvoid *data, int width, int height);
+ void decodeDXT(const GLvoid *data, int width, int height,
+ void *surface, int stride, int format);
+
+} // namespace android
+
+#endif // ANDROID_OPENGLES_TEXTURE_H
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
new file mode 100644
index 0000000..5b90bf0
--- /dev/null
+++ b/opengl/libagl/egl.cpp
@@ -0,0 +1,1543 @@
+/*
+**
+** Copyright 2007 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.
+*/
+
+#define LOG_TAG "EGL"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+
+#include <utils/threads.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <pixelflinger/format.h>
+#include <pixelflinger/pixelflinger.h>
+
+#include "context.h"
+#include "state.h"
+#include "texture.h"
+#include "matrix.h"
+
+#undef NELEM
+#define NELEM(x) (sizeof(x)/sizeof(*(x)))
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+const unsigned int NUM_DISPLAYS = 1;
+
+static pthread_mutex_t gInitMutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t gErrorKeyMutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_key_t gEGLErrorKey = -1;
+#ifndef HAVE_ANDROID_OS
+namespace gl {
+pthread_key_t gGLKey = -1;
+}; // namespace gl
+#endif
+
+template<typename T>
+static T setError(GLint error, T returnValue) {
+ if (ggl_unlikely(gEGLErrorKey == -1)) {
+ pthread_mutex_lock(&gErrorKeyMutex);
+ if (gEGLErrorKey == -1)
+ pthread_key_create(&gEGLErrorKey, NULL);
+ pthread_mutex_unlock(&gErrorKeyMutex);
+ }
+ pthread_setspecific(gEGLErrorKey, (void*)error);
+ return returnValue;
+}
+
+static GLint getError() {
+ if (ggl_unlikely(gEGLErrorKey == -1))
+ return EGL_SUCCESS;
+ GLint error = (GLint)pthread_getspecific(gEGLErrorKey);
+ pthread_setspecific(gEGLErrorKey, (void*)EGL_SUCCESS);
+ return error;
+}
+
+// ----------------------------------------------------------------------------
+
+struct egl_display_t
+{
+ egl_display_t() : type(0), initialized(0) { }
+
+ static egl_display_t& get_display(EGLDisplay dpy);
+
+ static EGLBoolean is_valid(EGLDisplay dpy) {
+ return ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS) ? EGL_FALSE : EGL_TRUE;
+ }
+
+ NativeDisplayType type;
+ volatile int32_t initialized;
+};
+
+static egl_display_t gDisplays[NUM_DISPLAYS];
+
+egl_display_t& egl_display_t::get_display(EGLDisplay dpy) {
+ return gDisplays[uintptr_t(dpy)-1U];
+}
+
+struct egl_context_t {
+ enum {
+ IS_CURRENT = 0x00010000,
+ NEVER_CURRENT = 0x00020000
+ };
+ uint32_t flags;
+ EGLDisplay dpy;
+ EGLConfig config;
+ EGLSurface read;
+ EGLSurface draw;
+
+ static inline egl_context_t* context(EGLContext ctx) {
+ ogles_context_t* const gl = static_cast<ogles_context_t*>(ctx);
+ return static_cast<egl_context_t*>(gl->rasterizer.base);
+ }
+};
+
+// ----------------------------------------------------------------------------
+
+struct egl_surface_t
+{
+ enum {
+ PAGE_FLIP = 0x00000001,
+ MAGIC = 0x31415265
+ };
+
+ uint32_t magic;
+ EGLDisplay dpy;
+ EGLConfig config;
+ EGLContext ctx;
+
+ egl_surface_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat);
+ virtual ~egl_surface_t();
+ virtual bool isValid() const = 0;
+
+ virtual EGLBoolean bindDrawSurface(ogles_context_t* gl) = 0;
+ virtual EGLBoolean bindReadSurface(ogles_context_t* gl) = 0;
+ virtual EGLint getWidth() const = 0;
+ virtual EGLint getHeight() const = 0;
+ virtual void* getBits() const = 0;
+
+ virtual EGLint getHorizontalResolution() const;
+ virtual EGLint getVerticalResolution() const;
+ virtual EGLint getRefreshRate() const;
+ virtual EGLint getSwapBehavior() const;
+ virtual EGLBoolean swapBuffers();
+protected:
+ GGLSurface depth;
+};
+
+egl_surface_t::egl_surface_t(EGLDisplay dpy,
+ EGLConfig config,
+ int32_t depthFormat)
+ : magic(MAGIC), dpy(dpy), config(config), ctx(0)
+{
+ depth.version = sizeof(GGLSurface);
+ depth.data = 0;
+ depth.format = depthFormat;
+}
+egl_surface_t::~egl_surface_t()
+{
+ magic = 0;
+ free(depth.data);
+}
+EGLBoolean egl_surface_t::swapBuffers() {
+ return EGL_FALSE;
+}
+EGLint egl_surface_t::getHorizontalResolution() const {
+ return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
+}
+EGLint egl_surface_t::getVerticalResolution() const {
+ return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
+}
+EGLint egl_surface_t::getRefreshRate() const {
+ return (60 * EGL_DISPLAY_SCALING);
+}
+EGLint egl_surface_t::getSwapBehavior() const {
+ return EGL_BUFFER_PRESERVED;
+}
+
+// ----------------------------------------------------------------------------
+
+struct egl_window_surface_t : public egl_surface_t
+{
+ egl_window_surface_t(
+ EGLDisplay dpy, EGLConfig config,
+ int32_t depthFormat,
+ egl_native_window_t* window);
+
+ ~egl_window_surface_t();
+
+ virtual bool isValid() const { return nativeWindow->magic == 0x600913; }
+ virtual EGLBoolean swapBuffers();
+ virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
+ virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
+ virtual EGLint getWidth() const { return nativeWindow->width; }
+ virtual EGLint getHeight() const { return nativeWindow->height; }
+ virtual void* getBits() const;
+ virtual EGLint getHorizontalResolution() const;
+ virtual EGLint getVerticalResolution() const;
+ virtual EGLint getRefreshRate() const;
+ virtual EGLint getSwapBehavior() const;
+private:
+ egl_native_window_t* nativeWindow;
+};
+
+egl_window_surface_t::egl_window_surface_t(EGLDisplay dpy,
+ EGLConfig config,
+ int32_t depthFormat,
+ egl_native_window_t* window)
+ : egl_surface_t(dpy, config, depthFormat), nativeWindow(window)
+{
+ if (depthFormat) {
+ depth.width = window->width;
+ depth.height = window->height;
+ depth.stride = depth.width; // use the width here
+ depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
+ if (depth.data == 0) {
+ setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+ return;
+ }
+ }
+ nativeWindow->incRef(nativeWindow);
+}
+egl_window_surface_t::~egl_window_surface_t() {
+ nativeWindow->decRef(nativeWindow);
+}
+
+EGLBoolean egl_window_surface_t::swapBuffers()
+{
+ uint32_t flags = nativeWindow->swapBuffers(nativeWindow);
+ if (flags & EGL_NATIVES_FLAG_SIZE_CHANGED) {
+ // TODO: we probably should reset the swap rect here
+ // if the window size has changed
+ if (depth.data) {
+ free(depth.data);
+ depth.width = nativeWindow->width;
+ depth.height = nativeWindow->height;
+ depth.stride = nativeWindow->stride;
+ depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
+ if (depth.data == 0) {
+ setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+ return EGL_FALSE;
+ }
+ }
+ }
+ return EGL_TRUE;
+}
+
+EGLBoolean egl_window_surface_t::bindDrawSurface(ogles_context_t* gl)
+{
+ GGLSurface buffer;
+ buffer.version = sizeof(GGLSurface);
+ buffer.width = nativeWindow->width;
+ buffer.height = nativeWindow->height;
+ buffer.stride = nativeWindow->stride;
+ buffer.data = (GGLubyte*)nativeWindow->base + nativeWindow->offset;
+ buffer.format = nativeWindow->format;
+ gl->rasterizer.procs.colorBuffer(gl, &buffer);
+ if (depth.data != gl->rasterizer.state.buffers.depth.data)
+ gl->rasterizer.procs.depthBuffer(gl, &depth);
+ return EGL_TRUE;
+}
+EGLBoolean egl_window_surface_t::bindReadSurface(ogles_context_t* gl)
+{
+ GGLSurface buffer;
+ buffer.version = sizeof(GGLSurface);
+ buffer.width = nativeWindow->width;
+ buffer.height = nativeWindow->height;
+ buffer.stride = nativeWindow->stride;
+ buffer.data = (GGLubyte*)nativeWindow->base + nativeWindow->offset;
+ buffer.format = nativeWindow->format;
+ gl->rasterizer.procs.readBuffer(gl, &buffer);
+ return EGL_TRUE;
+}
+void* egl_window_surface_t::getBits() const {
+ return (GGLubyte*)nativeWindow->base + nativeWindow->offset;
+}
+EGLint egl_window_surface_t::getHorizontalResolution() const {
+ return (nativeWindow->xdpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
+}
+EGLint egl_window_surface_t::getVerticalResolution() const {
+ return (nativeWindow->ydpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
+}
+EGLint egl_window_surface_t::getRefreshRate() const {
+ return (nativeWindow->fps * EGL_DISPLAY_SCALING);
+}
+EGLint egl_window_surface_t::getSwapBehavior() const {
+ uint32_t flags = nativeWindow->flags;
+ if (flags & EGL_NATIVES_FLAG_DESTROY_BACKBUFFER)
+ return EGL_BUFFER_DESTROYED;
+ return EGL_BUFFER_PRESERVED;
+}
+
+// ----------------------------------------------------------------------------
+
+struct egl_pixmap_surface_t : public egl_surface_t
+{
+ egl_pixmap_surface_t(
+ EGLDisplay dpy, EGLConfig config,
+ int32_t depthFormat,
+ egl_native_pixmap_t const * pixmap);
+
+ virtual ~egl_pixmap_surface_t() { }
+
+ virtual bool isValid() const { return nativePixmap.version == sizeof(egl_native_pixmap_t); }
+ virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
+ virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
+ virtual EGLint getWidth() const { return nativePixmap.width; }
+ virtual EGLint getHeight() const { return nativePixmap.height; }
+ virtual void* getBits() const { return nativePixmap.data; }
+private:
+ egl_native_pixmap_t nativePixmap;
+};
+
+egl_pixmap_surface_t::egl_pixmap_surface_t(EGLDisplay dpy,
+ EGLConfig config,
+ int32_t depthFormat,
+ egl_native_pixmap_t const * pixmap)
+ : egl_surface_t(dpy, config, depthFormat), nativePixmap(*pixmap)
+{
+ if (depthFormat) {
+ depth.width = pixmap->width;
+ depth.height = pixmap->height;
+ depth.stride = depth.width; // use the width here
+ depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
+ if (depth.data == 0) {
+ setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+ return;
+ }
+ }
+}
+EGLBoolean egl_pixmap_surface_t::bindDrawSurface(ogles_context_t* gl)
+{
+ GGLSurface buffer;
+ buffer.version = sizeof(GGLSurface);
+ buffer.width = nativePixmap.width;
+ buffer.height = nativePixmap.height;
+ buffer.stride = nativePixmap.stride;
+ buffer.data = nativePixmap.data;
+ buffer.format = nativePixmap.format;
+
+ gl->rasterizer.procs.colorBuffer(gl, &buffer);
+ if (depth.data != gl->rasterizer.state.buffers.depth.data)
+ gl->rasterizer.procs.depthBuffer(gl, &depth);
+ return EGL_TRUE;
+}
+EGLBoolean egl_pixmap_surface_t::bindReadSurface(ogles_context_t* gl)
+{
+ GGLSurface buffer;
+ buffer.version = sizeof(GGLSurface);
+ buffer.width = nativePixmap.width;
+ buffer.height = nativePixmap.height;
+ buffer.stride = nativePixmap.stride;
+ buffer.data = nativePixmap.data;
+ buffer.format = nativePixmap.format;
+ gl->rasterizer.procs.readBuffer(gl, &buffer);
+ return EGL_TRUE;
+}
+
+// ----------------------------------------------------------------------------
+
+struct egl_pbuffer_surface_t : public egl_surface_t
+{
+ egl_pbuffer_surface_t(
+ EGLDisplay dpy, EGLConfig config, int32_t depthFormat,
+ int32_t w, int32_t h, int32_t f);
+
+ virtual ~egl_pbuffer_surface_t();
+
+ virtual bool isValid() const { return pbuffer.data != 0; }
+ virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
+ virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
+ virtual EGLint getWidth() const { return pbuffer.width; }
+ virtual EGLint getHeight() const { return pbuffer.height; }
+ virtual void* getBits() const { return pbuffer.data; }
+private:
+ GGLSurface pbuffer;
+};
+
+egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy,
+ EGLConfig config, int32_t depthFormat,
+ int32_t w, int32_t h, int32_t f)
+ : egl_surface_t(dpy, config, depthFormat)
+{
+ size_t size = w*h;
+ switch (f) {
+ case GGL_PIXEL_FORMAT_A_8: size *= 1; break;
+ case GGL_PIXEL_FORMAT_RGB_565: size *= 2; break;
+ case GGL_PIXEL_FORMAT_RGBA_8888: size *= 4; break;
+ default:
+ LOGE("incompatible pixel format for pbuffer (format=%d)", f);
+ pbuffer.data = 0;
+ break;
+ }
+ pbuffer.version = sizeof(GGLSurface);
+ pbuffer.width = w;
+ pbuffer.height = h;
+ pbuffer.stride = w;
+ pbuffer.data = (GGLubyte*)malloc(size);
+ pbuffer.format = f;
+
+ if (depthFormat) {
+ depth.width = pbuffer.width;
+ depth.height = pbuffer.height;
+ depth.stride = depth.width; // use the width here
+ depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
+ if (depth.data == 0) {
+ setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+ return;
+ }
+ }
+}
+egl_pbuffer_surface_t::~egl_pbuffer_surface_t() {
+ free(pbuffer.data);
+}
+EGLBoolean egl_pbuffer_surface_t::bindDrawSurface(ogles_context_t* gl)
+{
+ gl->rasterizer.procs.colorBuffer(gl, &pbuffer);
+ if (depth.data != gl->rasterizer.state.buffers.depth.data)
+ gl->rasterizer.procs.depthBuffer(gl, &depth);
+ return EGL_TRUE;
+}
+EGLBoolean egl_pbuffer_surface_t::bindReadSurface(ogles_context_t* gl)
+{
+ gl->rasterizer.procs.readBuffer(gl, &pbuffer);
+ return EGL_TRUE;
+}
+
+// ----------------------------------------------------------------------------
+
+struct config_pair_t {
+ GLint key;
+ GLint value;
+};
+
+struct configs_t {
+ const config_pair_t* array;
+ int size;
+};
+
+struct config_management_t {
+ GLint key;
+ bool (*match)(GLint reqValue, GLint confValue);
+ static bool atLeast(GLint reqValue, GLint confValue) {
+ return (reqValue == EGL_DONT_CARE) || (confValue >= reqValue);
+ }
+ static bool exact(GLint reqValue, GLint confValue) {
+ return (reqValue == EGL_DONT_CARE) || (confValue == reqValue);
+ }
+ static bool mask(GLint reqValue, GLint confValue) {
+ return (confValue & reqValue) == reqValue;
+ }
+};
+
+// ----------------------------------------------------------------------------
+
+#define VERSION_MAJOR 1
+#define VERSION_MINOR 2
+static char const * const gVendorString = "Google Inc.";
+static char const * const gVersionString = "1.2 Android Driver";
+static char const * const gClientApiString = "OpenGL ES";
+static char const * const gExtensionsString = "";
+
+// ----------------------------------------------------------------------------
+
+struct extention_map_t {
+ const char * const name;
+ __eglMustCastToProperFunctionPointerType address;
+};
+
+static const extention_map_t gExtentionMap[] = {
+ { "glDrawTexsOES", (void(*)())&glDrawTexsOES },
+ { "glDrawTexiOES", (void(*)())&glDrawTexiOES },
+ { "glDrawTexfOES", (void(*)())&glDrawTexfOES },
+ { "glDrawTexxOES", (void(*)())&glDrawTexxOES },
+ { "glDrawTexsvOES", (void(*)())&glDrawTexsvOES },
+ { "glDrawTexivOES", (void(*)())&glDrawTexivOES },
+ { "glDrawTexfvOES", (void(*)())&glDrawTexfvOES },
+ { "glDrawTexxvOES", (void(*)())&glDrawTexxvOES },
+ { "glQueryMatrixxOES", (void(*)())&glQueryMatrixxOES },
+ { "glClipPlanef", (void(*)())&glClipPlanef },
+ { "glClipPlanex", (void(*)())&glClipPlanex },
+ { "glBindBuffer", (void(*)())&glBindBuffer },
+ { "glBufferData", (void(*)())&glBufferData },
+ { "glBufferSubData", (void(*)())&glBufferSubData },
+ { "glDeleteBuffers", (void(*)())&glDeleteBuffers },
+ { "glGenBuffers", (void(*)())&glGenBuffers },
+};
+
+/*
+ * In the lists below, attributes names MUST be sorted.
+ * Additionally, all configs must be sorted according to
+ * the EGL specification.
+ */
+
+static config_pair_t const config_base_attribute_list[] = {
+ { EGL_STENCIL_SIZE, 0 },
+ { EGL_CONFIG_CAVEAT, EGL_SLOW_CONFIG },
+ { EGL_LEVEL, 0 },
+ { EGL_MAX_PBUFFER_HEIGHT, GGL_MAX_VIEWPORT_DIMS },
+ { EGL_MAX_PBUFFER_PIXELS,
+ GGL_MAX_VIEWPORT_DIMS*GGL_MAX_VIEWPORT_DIMS },
+ { EGL_MAX_PBUFFER_WIDTH, GGL_MAX_VIEWPORT_DIMS },
+ { EGL_NATIVE_RENDERABLE, EGL_TRUE },
+ { EGL_NATIVE_VISUAL_ID, 0 },
+ { EGL_NATIVE_VISUAL_TYPE, GGL_PIXEL_FORMAT_RGB_565 },
+ { EGL_SAMPLES, 0 },
+ { EGL_SAMPLE_BUFFERS, 0 },
+ { EGL_TRANSPARENT_TYPE, EGL_NONE },
+ { EGL_TRANSPARENT_BLUE_VALUE, 0 },
+ { EGL_TRANSPARENT_GREEN_VALUE, 0 },
+ { EGL_TRANSPARENT_RED_VALUE, 0 },
+ { EGL_BIND_TO_TEXTURE_RGBA, EGL_FALSE },
+ { EGL_BIND_TO_TEXTURE_RGB, EGL_FALSE },
+ { EGL_MIN_SWAP_INTERVAL, 1 },
+ { EGL_MAX_SWAP_INTERVAL, 4 },
+};
+
+// These configs can override the base attribute list
+// NOTE: when adding a config here, don't forget to update eglCreate*Surface()
+
+static config_pair_t const config_0_attribute_list[] = {
+ { EGL_BUFFER_SIZE, 16 },
+ { EGL_ALPHA_SIZE, 0 },
+ { EGL_BLUE_SIZE, 5 },
+ { EGL_GREEN_SIZE, 6 },
+ { EGL_RED_SIZE, 5 },
+ { EGL_DEPTH_SIZE, 0 },
+ { EGL_CONFIG_ID, 0 },
+ { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+};
+
+static config_pair_t const config_1_attribute_list[] = {
+ { EGL_BUFFER_SIZE, 16 },
+ { EGL_ALPHA_SIZE, 0 },
+ { EGL_BLUE_SIZE, 5 },
+ { EGL_GREEN_SIZE, 6 },
+ { EGL_RED_SIZE, 5 },
+ { EGL_DEPTH_SIZE, 16 },
+ { EGL_CONFIG_ID, 1 },
+ { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+};
+
+static config_pair_t const config_2_attribute_list[] = {
+ { EGL_BUFFER_SIZE, 32 },
+ { EGL_ALPHA_SIZE, 8 },
+ { EGL_BLUE_SIZE, 8 },
+ { EGL_GREEN_SIZE, 8 },
+ { EGL_RED_SIZE, 8 },
+ { EGL_DEPTH_SIZE, 0 },
+ { EGL_CONFIG_ID, 2 },
+ { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+};
+
+static config_pair_t const config_3_attribute_list[] = {
+ { EGL_BUFFER_SIZE, 32 },
+ { EGL_ALPHA_SIZE, 8 },
+ { EGL_BLUE_SIZE, 8 },
+ { EGL_GREEN_SIZE, 8 },
+ { EGL_RED_SIZE, 8 },
+ { EGL_DEPTH_SIZE, 16 },
+ { EGL_CONFIG_ID, 3 },
+ { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+};
+
+static config_pair_t const config_4_attribute_list[] = {
+ { EGL_BUFFER_SIZE, 8 },
+ { EGL_ALPHA_SIZE, 8 },
+ { EGL_BLUE_SIZE, 0 },
+ { EGL_GREEN_SIZE, 0 },
+ { EGL_RED_SIZE, 0 },
+ { EGL_DEPTH_SIZE, 0 },
+ { EGL_CONFIG_ID, 4 },
+ { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+};
+
+static config_pair_t const config_5_attribute_list[] = {
+ { EGL_BUFFER_SIZE, 8 },
+ { EGL_ALPHA_SIZE, 8 },
+ { EGL_BLUE_SIZE, 0 },
+ { EGL_GREEN_SIZE, 0 },
+ { EGL_RED_SIZE, 0 },
+ { EGL_DEPTH_SIZE, 16 },
+ { EGL_CONFIG_ID, 5 },
+ { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+};
+
+static configs_t const gConfigs[] = {
+ { config_0_attribute_list, NELEM(config_0_attribute_list) },
+ { config_1_attribute_list, NELEM(config_1_attribute_list) },
+ { config_2_attribute_list, NELEM(config_2_attribute_list) },
+ { config_3_attribute_list, NELEM(config_3_attribute_list) },
+ { config_4_attribute_list, NELEM(config_4_attribute_list) },
+ { config_5_attribute_list, NELEM(config_5_attribute_list) },
+};
+
+static config_management_t const gConfigManagement[] = {
+ { EGL_BUFFER_SIZE, config_management_t::atLeast },
+ { EGL_ALPHA_SIZE, config_management_t::atLeast },
+ { EGL_BLUE_SIZE, config_management_t::atLeast },
+ { EGL_GREEN_SIZE, config_management_t::atLeast },
+ { EGL_RED_SIZE, config_management_t::atLeast },
+ { EGL_DEPTH_SIZE, config_management_t::atLeast },
+ { EGL_STENCIL_SIZE, config_management_t::atLeast },
+ { EGL_CONFIG_CAVEAT, config_management_t::exact },
+ { EGL_CONFIG_ID, config_management_t::exact },
+ { EGL_LEVEL, config_management_t::exact },
+ { EGL_MAX_PBUFFER_HEIGHT, config_management_t::exact },
+ { EGL_MAX_PBUFFER_PIXELS, config_management_t::exact },
+ { EGL_MAX_PBUFFER_WIDTH, config_management_t::exact },
+ { EGL_NATIVE_RENDERABLE, config_management_t::exact },
+ { EGL_NATIVE_VISUAL_ID, config_management_t::exact },
+ { EGL_NATIVE_VISUAL_TYPE, config_management_t::exact },
+ { EGL_SAMPLES, config_management_t::exact },
+ { EGL_SAMPLE_BUFFERS, config_management_t::exact },
+ { EGL_SURFACE_TYPE, config_management_t::mask },
+ { EGL_TRANSPARENT_TYPE, config_management_t::exact },
+ { EGL_TRANSPARENT_BLUE_VALUE, config_management_t::exact },
+ { EGL_TRANSPARENT_GREEN_VALUE, config_management_t::exact },
+ { EGL_TRANSPARENT_RED_VALUE, config_management_t::exact },
+ { EGL_BIND_TO_TEXTURE_RGBA, config_management_t::exact },
+ { EGL_BIND_TO_TEXTURE_RGB, config_management_t::exact },
+ { EGL_MIN_SWAP_INTERVAL, config_management_t::exact },
+ { EGL_MAX_SWAP_INTERVAL, config_management_t::exact },
+};
+
+static config_pair_t const config_defaults[] = {
+ { EGL_SURFACE_TYPE, EGL_WINDOW_BIT },
+};
+
+// ----------------------------------------------------------------------------
+
+template<typename T>
+static int binarySearch(T const sortedArray[], int first, int last, EGLint key)
+{
+ while (first <= last) {
+ int mid = (first + last) / 2;
+ if (key > sortedArray[mid].key) {
+ first = mid + 1;
+ } else if (key < sortedArray[mid].key) {
+ last = mid - 1;
+ } else {
+ return mid;
+ }
+ }
+ return -1;
+}
+
+static int isAttributeMatching(int i, EGLint attr, EGLint val)
+{
+ // look for the attribute in all of our configs
+ config_pair_t const* configFound = gConfigs[i].array;
+ int index = binarySearch<config_pair_t>(
+ gConfigs[i].array,
+ 0, gConfigs[i].size-1,
+ attr);
+ if (index < 0) {
+ configFound = config_base_attribute_list;
+ index = binarySearch<config_pair_t>(
+ config_base_attribute_list,
+ 0, NELEM(config_base_attribute_list)-1,
+ attr);
+ }
+ if (index >= 0) {
+ // attribute found, check if this config could match
+ int cfgMgtIndex = binarySearch<config_management_t>(
+ gConfigManagement,
+ 0, NELEM(gConfigManagement)-1,
+ attr);
+ if (index >= 0) {
+ bool match = gConfigManagement[cfgMgtIndex].match(
+ val, configFound[index].value);
+ if (match) {
+ // this config matches
+ return 1;
+ }
+ } else {
+ // attribute not found. this should NEVER happen.
+ }
+ } else {
+ // error, this attribute doesn't exist
+ }
+ return 0;
+}
+
+static int makeCurrent(ogles_context_t* gl)
+{
+ ogles_context_t* current = (ogles_context_t*)getGlThreadSpecific();
+ if (gl) {
+ egl_context_t* c = egl_context_t::context(gl);
+ if (c->flags & egl_context_t::IS_CURRENT) {
+ if (current != gl) {
+ // it is an error to set a context current, if it's already
+ // current to another thread
+ return -1;
+ }
+ } else {
+ if (current) {
+ // mark the current context as not current, and flush
+ glFlush();
+ egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
+ }
+ }
+ if (!(c->flags & egl_context_t::IS_CURRENT)) {
+ // The context is not current, make it current!
+ setGlThreadSpecific(gl);
+ c->flags |= egl_context_t::IS_CURRENT;
+ }
+ } else {
+ if (current) {
+ // mark the current context as not current, and flush
+ glFlush();
+ egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
+ }
+ // this thread has no context attached to it
+ setGlThreadSpecific(0);
+ }
+ return 0;
+}
+
+static EGLBoolean getConfigAttrib(EGLDisplay dpy, EGLConfig config,
+ EGLint attribute, EGLint *value)
+{
+ size_t numConfigs = NELEM(gConfigs);
+ int index = (int)config;
+ if (uint32_t(index) >= numConfigs)
+ return setError(EGL_BAD_CONFIG, EGL_FALSE);
+
+ int attrIndex;
+ attrIndex = binarySearch<config_pair_t>(
+ gConfigs[index].array,
+ 0, gConfigs[index].size-1,
+ attribute);
+ if (attrIndex>=0) {
+ *value = gConfigs[index].array[attrIndex].value;
+ return EGL_TRUE;
+ }
+
+ attrIndex = binarySearch<config_pair_t>(
+ config_base_attribute_list,
+ 0, NELEM(config_base_attribute_list)-1,
+ attribute);
+ if (attrIndex>=0) {
+ *value = config_base_attribute_list[attrIndex].value;
+ return EGL_TRUE;
+ }
+ return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+}
+
+static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config,
+ NativeWindowType window, const EGLint *attrib_list)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
+ if (window == 0)
+ return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+
+ EGLint surfaceType;
+ if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
+ return EGL_FALSE;
+
+ if (!(surfaceType & EGL_WINDOW_BIT))
+ return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+
+ EGLint configID;
+ if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
+ return EGL_FALSE;
+
+ int32_t depthFormat;
+ int32_t pixelFormat;
+ switch(configID) {
+ case 0:
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ depthFormat = 0;
+ break;
+ case 1:
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ depthFormat = GGL_PIXEL_FORMAT_Z_16;
+ break;
+ case 2:
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ depthFormat = 0;
+ break;
+ case 3:
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ depthFormat = GGL_PIXEL_FORMAT_Z_16;
+ break;
+ case 4:
+ pixelFormat = GGL_PIXEL_FORMAT_A_8;
+ depthFormat = 0;
+ break;
+ case 5:
+ pixelFormat = GGL_PIXEL_FORMAT_A_8;
+ depthFormat = GGL_PIXEL_FORMAT_Z_16;
+ break;
+ default:
+ return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ }
+
+ // FIXME: we don't have access to the pixelFormat here just yet.
+ // (it's possible that the surface is not fully initialized)
+ // maybe this should be done after the page-flip
+ //if (EGLint(info.format) != pixelFormat)
+ // return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+
+ egl_surface_t* surface =
+ new egl_window_surface_t(dpy, config, depthFormat,
+ static_cast<egl_native_window_t*>(window));
+
+ if (!surface->isValid()) {
+ // there was a problem in the ctor, the error
+ // flag has been set.
+ delete surface;
+ surface = 0;
+ }
+ return surface;
+}
+
+static EGLSurface createPixmapSurface(EGLDisplay dpy, EGLConfig config,
+ NativePixmapType pixmap, const EGLint *attrib_list)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
+ if (pixmap == 0)
+ return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+
+ EGLint surfaceType;
+ if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
+ return EGL_FALSE;
+
+ if (!(surfaceType & EGL_PIXMAP_BIT))
+ return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+
+ EGLint configID;
+ if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
+ return EGL_FALSE;
+
+ int32_t depthFormat;
+ int32_t pixelFormat;
+ switch(configID) {
+ case 0:
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ depthFormat = 0;
+ break;
+ case 1:
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ depthFormat = GGL_PIXEL_FORMAT_Z_16;
+ break;
+ case 2:
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ depthFormat = 0;
+ break;
+ case 3:
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ depthFormat = GGL_PIXEL_FORMAT_Z_16;
+ break;
+ case 4:
+ pixelFormat = GGL_PIXEL_FORMAT_A_8;
+ depthFormat = 0;
+ break;
+ case 5:
+ pixelFormat = GGL_PIXEL_FORMAT_A_8;
+ depthFormat = GGL_PIXEL_FORMAT_Z_16;
+ break;
+ default:
+ return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ }
+
+ if (pixmap->format != pixelFormat)
+ return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+
+ egl_surface_t* surface =
+ new egl_pixmap_surface_t(dpy, config, depthFormat,
+ static_cast<egl_native_pixmap_t*>(pixmap));
+
+ if (!surface->isValid()) {
+ // there was a problem in the ctor, the error
+ // flag has been set.
+ delete surface;
+ surface = 0;
+ }
+ return surface;
+}
+
+static EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config,
+ const EGLint *attrib_list)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
+
+ EGLint surfaceType;
+ if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
+ return EGL_FALSE;
+
+ if (!(surfaceType & EGL_PBUFFER_BIT))
+ return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+
+ EGLint configID;
+ if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
+ return EGL_FALSE;
+
+ int32_t depthFormat;
+ int32_t pixelFormat;
+ switch(configID) {
+ case 0:
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ depthFormat = 0;
+ break;
+ case 1:
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ depthFormat = GGL_PIXEL_FORMAT_Z_16;
+ break;
+ case 2:
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ depthFormat = 0;
+ break;
+ case 3:
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ depthFormat = GGL_PIXEL_FORMAT_Z_16;
+ break;
+ case 4:
+ pixelFormat = GGL_PIXEL_FORMAT_A_8;
+ depthFormat = 0;
+ break;
+ case 5:
+ pixelFormat = GGL_PIXEL_FORMAT_A_8;
+ depthFormat = GGL_PIXEL_FORMAT_Z_16;
+ break;
+ default:
+ return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ }
+
+ int32_t w = 0;
+ int32_t h = 0;
+ while (attrib_list[0]) {
+ if (attrib_list[0] == EGL_WIDTH) w = attrib_list[1];
+ if (attrib_list[0] == EGL_HEIGHT) h = attrib_list[1];
+ attrib_list+=2;
+ }
+
+ egl_surface_t* surface =
+ new egl_pbuffer_surface_t(dpy, config, depthFormat, w, h, pixelFormat);
+
+ if (!surface->isValid()) {
+ // there was a problem in the ctor, the error
+ // flag has been set.
+ delete surface;
+ surface = 0;
+ }
+ return surface;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+// ----------------------------------------------------------------------------
+// Initialization
+// ----------------------------------------------------------------------------
+
+EGLDisplay eglGetDisplay(NativeDisplayType display)
+{
+#ifndef HAVE_ANDROID_OS
+ // this just needs to be done once
+ if (gGLKey == -1) {
+ pthread_mutex_lock(&gInitMutex);
+ if (gGLKey == -1)
+ pthread_key_create(&gGLKey, NULL);
+ pthread_mutex_unlock(&gInitMutex);
+ }
+#endif
+ if (display == EGL_DEFAULT_DISPLAY) {
+ EGLDisplay dpy = (EGLDisplay)1;
+ egl_display_t& d = egl_display_t::get_display(dpy);
+ d.type = display;
+ return dpy;
+ }
+ return EGL_NO_DISPLAY;
+}
+
+EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ EGLBoolean res = EGL_TRUE;
+ egl_display_t& d = egl_display_t::get_display(dpy);
+
+ if (android_atomic_inc(&d.initialized) == 0) {
+ // initialize stuff here if needed
+ //pthread_mutex_lock(&gInitMutex);
+ //pthread_mutex_unlock(&gInitMutex);
+ }
+
+ if (res == EGL_TRUE) {
+ if (major != NULL) *major = VERSION_MAJOR;
+ if (minor != NULL) *minor = VERSION_MINOR;
+ }
+ return res;
+}
+
+EGLBoolean eglTerminate(EGLDisplay dpy)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ EGLBoolean res = EGL_TRUE;
+ egl_display_t& d = egl_display_t::get_display(dpy);
+ if (android_atomic_dec(&d.initialized) == 1) {
+ // TODO: destroy all resources (surfaces, contexts, etc...)
+ //pthread_mutex_lock(&gInitMutex);
+ //pthread_mutex_unlock(&gInitMutex);
+ }
+ return res;
+}
+
+// ----------------------------------------------------------------------------
+// configuration
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglGetConfigs( EGLDisplay dpy,
+ EGLConfig *configs,
+ EGLint config_size, EGLint *num_config)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ GLint numConfigs = NELEM(gConfigs);
+ if (!configs) {
+ *num_config = numConfigs;
+ return EGL_TRUE;
+ }
+ GLint i;
+ for (i=0 ; i<numConfigs && i<config_size ; i++) {
+ *configs++ = (EGLConfig)i;
+ }
+ *num_config = i;
+ return EGL_TRUE;
+}
+
+EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
+ EGLConfig *configs, EGLint config_size,
+ EGLint *num_config)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ if (ggl_unlikely(configs==0 || attrib_list==0)) {
+ *num_config = 0;
+ return EGL_TRUE;
+ }
+
+ int numAttributes = 0;
+ int numConfigs = NELEM(gConfigs);
+ uint32_t possibleMatch = (1<<numConfigs)-1;
+ while(possibleMatch && *attrib_list != EGL_NONE) {
+ numAttributes++;
+ EGLint attr = *attrib_list++;
+ EGLint val = *attrib_list++;
+ for (int i=0 ; i<numConfigs ; i++) {
+ if (!(possibleMatch & (1<<i)))
+ continue;
+ if (isAttributeMatching(i, attr, val) == 0) {
+ possibleMatch &= ~(1<<i);
+ }
+ }
+ }
+
+ // now, handle the attributes which have a useful default value
+ for (size_t j=0 ; j<NELEM(config_defaults) ; j++) {
+ // see if this attribute was specified, if not apply its
+ // default value
+ if (binarySearch<config_pair_t>(
+ (config_pair_t const*)attrib_list,
+ 0, numAttributes,
+ config_defaults[j].key) < 0)
+ {
+ for (int i=0 ; i<numConfigs ; i++) {
+ if (!(possibleMatch & (1<<i)))
+ continue;
+ if (isAttributeMatching(i,
+ config_defaults[j].key,
+ config_defaults[j].value) == 0)
+ {
+ possibleMatch &= ~(1<<i);
+ }
+ }
+ }
+ }
+
+ // return the configurations found
+ int n=0;
+ if (possibleMatch) {
+ for (int i=0 ; config_size && i<numConfigs ; i++) {
+ if (possibleMatch & (1<<i)) {
+ *configs++ = (EGLConfig)i;
+ config_size--;
+ n++;
+ }
+ }
+ }
+ *num_config = n;
+ return EGL_TRUE;
+}
+
+EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
+ EGLint attribute, EGLint *value)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ return getConfigAttrib(dpy, config, attribute, value);
+}
+
+// ----------------------------------------------------------------------------
+// surfaces
+// ----------------------------------------------------------------------------
+
+EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
+ NativeWindowType window,
+ const EGLint *attrib_list)
+{
+ return createWindowSurface(dpy, config, window, attrib_list);
+}
+
+EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
+ NativePixmapType pixmap,
+ const EGLint *attrib_list)
+{
+ return createPixmapSurface(dpy, config, pixmap, attrib_list);
+}
+
+EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
+ const EGLint *attrib_list)
+{
+ return createPbufferSurface(dpy, config, attrib_list);
+}
+
+EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ if (eglSurface != EGL_NO_SURFACE) {
+ egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
+ if (surface->magic != egl_surface_t::MAGIC)
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ if (surface->dpy != dpy)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ delete surface;
+ }
+ return EGL_TRUE;
+}
+
+EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface eglSurface,
+ EGLint attribute, EGLint *value)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ egl_surface_t* surface = static_cast<egl_surface_t*>(eglSurface);
+ if (surface->dpy != dpy)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ EGLBoolean ret = EGL_TRUE;
+ switch (attribute) {
+ case EGL_CONFIG_ID:
+ ret = getConfigAttrib(dpy, surface->config, EGL_CONFIG_ID, value);
+ break;
+ case EGL_WIDTH:
+ *value = surface->getWidth();
+ break;
+ case EGL_HEIGHT:
+ *value = surface->getHeight();
+ break;
+ case EGL_LARGEST_PBUFFER:
+ // not modified for a window or pixmap surface
+ break;
+ case EGL_TEXTURE_FORMAT:
+ *value = EGL_NO_TEXTURE;
+ break;
+ case EGL_TEXTURE_TARGET:
+ *value = EGL_NO_TEXTURE;
+ break;
+ case EGL_MIPMAP_TEXTURE:
+ *value = EGL_FALSE;
+ break;
+ case EGL_MIPMAP_LEVEL:
+ *value = 0;
+ break;
+ case EGL_RENDER_BUFFER:
+ // TODO: return the real RENDER_BUFFER here
+ *value = EGL_BACK_BUFFER;
+ break;
+ case EGL_HORIZONTAL_RESOLUTION:
+ // pixel/mm * EGL_DISPLAY_SCALING
+ *value = surface->getHorizontalResolution();
+ break;
+ case EGL_VERTICAL_RESOLUTION:
+ // pixel/mm * EGL_DISPLAY_SCALING
+ *value = surface->getVerticalResolution();
+ break;
+ case EGL_PIXEL_ASPECT_RATIO: {
+ // w/h * EGL_DISPLAY_SCALING
+ int wr = surface->getHorizontalResolution();
+ int hr = surface->getVerticalResolution();
+ *value = (wr * EGL_DISPLAY_SCALING) / hr;
+ } break;
+ case EGL_SWAP_BEHAVIOR:
+ *value = surface->getSwapBehavior();
+ break;
+ default:
+ ret = setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+ }
+ return ret;
+}
+
+EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
+ EGLContext share_list, const EGLint *attrib_list)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
+
+ ogles_context_t* gl = ogles_init(sizeof(egl_context_t));
+ if (!gl) return setError(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
+
+ egl_context_t* c = static_cast<egl_context_t*>(gl->rasterizer.base);
+ c->flags = egl_context_t::NEVER_CURRENT;
+ c->dpy = dpy;
+ c->config = config;
+ c->read = 0;
+ c->draw = 0;
+ return (EGLContext)gl;
+}
+
+EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ egl_context_t* c = egl_context_t::context(ctx);
+ if (c->flags & egl_context_t::IS_CURRENT)
+ setGlThreadSpecific(0);
+ ogles_uninit((ogles_context_t*)ctx);
+ return EGL_TRUE;
+}
+
+EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
+ EGLSurface read, EGLContext ctx)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ if (draw) {
+ egl_surface_t* s = (egl_surface_t*)draw;
+ if (s->dpy != dpy)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ // TODO: check that draw and read are compatible with the context
+ }
+
+ EGLContext current_ctx = EGL_NO_CONTEXT;
+
+ if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT))
+ return setError(EGL_BAD_MATCH, EGL_FALSE);
+
+ if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT))
+ return setError(EGL_BAD_MATCH, EGL_FALSE);
+
+ if (ctx == EGL_NO_CONTEXT) {
+ // if we're detaching, we need the current context
+ current_ctx = (EGLContext)getGlThreadSpecific();
+ } else {
+ egl_context_t* c = egl_context_t::context(ctx);
+ egl_surface_t* d = (egl_surface_t*)draw;
+ egl_surface_t* r = (egl_surface_t*)read;
+ if ((d && d->ctx && d->ctx != ctx) ||
+ (r && r->ctx && r->ctx != ctx)) {
+ // once of the surface is bound to a context in another thread
+ return setError(EGL_BAD_ACCESS, EGL_FALSE);
+ }
+ }
+
+ ogles_context_t* gl = (ogles_context_t*)ctx;
+ if (makeCurrent(gl) == 0) {
+ if (ctx) {
+ egl_context_t* c = egl_context_t::context(ctx);
+ egl_surface_t* d = (egl_surface_t*)draw;
+ egl_surface_t* r = (egl_surface_t*)read;
+ c->read = read;
+ c->draw = draw;
+ if (c->flags & egl_context_t::NEVER_CURRENT) {
+ c->flags &= ~egl_context_t::NEVER_CURRENT;
+ GLint w = 0;
+ GLint h = 0;
+ if (draw) {
+ w = d->getWidth();
+ h = d->getHeight();
+ }
+ ogles_surfaceport(gl, 0, 0);
+ ogles_viewport(gl, 0, 0, w, h);
+ ogles_scissor(gl, 0, 0, w, h);
+ }
+ if (d) {
+ d->ctx = ctx;
+ d->bindDrawSurface(gl);
+ }
+ if (r) {
+ r->ctx = ctx;
+ r->bindReadSurface(gl);
+ }
+ } else {
+ // if surfaces were bound to the context bound to this thread
+ // mark then as unbound.
+ if (current_ctx) {
+ egl_context_t* c = egl_context_t::context(current_ctx);
+ egl_surface_t* d = (egl_surface_t*)c->draw;
+ egl_surface_t* r = (egl_surface_t*)c->read;
+ if (d) d->ctx = EGL_NO_CONTEXT;
+ if (r) r->ctx = EGL_NO_CONTEXT;
+ }
+ }
+ return EGL_TRUE;
+ }
+ return setError(EGL_BAD_ACCESS, EGL_FALSE);
+}
+
+EGLContext eglGetCurrentContext(void)
+{
+ // eglGetCurrentContext returns the current EGL rendering context,
+ // as specified by eglMakeCurrent. If no context is current,
+ // EGL_NO_CONTEXT is returned.
+ return (EGLContext)getGlThreadSpecific();
+}
+
+EGLSurface eglGetCurrentSurface(EGLint readdraw)
+{
+ // eglGetCurrentSurface returns the read or draw surface attached
+ // to the current EGL rendering context, as specified by eglMakeCurrent.
+ // If no context is current, EGL_NO_SURFACE is returned.
+ EGLContext ctx = (EGLContext)getGlThreadSpecific();
+ if (ctx == EGL_NO_CONTEXT) return EGL_NO_SURFACE;
+ egl_context_t* c = egl_context_t::context(ctx);
+ if (readdraw == EGL_READ) {
+ return c->read;
+ } else if (readdraw == EGL_DRAW) {
+ return c->draw;
+ }
+ return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+}
+
+EGLDisplay eglGetCurrentDisplay(void)
+{
+ // eglGetCurrentDisplay returns the current EGL display connection
+ // for the current EGL rendering context, as specified by eglMakeCurrent.
+ // If no context is current, EGL_NO_DISPLAY is returned.
+ EGLContext ctx = (EGLContext)getGlThreadSpecific();
+ if (ctx == EGL_NO_CONTEXT) return EGL_NO_DISPLAY;
+ egl_context_t* c = egl_context_t::context(ctx);
+ return c->dpy;
+}
+
+EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
+ EGLint attribute, EGLint *value)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ egl_context_t* c = egl_context_t::context(ctx);
+ switch (attribute) {
+ case EGL_CONFIG_ID:
+ // Returns the ID of the EGL frame buffer configuration with
+ // respect to which the context was created
+ return getConfigAttrib(dpy, c->config, EGL_CONFIG_ID, value);
+ }
+ return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+}
+
+EGLBoolean eglWaitGL(void)
+{
+ return EGL_TRUE;
+}
+
+EGLBoolean eglWaitNative(EGLint engine)
+{
+ return EGL_TRUE;
+}
+
+EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ egl_surface_t* d = static_cast<egl_surface_t*>(draw);
+ if (d->dpy != dpy)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ // post the surface
+ d->swapBuffers();
+
+ // if it's bound to a context, update the buffer
+ if (d->ctx != EGL_NO_CONTEXT) {
+ d->bindDrawSurface((ogles_context_t*)d->ctx);
+ // if this surface is also the read surface of the context
+ // it is bound to, make sure to update the read buffer as well.
+ // The EGL spec is a little unclear about this.
+ egl_context_t* c = egl_context_t::context(d->ctx);
+ if (c->read == draw) {
+ d->bindReadSurface((ogles_context_t*)d->ctx);
+ }
+ }
+
+ return EGL_TRUE;
+}
+
+EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
+ NativePixmapType target)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ // TODO: eglCopyBuffers()
+ return EGL_FALSE;
+}
+
+EGLint eglGetError(void)
+{
+ return getError();
+}
+
+const char* eglQueryString(EGLDisplay dpy, EGLint name)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, (const char*)0);
+
+ switch (name) {
+ case EGL_VENDOR:
+ return gVendorString;
+ case EGL_VERSION:
+ return gVersionString;
+ case EGL_EXTENSIONS:
+ return gExtensionsString;
+ case EGL_CLIENT_APIS:
+ return gClientApiString;
+ }
+ return setError(EGL_BAD_PARAMETER, (const char *)0);
+}
+
+// ----------------------------------------------------------------------------
+// EGL 1.1
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglSurfaceAttrib(
+ EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ // TODO: eglSurfaceAttrib()
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+}
+
+EGLBoolean eglBindTexImage(
+ EGLDisplay dpy, EGLSurface surface, EGLint buffer)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ // TODO: eglBindTexImage()
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+}
+
+EGLBoolean eglReleaseTexImage(
+ EGLDisplay dpy, EGLSurface surface, EGLint buffer)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ // TODO: eglReleaseTexImage()
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+}
+
+EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ // TODO: eglSwapInterval()
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+}
+
+// ----------------------------------------------------------------------------
+// EGL 1.2
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglBindAPI(EGLenum api)
+{
+ if (api != EGL_OPENGL_ES_API)
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ return EGL_TRUE;
+}
+
+EGLenum eglQueryAPI(void)
+{
+ return EGL_OPENGL_ES_API;
+}
+
+EGLBoolean eglWaitClient(void)
+{
+ glFinish();
+ return EGL_TRUE;
+}
+
+EGLBoolean eglReleaseThread(void)
+{
+ // TODO: eglReleaseThread()
+ return EGL_TRUE;
+}
+
+EGLSurface eglCreatePbufferFromClientBuffer(
+ EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
+ EGLConfig config, const EGLint *attrib_list)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
+ // TODO: eglCreatePbufferFromClientBuffer()
+ return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
+}
+
+// ----------------------------------------------------------------------------
+// Android extensions
+// ----------------------------------------------------------------------------
+
+void (*eglGetProcAddress (const char *procname))()
+{
+ extention_map_t const * const map = gExtentionMap;
+ for (uint32_t i=0 ; i<NELEM(gExtentionMap) ; i++) {
+ if (!strcmp(procname, map[i].name)) {
+ return map[i].address;
+ }
+ }
+ return NULL;
+}
diff --git a/opengl/libagl/fixed_asm.S b/opengl/libagl/fixed_asm.S
new file mode 100644
index 0000000..6cbc56f
--- /dev/null
+++ b/opengl/libagl/fixed_asm.S
@@ -0,0 +1,65 @@
+/* libs/opengles/fixed_asm.S
+**
+** 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.
+*/
+
+
+ .text
+ .align
+
+ .global gglFloatToFixed
+ .global gglFloatToFixedFast
+
+
+/*
+ * Converts a float to a s15.16 fixed-point number.
+ * this doesn't handle floats out of the [-32768, +32768[ range
+ * and doesn't performs round-to-nearest.
+ * however, it's very fast :-)
+ */
+
+gglFloatToFixedFast:
+ movs r1, r0, lsl #1 /* remove bit sign */
+ mov r2, #0x8E /* 127 + 15 */
+ sub r1, r2, r1, lsr #24 /* compute shift */
+ mov r2, r0, lsl #8 /* mantissa<<8 */
+ orr r2, r2, #0x80000000 /* add the missing 1 */
+ mov r0, r2, lsr r1 /* scale to 16.16 */
+ rsbcs r0, r0, #0 /* negate if needed */
+ bx lr
+
+/*
+ * this version rounds-to-nearest and saturates numbers
+ * outside the range (but not NaNs).
+ */
+
+gglFloatToFixed:
+ mov r1, r0, lsl #1 /* remove bit sign */
+ mov r2, #0x8E /* 127 + 15 */
+ subs r1, r2, r1, lsr #24 /* compute shift */
+ bls 0f /* too big */
+ mov r2, r0, lsl #8 /* mantissa<<8 */
+ orr r2, r2, #0x80000000 /* add the missing 1 */
+ mov r3, r0
+ movs r0, r2, lsr r1 /* scale to 16.16 */
+ addcs r0, r0, #1 /* round-to-nearest */
+ tst r3, #0x80000000 /* negative? */
+ rsbne r0, r0, #0 /* negate if needed */
+ bx lr
+
+0: ands r0, r0, #0x80000000 /* keep only the sign bit */
+ moveq r0, #0x7fffffff /* positive, maximum value */
+ bx lr
+
diff --git a/opengl/libagl/fp.cpp b/opengl/libagl/fp.cpp
new file mode 100644
index 0000000..ae5f1fe
--- /dev/null
+++ b/opengl/libagl/fp.cpp
@@ -0,0 +1,87 @@
+/* libs/opengles/fp.cpp
+**
+** 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 "fp.h"
+
+// ----------------------------------------------------------------------------
+
+#if !defined(__arm__)
+GGLfixed gglFloatToFixed(float v) {
+ return GGLfixed(floorf(v * 65536.0f + 0.5f));
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+namespace gl {
+
+GLfloat fixedToFloat(GLfixed x)
+{
+#if DEBUG_USE_FLOATS
+ return x / 65536.0f;
+#else
+ if (!x) return 0;
+ const uint32_t s = x & 0x80000000;
+ union {
+ uint32_t i;
+ float f;
+ };
+ i = s ? -x : x;
+ const int c = gglClz(i) - 8;
+ i = (c>=0) ? (i<<c) : (i>>-c);
+ const uint32_t e = 134 - c;
+ i &= ~0x800000;
+ i |= e<<23;
+ i |= s;
+ return f;
+#endif
+}
+
+float sinef(float x)
+{
+ const float A = 1.0f / (2.0f*M_PI);
+ const float B = -16.0f;
+ const float C = 8.0f;
+
+ // scale angle for easy argument reduction
+ x *= A;
+
+ if (fabsf(x) >= 0.5f) {
+ // Argument reduction
+ x = x - ceilf(x + 0.5f) + 1.0f;
+ }
+
+ const float y = B*x*fabsf(x) + C*x;
+ return 0.2215f * (y*fabsf(y) - y) + y;
+}
+
+float cosinef(float x)
+{
+ return sinef(x + float(M_PI/2));
+}
+
+void sincosf(GLfloat angle, GLfloat* s, GLfloat* c) {
+ *s = sinef(angle);
+ *c = cosinef(angle);
+}
+
+}; // namespace fp_utils
+
+// ----------------------------------------------------------------------------
+}; // namespace android
diff --git a/opengl/libagl/fp.h b/opengl/libagl/fp.h
new file mode 100644
index 0000000..6d0c183
--- /dev/null
+++ b/opengl/libagl/fp.h
@@ -0,0 +1,243 @@
+/* libs/opengles/fp.h
+**
+** 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.
+*/
+
+#ifndef ANDROID_OPENGLES_FP_H
+#define ANDROID_OPENGLES_FP_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <math.h>
+
+#include <private/pixelflinger/ggl_context.h>
+
+#include <GLES/gl.h>
+
+#define DEBUG_USE_FLOATS 0
+
+// ----------------------------------------------------------------------------
+
+extern "C" GLfixed gglFloatToFixed(float f) __attribute__((const));
+
+// ----------------------------------------------------------------------------
+namespace android {
+
+namespace gl {
+
+ GLfloat fixedToFloat(GLfixed) CONST;
+
+ void sincosf(GLfloat angle, GLfloat* s, GLfloat* c);
+ float sinef(GLfloat x) CONST;
+ float cosinef(GLfloat x) CONST;
+
+inline bool cmpf(GLfloat a, GLfloat b) CONST;
+inline bool isZerof(GLfloat) CONST;
+inline bool isOnef(GLfloat) CONST;
+
+inline int isZeroOrNegativef(GLfloat) CONST;
+
+inline int exponent(GLfloat) CONST;
+inline int32_t mantissa(GLfloat) CONST;
+inline GLfloat clampToZerof(GLfloat) CONST;
+inline GLfloat reciprocalf(GLfloat) CONST;
+inline GLfloat rsqrtf(GLfloat) CONST;
+inline GLfloat sqrf(GLfloat) CONST;
+inline GLfloat addExpf(GLfloat v, int e) CONST;
+inline GLfloat mul2f(GLfloat v) CONST;
+inline GLfloat div2f(GLfloat v) CONST;
+inline GLfloat absf(GLfloat v) CONST;
+
+
+/*
+ * float fastexpf(float) : a fast approximation of expf(x)
+ * give somewhat accurate results for -88 <= x <= 88
+ *
+ * exp(x) = 2^(x/ln(2))
+ * we use the properties of float encoding
+ * to get a fast 2^ and linear interpolation
+ *
+ */
+
+inline float fastexpf(float y) __attribute__((const));
+
+inline float fastexpf(float y)
+{
+ union {
+ float r;
+ int32_t i;
+ } u;
+
+ // 127*ln(2) = 88
+ if (y < -88.0f) {
+ u.r = 0.0f;
+ } else if (y > 88.0f) {
+ u.r = INFINITY;
+ } else {
+ const float kOneOverLogTwo = (1L<<23) / M_LN2;
+ const int32_t kExponentBias = 127L<<23;
+ const int32_t e = int32_t(y*kOneOverLogTwo);
+ u.i = e + kExponentBias;
+ }
+
+ return u.r;
+}
+
+
+bool cmpf(GLfloat a, GLfloat b) {
+#if DEBUG_USE_FLOATS
+ return a == b;
+#else
+ union {
+ float f;
+ uint32_t i;
+ } ua, ub;
+ ua.f = a;
+ ub.f = b;
+ return ua.i == ub.i;
+#endif
+}
+
+bool isZerof(GLfloat v) {
+#if DEBUG_USE_FLOATS
+ return v == 0;
+#else
+ union {
+ float f;
+ int32_t i;
+ };
+ f = v;
+ return (i<<1) == 0;
+#endif
+}
+
+bool isOnef(GLfloat v) {
+ return cmpf(v, 1.0f);
+}
+
+int isZeroOrNegativef(GLfloat v) {
+#if DEBUG_USE_FLOATS
+ return v <= 0;
+#else
+ union {
+ float f;
+ int32_t i;
+ };
+ f = v;
+ return isZerof(v) | (i>>31);
+#endif
+}
+
+int exponent(GLfloat v) {
+ union {
+ float f;
+ uint32_t i;
+ };
+ f = v;
+ return ((i << 1) >> 24) - 127;
+}
+
+int32_t mantissa(GLfloat v) {
+ union {
+ float f;
+ uint32_t i;
+ };
+ f = v;
+ if (!(i&0x7F800000)) return 0;
+ const int s = i >> 31;
+ i |= (1L<<23);
+ i &= ~0xFF000000;
+ return s ? -i : i;
+}
+
+GLfloat clampToZerof(GLfloat v) {
+#if DEBUG_USE_FLOATS
+ return v<0 ? 0 : (v>1 ? 1 : v);
+#else
+ union {
+ float f;
+ int32_t i;
+ };
+ f = v;
+ i &= ~(i>>31);
+ return f;
+#endif
+}
+
+GLfloat reciprocalf(GLfloat v) {
+ // XXX: do better
+ return 1.0f / v;
+}
+
+GLfloat rsqrtf(GLfloat v) {
+ // XXX: do better
+ return 1.0f / sqrtf(v);
+}
+
+GLfloat sqrf(GLfloat v) {
+ // XXX: do better
+ return v*v;
+}
+
+GLfloat addExpf(GLfloat v, int e) {
+ union {
+ float f;
+ int32_t i;
+ };
+ f = v;
+ if (i<<1) { // XXX: deal with over/underflow
+ i += int32_t(e)<<23;
+ }
+ return f;
+}
+
+GLfloat mul2f(GLfloat v) {
+#if DEBUG_USE_FLOATS
+ return v*2;
+#else
+ return addExpf(v, 1);
+#endif
+}
+
+GLfloat div2f(GLfloat v) {
+#if DEBUG_USE_FLOATS
+ return v*0.5f;
+#else
+ return addExpf(v, -1);
+#endif
+}
+
+GLfloat absf(GLfloat v) {
+#if DEBUG_USE_FLOATS
+ return v<0 ? -v : v;
+#else
+ union {
+ float f;
+ int32_t i;
+ };
+ f = v;
+ i &= ~0x80000000;
+ return f;
+#endif
+}
+
+}; // namespace gl
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_FP_H
+
diff --git a/opengl/libagl/iterators.S b/opengl/libagl/iterators.S
new file mode 100644
index 0000000..daf2937
--- /dev/null
+++ b/opengl/libagl/iterators.S
@@ -0,0 +1,88 @@
+/* libs/opengles/iterators.S
+**
+** 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.
+*/
+
+
+ .text
+ .align
+ .arm
+
+ .global iterators0032
+
+/*
+ * iterators0032
+ *
+ * MUST BE CALLED FROM ARM CODE
+ *
+ * r0: const compute_iterators_t* (this)
+ * r0 + 0: m_dx01
+ * r0 + 4: m_dy10
+ * r0 + 8: m_dx20
+ * r0 +12: m_dy02
+ * r0 +16: m_x0
+ * r0 +20: m_y0
+ * r0 +24: m_area
+ * r0 +28: m_scale
+ * r0 +29: m_area_scale;
+ * r1: int32_t* (out)
+ * r1 + 0: c
+ * r1 + 4: dcdx
+ * r1 + 8: dcdy
+ * r2: c0
+ * r3: c1
+ * [sp]: c2
+ */
+
+iterators0032:
+ stmfd sp!, {r4, r5, r6, r7, r8, lr}
+ ldr r4, [sp, #4*6]
+
+ ldrb r12, [r0, #29]
+ sub r3, r3, r2
+ sub r4, r4, r2
+ sub r12, r12, #16
+ mov r3, r3, asr r12
+ mov r4, r4, asr r12
+
+ ldr r5, [r0, #0]
+ ldr r12, [r0, #4]
+ smull r8, lr, r4, r5
+ ldr r5, [r0, #8]
+ smull r6, r7, r4, r12
+ ldr r12, [r0, #12]
+ smlal r8, lr, r3, r5
+ smlal r6, r7, r3, r12
+
+ ldr r3, [r0, #16] // m_x0
+ ldr r4, [r0, #20] // m_x1
+
+ str r6, [r1, #4]
+ str r8, [r1, #8]
+
+ umull r6, r5, r3, r6
+ umull r8, r0, r4, r8
+ mla r7, r3, r7, r5
+ mla lr, r4, lr, r0
+ adds r6, r6, r8
+ adc r7, r7, lr
+
+ movs r6, r6, lsr #4
+ adc r6, r6, r7, lsl #28
+ rsb r6, r6, r2, lsl #16
+ str r6, [r1, #0]
+
+ ldmfd sp!, {r4, r5, r6, r7, r8, pc}
+
diff --git a/opengl/libagl/light.cpp b/opengl/libagl/light.cpp
new file mode 100644
index 0000000..25c41d0
--- /dev/null
+++ b/opengl/libagl/light.cpp
@@ -0,0 +1,852 @@
+/* libs/opengles/light.cpp
+**
+** 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 <stdio.h>
+#include "context.h"
+#include "fp.h"
+#include "light.h"
+#include "state.h"
+#include "matrix.h"
+
+
+#if defined(__arm__) && defined(__thumb__)
+#warning "light.cpp should not be compiled in thumb on ARM."
+#endif
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static void invalidate_lighting(ogles_context_t* c);
+static void lightVertexValidate(ogles_context_t* c, vertex_t* v);
+static void lightVertexNop(ogles_context_t* c, vertex_t* v);
+static void lightVertex(ogles_context_t* c, vertex_t* v);
+static void lightVertexMaterial(ogles_context_t* c, vertex_t* v);
+
+static inline void vscale3(GLfixed* d, const GLfixed* m, GLfixed s);
+static inline void vsub3w(GLfixed* d, const GLfixed* a, const GLfixed* b);
+
+static __attribute__((noinline))
+void vnorm3(GLfixed* d, const GLfixed* a);
+
+static inline void vsa3(GLfixed* d,
+ const GLfixed* m, GLfixed s, const GLfixed* a);
+static inline void vmla3(GLfixed* d,
+ const GLfixed* m0, const GLfixed* m1, const GLfixed* a);
+static inline void vmul3(GLfixed* d,
+ const GLfixed* m0, const GLfixed* m1);
+
+static GLfixed fog_linear(ogles_context_t* c, GLfixed z);
+static GLfixed fog_exp(ogles_context_t* c, GLfixed z);
+static GLfixed fog_exp2(ogles_context_t* c, GLfixed z);
+
+
+// ----------------------------------------------------------------------------
+
+static void init_white(vec4_t& c) {
+ c.r = c.g = c.b = c.a = 0x10000;
+}
+
+void ogles_init_light(ogles_context_t* c)
+{
+ for (unsigned int i=0 ; i<OGLES_MAX_LIGHTS ; i++) {
+ c->lighting.lights[i].ambient.a = 0x10000;
+ c->lighting.lights[i].position.z = 0x10000;
+ c->lighting.lights[i].spotDir.z = -0x10000;
+ c->lighting.lights[i].spotCutoff = gglIntToFixed(180);
+ c->lighting.lights[i].attenuation[0] = 0x10000;
+ }
+ init_white(c->lighting.lights[0].diffuse);
+ init_white(c->lighting.lights[0].specular);
+
+ c->lighting.front.ambient.r =
+ c->lighting.front.ambient.g =
+ c->lighting.front.ambient.b = gglFloatToFixed(0.2f);
+ c->lighting.front.ambient.a = 0x10000;
+ c->lighting.front.diffuse.r =
+ c->lighting.front.diffuse.g =
+ c->lighting.front.diffuse.b = gglFloatToFixed(0.8f);
+ c->lighting.front.diffuse.a = 0x10000;
+ c->lighting.front.specular.a = 0x10000;
+ c->lighting.front.emission.a = 0x10000;
+
+ c->lighting.lightModel.ambient.r =
+ c->lighting.lightModel.ambient.g =
+ c->lighting.lightModel.ambient.b = gglFloatToFixed(0.2f);
+ c->lighting.lightModel.ambient.a = 0x10000;
+
+ c->lighting.colorMaterial.face = GL_FRONT_AND_BACK;
+ c->lighting.colorMaterial.mode = GL_AMBIENT_AND_DIFFUSE;
+
+ c->fog.mode = GL_EXP;
+ c->fog.fog = fog_exp;
+ c->fog.density = 0x10000;
+ c->fog.end = 0x10000;
+ c->fog.invEndMinusStart = 0x10000;
+
+ invalidate_lighting(c);
+
+ c->rasterizer.procs.shadeModel(c, GL_SMOOTH);
+ c->lighting.shadeModel = GL_SMOOTH;
+}
+
+void ogles_uninit_light(ogles_context_t* c)
+{
+}
+
+static inline int32_t clampF(GLfixed f) CONST;
+int32_t clampF(GLfixed f) {
+ f = (f & ~(f>>31));
+ if (f >= 0x10000)
+ f = 0x10000;
+ return f;
+}
+
+static GLfixed fog_linear(ogles_context_t* c, GLfixed z) {
+ return clampF(gglMulx((c->fog.end - ((z<0)?-z:z)), c->fog.invEndMinusStart));
+}
+
+static GLfixed fog_exp(ogles_context_t* c, GLfixed z) {
+ const float e = fixedToFloat(gglMulx(c->fog.density, ((z<0)?-z:z)));
+ return clampF(gglFloatToFixed(fastexpf(-e)));
+}
+
+static GLfixed fog_exp2(ogles_context_t* c, GLfixed z) {
+ const float e = fixedToFloat(gglMulx(c->fog.density, z));
+ return clampF(gglFloatToFixed(fastexpf(-e*e)));
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark math helpers
+#endif
+
+static inline
+void vscale3(GLfixed* d, const GLfixed* m, GLfixed s) {
+ d[0] = gglMulx(m[0], s);
+ d[1] = gglMulx(m[1], s);
+ d[2] = gglMulx(m[2], s);
+}
+
+static inline
+void vsa3(GLfixed* d, const GLfixed* m, GLfixed s, const GLfixed* a) {
+ d[0] = gglMulAddx(m[0], s, a[0]);
+ d[1] = gglMulAddx(m[1], s, a[1]);
+ d[2] = gglMulAddx(m[2], s, a[2]);
+}
+
+static inline
+void vsub3w(GLfixed* d, const GLfixed* a, const GLfixed* b) {
+ const GLfixed wa = a[3];
+ const GLfixed wb = b[3];
+ if (ggl_likely(wa == wb)) {
+ d[0] = a[0] - b[0];
+ d[1] = a[1] - b[1];
+ d[2] = a[2] - b[2];
+ } else {
+ d[0] = gglMulSubx(a[0], wb, gglMulx(b[0], wa));
+ d[1] = gglMulSubx(a[1], wb, gglMulx(b[1], wa));
+ d[2] = gglMulSubx(a[2], wb, gglMulx(b[2], wa));
+ }
+}
+
+static inline
+void vmla3(GLfixed* d,
+ const GLfixed* m0, const GLfixed* m1, const GLfixed* a)
+{
+ d[0] = gglMulAddx(m0[0], m1[0], a[0]);
+ d[1] = gglMulAddx(m0[1], m1[1], a[1]);
+ d[2] = gglMulAddx(m0[2], m1[2], a[2]);
+}
+
+static inline
+void vmul3(GLfixed* d, const GLfixed* m0, const GLfixed* m1) {
+ d[0] = gglMulx(m0[0], m1[0]);
+ d[1] = gglMulx(m0[1], m1[1]);
+ d[2] = gglMulx(m0[2], m1[2]);
+}
+
+void vnorm3(GLfixed* d, const GLfixed* a)
+{
+ // we must take care of overflows when normalizing a vector
+ GLfixed n;
+ int32_t x = a[0]; x = x>=0 ? x : -x;
+ int32_t y = a[1]; y = y>=0 ? y : -y;
+ int32_t z = a[2]; z = z>=0 ? z : -z;
+ if (ggl_likely(x<=0x6800 && y<=0x6800 && z<= 0x6800)) {
+ // in this case this will all fit on 32 bits
+ n = x*x + y*y + z*z;
+ n = gglSqrtRecipx(n);
+ n <<= 8;
+ } else {
+ // here norm^2 is at least 0x7EC00000 (>>32 == 0.495117)
+ n = vsquare3(x, y, z);
+ n = gglSqrtRecipx(n);
+ }
+ vscale3(d, a, n);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark lighting equations
+#endif
+
+static inline void light_picker(ogles_context_t* c)
+{
+ if (ggl_likely(!c->lighting.enable)) {
+ c->lighting.lightVertex = lightVertexNop;
+ return;
+ }
+ if (c->lighting.colorMaterial.enable) {
+ c->lighting.lightVertex = lightVertexMaterial;
+ } else {
+ c->lighting.lightVertex = lightVertex;
+ }
+}
+
+static inline void validate_light_mvi(ogles_context_t* c)
+{
+ uint32_t en = c->lighting.enabledLights;
+ while (en) {
+ const int i = 31 - gglClz(en);
+ en &= ~(1<<i);
+ light_t& l = c->lighting.lights[i];
+ c->transforms.mvui.point3(&c->transforms.mvui,
+ &l.objPosition, &l.position);
+ vnorm3(l.normalizedObjPosition.v, l.objPosition.v);
+ }
+}
+
+static inline void validate_light(ogles_context_t* c)
+{
+ // if colorMaterial is enabled, we get the color from the vertex
+ if (!c->lighting.colorMaterial.enable) {
+ material_t& material = c->lighting.front;
+ uint32_t en = c->lighting.enabledLights;
+ while (en) {
+ const int i = 31 - gglClz(en);
+ en &= ~(1<<i);
+ light_t& l = c->lighting.lights[i];
+ vmul3(l.implicitAmbient.v, material.ambient.v, l.ambient.v);
+ vmul3(l.implicitDiffuse.v, material.diffuse.v, l.diffuse.v);
+ vmul3(l.implicitSpecular.v, material.specular.v, l.specular.v);
+
+ // this is just a flag to tell if we have a specular component
+ l.implicitSpecular.v[3] =
+ l.implicitSpecular.r |
+ l.implicitSpecular.g |
+ l.implicitSpecular.b;
+
+ l.rConstAttenuation = (l.attenuation[1] | l.attenuation[2])==0;
+ if (l.rConstAttenuation)
+ l.rConstAttenuation = gglRecipFast(l.attenuation[0]);
+ }
+ // emission and ambient for the whole scene
+ vmla3( c->lighting.implicitSceneEmissionAndAmbient.v,
+ c->lighting.lightModel.ambient.v,
+ material.ambient.v,
+ material.emission.v);
+ c->lighting.implicitSceneEmissionAndAmbient.a = material.diffuse.a;
+ }
+ validate_light_mvi(c);
+}
+
+void invalidate_lighting(ogles_context_t* c)
+{
+ // TODO: pick lightVertexValidate or lightVertexValidateMVI
+ // instead of systematically the heavier lightVertexValidate()
+ c->lighting.lightVertex = lightVertexValidate;
+}
+
+void ogles_invalidate_lighting_mvui(ogles_context_t* c)
+{
+ invalidate_lighting(c);
+}
+
+void lightVertexNop(ogles_context_t*, vertex_t* v)
+{
+ // we should never end-up here
+}
+
+void lightVertexValidateMVI(ogles_context_t* c, vertex_t* v)
+{
+ validate_light_mvi(c);
+ light_picker(c);
+ c->lighting.lightVertex(c, v);
+}
+
+void lightVertexValidate(ogles_context_t* c, vertex_t* v)
+{
+ validate_light(c);
+ light_picker(c);
+ c->lighting.lightVertex(c, v);
+}
+
+void lightVertexMaterial(ogles_context_t* c, vertex_t* v)
+{
+ // fetch the material color
+ const GLvoid* cp = c->arrays.color.element(
+ v->index & vertex_cache_t::INDEX_MASK);
+ c->arrays.color.fetch(c, v->color.v, cp);
+
+ // acquire the color-material from the vertex
+ material_t& material = c->lighting.front;
+ material.ambient =
+ material.diffuse = v->color;
+ // implicit arguments need to be computed per/vertex
+ uint32_t en = c->lighting.enabledLights;
+ while (en) {
+ const int i = 31 - gglClz(en);
+ en &= ~(1<<i);
+ light_t& l = c->lighting.lights[i];
+ vmul3(l.implicitAmbient.v, material.ambient.v, l.ambient.v);
+ vmul3(l.implicitDiffuse.v, material.diffuse.v, l.diffuse.v);
+ vmul3(l.implicitSpecular.v, material.specular.v, l.specular.v);
+ }
+ // emission and ambient for the whole scene
+ vmla3( c->lighting.implicitSceneEmissionAndAmbient.v,
+ c->lighting.lightModel.ambient.v,
+ material.ambient.v,
+ material.emission.v);
+ c->lighting.implicitSceneEmissionAndAmbient.a = material.diffuse.a;
+
+ // now we can light our vertex as usual
+ lightVertex(c, v);
+}
+
+void lightVertex(ogles_context_t* c, vertex_t* v)
+{
+ // emission and ambient for the whole scene
+ vec4_t r = c->lighting.implicitSceneEmissionAndAmbient;
+
+ uint32_t en = c->lighting.enabledLights;
+ if (ggl_likely(en)) {
+ // since we do the lighting in object-space, we don't need to
+ // transform each normal. However, we might still have to normalize
+ // it if GL_NORMALIZE is enabled.
+ vec4_t n;
+ c->arrays.normal.fetch(c, n.v,
+ c->arrays.normal.element(v->index & vertex_cache_t::INDEX_MASK));
+ if (c->transforms.rescaleNormals == GL_NORMALIZE)
+ vnorm3(n.v, n.v);
+
+ const material_t& material = c->lighting.front;
+ const int twoSide = c->lighting.lightModel.twoSide;
+
+ while (en) {
+ const int i = 31 - gglClz(en);
+ en &= ~(1<<i);
+ const light_t& l = c->lighting.lights[i];
+
+ vec4_t d, t;
+ GLfixed s;
+ GLfixed sqDist = 0x10000;
+
+ // compute vertex-to-light vector
+ if (ggl_unlikely(l.position.w)) {
+ vsub3w(d.v, l.objPosition.v, v->obj.v);
+ sqDist = dot3(d.v, d.v);
+ vscale3(d.v, d.v, gglSqrtRecipx(sqDist));
+ } else {
+ // TODO: avoid copy here
+ d = l.normalizedObjPosition;
+ }
+
+ // ambient & diffuse
+ s = dot3(n.v, d.v);
+ s = (s<0) ? (twoSide?(-s):0) : s;
+ vsa3(t.v, l.implicitDiffuse.v, s, l.implicitAmbient.v);
+
+ // specular
+ if (ggl_unlikely(s && l.implicitSpecular.v[3])) {
+ vec4_t h;
+ h.x = d.x;
+ h.y = d.y;
+ h.z = d.z + 0x10000;
+ vnorm3(h.v, h.v);
+ s = dot3(n.v, h.v);
+ s = (s<0) ? (twoSide?(-s):0) : s;
+ if (s > 0) {
+ s = gglPowx(s, material.shininess);
+ vsa3(t.v, l.implicitSpecular.v, s, t.v);
+ }
+ }
+
+ // spot
+ if (ggl_unlikely(l.spotCutoff != gglIntToFixed(180))) {
+ GLfixed spotAtt = -dot3(l.normalizedSpotDir.v, d.v);
+ if (spotAtt >= l.spotCutoffCosine) {
+ vscale3(t.v, t.v, gglPowx(spotAtt, l.spotExp));
+ }
+ }
+
+ // attenuation
+ if (ggl_unlikely(l.position.w)) {
+ if (l.rConstAttenuation) {
+ s = l.rConstAttenuation;
+ } else {
+ s = gglMulAddx(sqDist, l.attenuation[2], l.attenuation[0]);
+ if (l.attenuation[1])
+ s = gglMulAddx(gglSqrtx(sqDist), l.attenuation[1], s);
+ s = gglRecipFast(s);
+ }
+ vscale3(t.v, t.v, s);
+ }
+
+ r.r += t.r;
+ r.g += t.g;
+ r.b += t.b;
+ }
+ }
+ v->color.r = gglClampx(r.r);
+ v->color.g = gglClampx(r.g);
+ v->color.b = gglClampx(r.b);
+ v->color.a = gglClampx(r.a);
+ v->flags |= vertex_t::LIT;
+}
+
+static void lightModelx(GLenum pname, GLfixed param, ogles_context_t* c)
+{
+ if (ggl_unlikely(pname != GL_LIGHT_MODEL_TWO_SIDE)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ c->lighting.lightModel.twoSide = param ? GL_TRUE : GL_FALSE;
+ invalidate_lighting(c);
+}
+
+static void lightx(GLenum i, GLenum pname, GLfixed param, ogles_context_t* c)
+{
+ if (ggl_unlikely(uint32_t(i-GL_LIGHT0) >= OGLES_MAX_LIGHTS)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+
+ light_t& light = c->lighting.lights[i-GL_LIGHT0];
+ const GLfixed kDegToRad = GLfixed((M_PI * gglIntToFixed(1)) / 180.0f);
+ switch (pname) {
+ case GL_SPOT_EXPONENT:
+ if (GGLfixed(param) >= gglIntToFixed(128)) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ light.spotExp = param;
+ break;
+ case GL_SPOT_CUTOFF:
+ if (param!=gglIntToFixed(180) && GGLfixed(param)>=gglIntToFixed(90)) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ light.spotCutoff = param;
+ light.spotCutoffCosine =
+ gglFloatToFixed(cosinef((M_PI/(180.0f*65536.0f))*param));
+ break;
+ case GL_CONSTANT_ATTENUATION:
+ if (param < 0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ light.attenuation[0] = param;
+ break;
+ case GL_LINEAR_ATTENUATION:
+ if (param < 0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ light.attenuation[1] = param;
+ break;
+ case GL_QUADRATIC_ATTENUATION:
+ if (param < 0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ light.attenuation[2] = param;
+ break;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ invalidate_lighting(c);
+}
+
+static void lightxv(GLenum i, GLenum pname, const GLfixed *params, ogles_context_t* c)
+{
+ if (ggl_unlikely(uint32_t(i-GL_LIGHT0) >= OGLES_MAX_LIGHTS)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+
+ GLfixed* what;
+ light_t& light = c->lighting.lights[i-GL_LIGHT0];
+ switch (pname) {
+ case GL_AMBIENT:
+ what = light.ambient.v;
+ break;
+ case GL_DIFFUSE:
+ what = light.diffuse.v;
+ break;
+ case GL_SPECULAR:
+ what = light.specular.v;
+ break;
+ case GL_POSITION: {
+ ogles_validate_transform(c, transform_state_t::MODELVIEW);
+ transform_t& mv = c->transforms.modelview.transform;
+ memcpy(light.position.v, params, sizeof(light.position.v));
+ mv.point4(&mv, &light.position, &light.position);
+ invalidate_lighting(c);
+ return;
+ }
+ case GL_SPOT_DIRECTION: {
+ ogles_validate_transform(c, transform_state_t::MVUI);
+ transform_t& mvui = c->transforms.mvui;
+ mvui.point3(&mvui, &light.spotDir, (vec4_t*)params);
+ vnorm3(light.normalizedSpotDir.v, light.spotDir.v);
+ invalidate_lighting(c);
+ return;
+ }
+ default:
+ lightx(i, pname, params[0], c);
+ return;
+ }
+ what[0] = params[0];
+ what[1] = params[1];
+ what[2] = params[2];
+ what[3] = params[3];
+ invalidate_lighting(c);
+}
+
+static void materialx(GLenum face, GLenum pname, GLfixed param, ogles_context_t* c)
+{
+ if (ggl_unlikely(face != GL_FRONT_AND_BACK)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ if (ggl_unlikely(pname != GL_SHININESS)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ c->lighting.front.shininess = param;
+ invalidate_lighting(c);
+}
+
+static void fogx(GLenum pname, GLfixed param, ogles_context_t* c)
+{
+ switch (pname) {
+ case GL_FOG_DENSITY:
+ if (param >= 0) {
+ c->fog.density = param;
+ break;
+ }
+ ogles_error(c, GL_INVALID_VALUE);
+ break;
+ case GL_FOG_START:
+ c->fog.start = param;
+ c->fog.invEndMinusStart = gglRecip(c->fog.end - c->fog.start);
+ break;
+ case GL_FOG_END:
+ c->fog.end = param;
+ c->fog.invEndMinusStart = gglRecip(c->fog.end - c->fog.start);
+ break;
+ case GL_FOG_MODE:
+ switch (param) {
+ case GL_LINEAR:
+ c->fog.mode = param;
+ c->fog.fog = fog_linear;
+ break;
+ case GL_EXP:
+ c->fog.mode = param;
+ c->fog.fog = fog_exp;
+ break;
+ case GL_EXP2:
+ c->fog.mode = param;
+ c->fog.fog = fog_exp2;
+ break;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ break;
+ }
+ break;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ break;
+ }
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+#if 0
+#pragma mark -
+#pragma mark lighting APIs
+#endif
+
+void glShadeModel(GLenum mode)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (ggl_unlikely(mode != GL_SMOOTH && mode != GL_FLAT)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ c->lighting.shadeModel = mode;
+}
+
+void glLightModelf(GLenum pname, GLfloat param)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ lightModelx(pname, gglFloatToFixed(param), c);
+}
+
+void glLightModelx(GLenum pname, GLfixed param)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ lightModelx(pname, param, c);
+}
+
+void glLightModelfv(GLenum pname, const GLfloat *params)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (pname == GL_LIGHT_MODEL_TWO_SIDE) {
+ lightModelx(pname, gglFloatToFixed(params[0]), c);
+ return;
+ }
+
+ if (ggl_unlikely(pname != GL_LIGHT_MODEL_AMBIENT)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+
+ c->lighting.lightModel.ambient.r = gglFloatToFixed(params[0]);
+ c->lighting.lightModel.ambient.g = gglFloatToFixed(params[1]);
+ c->lighting.lightModel.ambient.b = gglFloatToFixed(params[2]);
+ c->lighting.lightModel.ambient.a = gglFloatToFixed(params[3]);
+ invalidate_lighting(c);
+}
+
+void glLightModelxv(GLenum pname, const GLfixed *params)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (pname == GL_LIGHT_MODEL_TWO_SIDE) {
+ lightModelx(pname, params[0], c);
+ return;
+ }
+
+ if (ggl_unlikely(pname != GL_LIGHT_MODEL_AMBIENT)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+
+ c->lighting.lightModel.ambient.r = params[0];
+ c->lighting.lightModel.ambient.g = params[1];
+ c->lighting.lightModel.ambient.b = params[2];
+ c->lighting.lightModel.ambient.a = params[3];
+ invalidate_lighting(c);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+void glLightf(GLenum i, GLenum pname, GLfloat param)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ lightx(i, pname, gglFloatToFixed(param), c);
+}
+
+void glLightx(GLenum i, GLenum pname, GLfixed param)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ lightx(i, pname, param, c);
+}
+
+void glLightfv(GLenum i, GLenum pname, const GLfloat *params)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ switch (pname) {
+ case GL_SPOT_EXPONENT:
+ case GL_SPOT_CUTOFF:
+ case GL_CONSTANT_ATTENUATION:
+ case GL_LINEAR_ATTENUATION:
+ case GL_QUADRATIC_ATTENUATION:
+ lightx(i, pname, gglFloatToFixed(params[0]), c);
+ return;
+ }
+
+ GLfixed paramsx[4];
+ paramsx[0] = gglFloatToFixed(params[0]);
+ paramsx[1] = gglFloatToFixed(params[1]);
+ paramsx[2] = gglFloatToFixed(params[2]);
+ if (pname != GL_SPOT_DIRECTION)
+ paramsx[3] = gglFloatToFixed(params[3]);
+
+ lightxv(i, pname, paramsx, c);
+}
+
+void glLightxv(GLenum i, GLenum pname, const GLfixed *params)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ lightxv(i, pname, params, c);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+void glMaterialf(GLenum face, GLenum pname, GLfloat param)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ materialx(face, pname, gglFloatToFixed(param), c);
+}
+
+void glMaterialx(GLenum face, GLenum pname, GLfixed param)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ materialx(face, pname, param, c);
+}
+
+void glMaterialfv(
+ GLenum face, GLenum pname, const GLfloat *params)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (ggl_unlikely(face != GL_FRONT_AND_BACK)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ GLfixed* what=0;
+ GLfixed* other=0;
+ switch (pname) {
+ case GL_AMBIENT: what = c->lighting.front.ambient.v; break;
+ case GL_DIFFUSE: what = c->lighting.front.diffuse.v; break;
+ case GL_SPECULAR: what = c->lighting.front.specular.v; break;
+ case GL_EMISSION: what = c->lighting.front.emission.v; break;
+ case GL_AMBIENT_AND_DIFFUSE:
+ what = c->lighting.front.ambient.v; break;
+ other = c->lighting.front.diffuse.v; break;
+ break;
+ case GL_SHININESS:
+ c->lighting.front.shininess = gglFloatToFixed(params[0]);
+ invalidate_lighting(c);
+ return;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ what[0] = gglFloatToFixed(params[0]);
+ what[1] = gglFloatToFixed(params[1]);
+ what[2] = gglFloatToFixed(params[2]);
+ what[3] = gglFloatToFixed(params[3]);
+ if (other) {
+ other[0] = what[0];
+ other[1] = what[1];
+ other[2] = what[2];
+ other[3] = what[3];
+ }
+ invalidate_lighting(c);
+}
+
+void glMaterialxv(
+ GLenum face, GLenum pname, const GLfixed *params)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (ggl_unlikely(face != GL_FRONT_AND_BACK)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ GLfixed* what=0;
+ GLfixed* other=0;
+ switch (pname) {
+ case GL_AMBIENT: what = c->lighting.front.ambient.v; break;
+ case GL_DIFFUSE: what = c->lighting.front.diffuse.v; break;
+ case GL_SPECULAR: what = c->lighting.front.specular.v; break;
+ case GL_EMISSION: what = c->lighting.front.emission.v; break;
+ case GL_AMBIENT_AND_DIFFUSE:
+ what = c->lighting.front.ambient.v; break;
+ other= c->lighting.front.diffuse.v; break;
+ break;
+ case GL_SHININESS:
+ c->lighting.front.shininess = gglFloatToFixed(params[0]);
+ invalidate_lighting(c);
+ return;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ what[0] = params[0];
+ what[1] = params[1];
+ what[2] = params[2];
+ what[3] = params[3];
+ if (other) {
+ other[0] = what[0];
+ other[1] = what[1];
+ other[2] = what[2];
+ other[3] = what[3];
+ }
+ invalidate_lighting(c);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark fog
+#endif
+
+void glFogf(GLenum pname, GLfloat param) {
+ ogles_context_t* c = ogles_context_t::get();
+ GLfixed paramx = (GLfixed)param;
+ if (pname != GL_FOG_MODE)
+ paramx = gglFloatToFixed(param);
+ fogx(pname, paramx, c);
+}
+
+void glFogx(GLenum pname, GLfixed param) {
+ ogles_context_t* c = ogles_context_t::get();
+ fogx(pname, param, c);
+}
+
+void glFogfv(GLenum pname, const GLfloat *params)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (pname != GL_FOG_COLOR) {
+ GLfixed paramx = (GLfixed)params[0];
+ if (pname != GL_FOG_MODE)
+ paramx = gglFloatToFixed(params[0]);
+ fogx(pname, paramx, c);
+ return;
+ }
+ GLfixed paramsx[4];
+ paramsx[0] = gglFloatToFixed(params[0]);
+ paramsx[1] = gglFloatToFixed(params[1]);
+ paramsx[2] = gglFloatToFixed(params[2]);
+ paramsx[3] = gglFloatToFixed(params[3]);
+ c->rasterizer.procs.fogColor3xv(c, paramsx);
+}
+
+void glFogxv(GLenum pname, const GLfixed *params)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (pname != GL_FOG_COLOR) {
+ fogx(pname, params[0], c);
+ return;
+ }
+ c->rasterizer.procs.fogColor3xv(c, params);
+}
diff --git a/opengl/libagl/light.h b/opengl/libagl/light.h
new file mode 100644
index 0000000..6dae25f
--- /dev/null
+++ b/opengl/libagl/light.h
@@ -0,0 +1,38 @@
+/* libs/opengles/light.h
+**
+** 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.
+*/
+
+#ifndef ANDROID_OPENGLES_LIGHT_H
+#define ANDROID_OPENGLES_LIGHT_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+namespace android {
+
+namespace gl {
+struct ogles_context_t;
+};
+
+void ogles_init_light(ogles_context_t* c);
+void ogles_uninit_light(ogles_context_t* c);
+void ogles_invalidate_lighting_mvui(ogles_context_t* c);
+
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_LIGHT_H
+
diff --git a/opengl/libagl/matrix.cpp b/opengl/libagl/matrix.cpp
new file mode 100644
index 0000000..f175cda
--- /dev/null
+++ b/opengl/libagl/matrix.cpp
@@ -0,0 +1,1145 @@
+/* libs/opengles/matrix.cpp
+**
+** 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"
+
+#if defined(__arm__) && defined(__thumb__)
+#warning "matrix.cpp should not be compiled in thumb on ARM."
+#endif
+
+#define I(_i, _j) ((_j)+ 4*(_i))
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static const GLfloat gIdentityf[16] = { 1,0,0,0,
+ 0,1,0,0,
+ 0,0,1,0,
+ 0,0,0,1 };
+
+static const matrixx_t gIdentityx = {
+ { 0x10000,0,0,0,
+ 0,0x10000,0,0,
+ 0,0,0x10000,0,
+ 0,0,0,0x10000
+ }
+ };
+
+static void point2__nop(transform_t const*, vec4_t* c, vec4_t const* o);
+static void point3__nop(transform_t const*, vec4_t* c, vec4_t const* o);
+static void point4__nop(transform_t const*, vec4_t* c, vec4_t const* o);
+static void normal__nop(transform_t const*, vec4_t* c, vec4_t const* o);
+static void point2__generic(transform_t const*, vec4_t* c, vec4_t const* o);
+static void point3__generic(transform_t const*, vec4_t* c, vec4_t const* o);
+static void point4__generic(transform_t const*, vec4_t* c, vec4_t const* o);
+static void normal__generic(transform_t const*, vec4_t* c, vec4_t const* o);
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+void ogles_init_matrix(ogles_context_t* c)
+{
+ c->transforms.modelview.init(OGLES_MODELVIEW_STACK_DEPTH);
+ c->transforms.projection.init(OGLES_PROJECTION_STACK_DEPTH);
+ for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++)
+ c->transforms.texture[i].init(OGLES_TEXTURE_STACK_DEPTH);
+
+ c->transforms.current = &c->transforms.modelview;
+ c->transforms.matrixMode = GL_MODELVIEW;
+ c->transforms.dirty = transform_state_t::VIEWPORT |
+ transform_state_t::MVUI |
+ transform_state_t::MVIT |
+ transform_state_t::MVP;
+ c->transforms.mvp.loadIdentity();
+ c->transforms.mvp4.loadIdentity();
+ c->transforms.mvit4.loadIdentity();
+ c->transforms.mvui.loadIdentity();
+ c->transforms.vpt.loadIdentity();
+ c->transforms.vpt.zNear = 0.0f;
+ c->transforms.vpt.zFar = 1.0f;
+}
+
+void ogles_uninit_matrix(ogles_context_t* c)
+{
+ c->transforms.modelview.uninit();
+ c->transforms.projection.uninit();
+ for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++)
+ c->transforms.texture[i].uninit();
+}
+
+static void validate_perspective(ogles_context_t* c, vertex_t* v)
+{
+ const uint32_t enables = c->rasterizer.state.enables;
+ c->arrays.perspective = (c->clipPlanes.enable) ?
+ ogles_vertex_clipAllPerspective3D : ogles_vertex_perspective3D;
+ if (enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)) {
+ c->arrays.perspective = ogles_vertex_perspective3DZ;
+ if (c->clipPlanes.enable || (enables&GGL_ENABLE_FOG))
+ c->arrays.perspective = ogles_vertex_clipAllPerspective3DZ;
+ }
+ if ((c->arrays.vertex.size != 4) &&
+ (c->transforms.mvp4.flags & transform_t::FLAGS_2D_PROJECTION)) {
+ c->arrays.perspective = ogles_vertex_perspective2D;
+ }
+ c->arrays.perspective(c, v);
+}
+
+void ogles_invalidate_perspective(ogles_context_t* c)
+{
+ c->arrays.perspective = validate_perspective;
+}
+
+void ogles_validate_transform_impl(ogles_context_t* c, uint32_t want)
+{
+ int dirty = c->transforms.dirty & want;
+
+ // Validate the modelview
+ if (dirty & transform_state_t::MODELVIEW) {
+ c->transforms.modelview.validate();
+ }
+
+ // Validate the projection stack (in fact, it's never needed)
+ if (dirty & transform_state_t::PROJECTION) {
+ c->transforms.projection.validate();
+ }
+
+ // Validate the viewport transformation
+ if (dirty & transform_state_t::VIEWPORT) {
+ vp_transform_t& vpt = c->transforms.vpt;
+ vpt.transform.matrix.load(vpt.matrix);
+ vpt.transform.picker();
+ }
+
+ // We need to update the mvp (used to transform each vertex)
+ if (dirty & transform_state_t::MVP) {
+ c->transforms.update_mvp();
+ // invalidate perspective (divide by W) and view volume clipping
+ ogles_invalidate_perspective(c);
+ }
+
+ // Validate the mvui (for normal transformation)
+ if (dirty & transform_state_t::MVUI) {
+ c->transforms.update_mvui();
+ ogles_invalidate_lighting_mvui(c);
+ }
+
+ // Validate the texture stack
+ if (dirty & transform_state_t::TEXTURE) {
+ for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++)
+ c->transforms.texture[i].validate();
+ }
+
+ // Validate the mvit4 (user-clip planes)
+ if (dirty & transform_state_t::MVIT) {
+ c->transforms.update_mvit();
+ }
+
+ c->transforms.dirty &= ~want;
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark transform_t
+#endif
+
+void transform_t::loadIdentity() {
+ matrix = gIdentityx;
+ flags = 0;
+ ops = OP_IDENTITY;
+ point2 = point2__nop;
+ point3 = point3__nop;
+ point4 = point4__nop;
+}
+
+
+static inline
+int notZero(GLfixed v) {
+ return abs(v) & ~0x3;
+}
+
+static inline
+int notOne(GLfixed v) {
+ return notZero(v - 0x10000);
+}
+
+void transform_t::picker()
+{
+ const GLfixed* const m = matrix.m;
+
+ // XXX: picker needs to be smarter
+ flags = 0;
+ ops = OP_ALL;
+ point2 = point2__generic;
+ point3 = point3__generic;
+ point4 = point4__generic;
+
+ // find out if this is a 2D projection
+ if (!(notZero(m[3]) | notZero(m[7]) | notZero(m[11]) | notOne(m[15]))) {
+ flags |= FLAGS_2D_PROJECTION;
+ }
+}
+
+void mvui_transform_t::picker()
+{
+ flags = 0;
+ ops = OP_ALL;
+ point3 = normal__generic;
+}
+
+void transform_t::dump(const char* what)
+{
+ GLfixed const * const m = matrix.m;
+ LOGD("%s:", what);
+ for (int i=0 ; i<4 ; i++)
+ LOGD("[%08x %08x %08x %08x] [%f %f %f %f]\n",
+ m[I(0,i)], m[I(1,i)], m[I(2,i)], m[I(3,i)],
+ fixedToFloat(m[I(0,i)]),
+ fixedToFloat(m[I(1,i)]),
+ fixedToFloat(m[I(2,i)]),
+ fixedToFloat(m[I(3,i)]));
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark matrixx_t
+#endif
+
+void matrixx_t::load(const matrixf_t& rhs) {
+ GLfixed* xp = m;
+ GLfloat const* fp = rhs.elements();
+ unsigned int i = 16;
+ do {
+ const GLfloat f = *fp++;
+ *xp++ = isZerof(f) ? 0 : gglFloatToFixed(f);
+ } while (--i);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark matrixf_t
+#endif
+
+void matrixf_t::multiply(matrixf_t& r, const matrixf_t& lhs, const matrixf_t& rhs)
+{
+ GLfloat const* const m = lhs.m;
+ for (int i=0 ; i<4 ; i++) {
+ register const float rhs_i0 = rhs.m[ I(i,0) ];
+ register float ri0 = m[ I(0,0) ] * rhs_i0;
+ register float ri1 = m[ I(0,1) ] * rhs_i0;
+ register float ri2 = m[ I(0,2) ] * rhs_i0;
+ register float ri3 = m[ I(0,3) ] * rhs_i0;
+ for (int j=1 ; j<4 ; j++) {
+ register const float rhs_ij = rhs.m[ I(i,j) ];
+ ri0 += m[ I(j,0) ] * rhs_ij;
+ ri1 += m[ I(j,1) ] * rhs_ij;
+ ri2 += m[ I(j,2) ] * rhs_ij;
+ ri3 += m[ I(j,3) ] * rhs_ij;
+ }
+ r.m[ I(i,0) ] = ri0;
+ r.m[ I(i,1) ] = ri1;
+ r.m[ I(i,2) ] = ri2;
+ r.m[ I(i,3) ] = ri3;
+ }
+}
+
+void matrixf_t::dump(const char* what) {
+ LOGD("%s", what);
+ LOGD("[ %9f %9f %9f %9f ]", m[I(0,0)], m[I(1,0)], m[I(2,0)], m[I(3,0)]);
+ LOGD("[ %9f %9f %9f %9f ]", m[I(0,1)], m[I(1,1)], m[I(2,1)], m[I(3,1)]);
+ LOGD("[ %9f %9f %9f %9f ]", m[I(0,2)], m[I(1,2)], m[I(2,2)], m[I(3,2)]);
+ LOGD("[ %9f %9f %9f %9f ]", m[I(0,3)], m[I(1,3)], m[I(2,3)], m[I(3,3)]);
+}
+
+void matrixf_t::loadIdentity() {
+ memcpy(m, gIdentityf, sizeof(m));
+}
+
+void matrixf_t::set(const GLfixed* rhs) {
+ load(rhs);
+}
+
+void matrixf_t::set(const GLfloat* rhs) {
+ load(rhs);
+}
+
+void matrixf_t::load(const GLfixed* rhs) {
+ GLfloat* fp = m;
+ unsigned int i = 16;
+ do {
+ *fp++ = fixedToFloat(*rhs++);
+ } while (--i);
+}
+
+void matrixf_t::load(const GLfloat* rhs) {
+ memcpy(m, rhs, sizeof(m));
+}
+
+void matrixf_t::load(const matrixf_t& rhs) {
+ operator = (rhs);
+}
+
+void matrixf_t::multiply(const matrixf_t& rhs) {
+ matrixf_t r;
+ multiply(r, *this, rhs);
+ operator = (r);
+}
+
+void matrixf_t::translate(GLfloat x, GLfloat y, GLfloat z) {
+ for (int i=0 ; i<4 ; i++) {
+ m[12+i] += m[i]*x + m[4+i]*y + m[8+i]*z;
+ }
+}
+
+void matrixf_t::scale(GLfloat x, GLfloat y, GLfloat z) {
+ for (int i=0 ; i<4 ; i++) {
+ m[ i] *= x;
+ m[4+i] *= y;
+ m[8+i] *= z;
+ }
+}
+
+void matrixf_t::rotate(GLfloat a, GLfloat x, GLfloat y, GLfloat z)
+{
+ matrixf_t rotation;
+ GLfloat* r = rotation.m;
+ GLfloat c, s;
+ r[3] = 0; r[7] = 0; r[11]= 0;
+ r[12]= 0; r[13]= 0; r[14]= 0; r[15]= 1;
+ a *= GLfloat(M_PI / 180.0f);
+ sincosf(a, &s, &c);
+ if (isOnef(x) && isZerof(y) && isZerof(z)) {
+ r[5] = c; r[10]= c;
+ r[6] = s; r[9] = -s;
+ r[1] = 0; r[2] = 0;
+ r[4] = 0; r[8] = 0;
+ r[0] = 1;
+ } else if (isZerof(x) && isOnef(y) && isZerof(z)) {
+ r[0] = c; r[10]= c;
+ r[8] = s; r[2] = -s;
+ r[1] = 0; r[4] = 0;
+ r[6] = 0; r[9] = 0;
+ r[5] = 1;
+ } else if (isZerof(x) && isZerof(y) && isOnef(z)) {
+ r[0] = c; r[5] = c;
+ r[1] = s; r[4] = -s;
+ r[2] = 0; r[6] = 0;
+ r[8] = 0; r[9] = 0;
+ r[10]= 1;
+ } else {
+ const GLfloat len = sqrtf(x*x + y*y + z*z);
+ if (!isOnef(len)) {
+ const GLfloat recipLen = reciprocalf(len);
+ x *= recipLen;
+ y *= recipLen;
+ z *= recipLen;
+ }
+ const GLfloat nc = 1.0f - c;
+ const GLfloat xy = x * y;
+ const GLfloat yz = y * z;
+ const GLfloat zx = z * x;
+ const GLfloat xs = x * s;
+ const GLfloat ys = y * s;
+ const GLfloat zs = z * s;
+ r[ 0] = x*x*nc + c; r[ 4] = xy*nc - zs; r[ 8] = zx*nc + ys;
+ r[ 1] = xy*nc + zs; r[ 5] = y*y*nc + c; r[ 9] = yz*nc - xs;
+ r[ 2] = zx*nc - ys; r[ 6] = yz*nc + xs; r[10] = z*z*nc + c;
+ }
+ multiply(rotation);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark matrix_stack_t
+#endif
+
+void matrix_stack_t::init(int depth) {
+ stack = new matrixf_t[depth];
+ ops = new uint8_t[depth];
+ maxDepth = depth;
+ depth = 0;
+ dirty = 0;
+ loadIdentity();
+}
+
+void matrix_stack_t::uninit() {
+ delete [] stack;
+ delete [] ops;
+}
+
+void matrix_stack_t::loadIdentity() {
+ transform.loadIdentity();
+ stack[depth].loadIdentity();
+ ops[depth] = OP_IDENTITY;
+}
+
+void matrix_stack_t::load(const GLfixed* rhs)
+{
+ memcpy(transform.matrix.m, rhs, sizeof(transform.matrix.m));
+ stack[depth].load(rhs);
+ ops[depth] = OP_ALL; // TODO: we should look at the matrix
+}
+
+void matrix_stack_t::load(const GLfloat* rhs)
+{
+ stack[depth].load(rhs);
+ ops[depth] = OP_ALL; // TODO: we should look at the matrix
+}
+
+void matrix_stack_t::multiply(const matrixf_t& rhs)
+{
+ stack[depth].multiply(rhs);
+ ops[depth] = OP_ALL; // TODO: we should look at the matrix
+}
+
+void matrix_stack_t::translate(GLfloat x, GLfloat y, GLfloat z)
+{
+ stack[depth].translate(x,y,z);
+ ops[depth] |= OP_TRANSLATE;
+}
+
+void matrix_stack_t::scale(GLfloat x, GLfloat y, GLfloat z)
+{
+ stack[depth].scale(x,y,z);
+ if (x==y && y==z) {
+ ops[depth] |= OP_UNIFORM_SCALE;
+ } else {
+ ops[depth] |= OP_SCALE;
+ }
+}
+
+void matrix_stack_t::rotate(GLfloat a, GLfloat x, GLfloat y, GLfloat z)
+{
+ stack[depth].rotate(a,x,y,z);
+ ops[depth] |= OP_ROTATE;
+}
+
+void matrix_stack_t::validate()
+{
+ if (dirty & DO_FLOAT_TO_FIXED) {
+ transform.matrix.load(top());
+ }
+ if (dirty & DO_PICKER) {
+ transform.picker();
+ }
+ dirty = 0;
+}
+
+GLint matrix_stack_t::push()
+{
+ if (depth >= (maxDepth-1)) {
+ return GL_STACK_OVERFLOW;
+ }
+ stack[depth+1] = stack[depth];
+ ops[depth+1] = ops[depth];
+ depth++;
+ return 0;
+}
+
+GLint matrix_stack_t::pop()
+{
+ if (depth == 0) {
+ return GL_STACK_UNDERFLOW;
+ }
+ depth--;
+ return 0;
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark vp_transform_t
+#endif
+
+void vp_transform_t::loadIdentity() {
+ transform.loadIdentity();
+ matrix.loadIdentity();
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark transform_state_t
+#endif
+
+void transform_state_t::invalidate()
+{
+ switch (matrixMode) {
+ case GL_MODELVIEW: dirty |= MODELVIEW | MVP | MVUI | MVIT; break;
+ case GL_PROJECTION: dirty |= PROJECTION | MVP; break;
+ case GL_TEXTURE: dirty |= TEXTURE | MVP; break;
+ }
+ current->dirty = matrix_stack_t::DO_PICKER |
+ matrix_stack_t::DO_FLOAT_TO_FIXED;
+}
+
+void transform_state_t::update_mvp()
+{
+ matrixf_t temp_mvp;
+ matrixf_t::multiply(temp_mvp, projection.top(), modelview.top());
+ mvp4.matrix.load(temp_mvp);
+ mvp4.picker();
+
+ if (mvp4.flags & transform_t::FLAGS_2D_PROJECTION) {
+ // the mvp matrix doesn't transform W, in this case we can
+ // premultiply it with the viewport transformation. In addition to
+ // being more efficient, this is also much more accurate and in fact
+ // is needed for 2D drawing with a resulting 1:1 mapping.
+ matrixf_t mvpv;
+ matrixf_t::multiply(mvpv, vpt.matrix, temp_mvp);
+ mvp.matrix.load(mvpv);
+ mvp.picker();
+ } else {
+ mvp = mvp4;
+ }
+}
+
+static inline
+GLfloat det22(GLfloat a, GLfloat b, GLfloat c, GLfloat d) {
+ return a*d - b*c;
+}
+
+static inline
+GLfloat ndet22(GLfloat a, GLfloat b, GLfloat c, GLfloat d) {
+ return b*c - a*d;
+}
+
+static __attribute__((noinline))
+void invert(GLfloat* inverse, const GLfloat* src)
+{
+ double t;
+ int i, j, k, swap;
+ GLfloat tmp[4][4];
+
+ memcpy(inverse, gIdentityf, sizeof(gIdentityf));
+ memcpy(tmp, src, sizeof(GLfloat)*16);
+
+ for (i = 0; i < 4; i++) {
+ // look for largest element in column
+ swap = i;
+ for (j = i + 1; j < 4; j++) {
+ if (fabs(tmp[j][i]) > fabs(tmp[i][i])) {
+ swap = j;
+ }
+ }
+
+ if (swap != i) {
+ /* swap rows. */
+ for (k = 0; k < 4; k++) {
+ t = tmp[i][k];
+ tmp[i][k] = tmp[swap][k];
+ tmp[swap][k] = t;
+
+ t = inverse[i*4+k];
+ inverse[i*4+k] = inverse[swap*4+k];
+ inverse[swap*4+k] = t;
+ }
+ }
+
+ t = 1.0f / tmp[i][i];
+ for (k = 0; k < 4; k++) {
+ tmp[i][k] *= t;
+ inverse[i*4+k] *= t;
+ }
+ for (j = 0; j < 4; j++) {
+ if (j != i) {
+ t = tmp[j][i];
+ for (k = 0; k < 4; k++) {
+ tmp[j][k] -= tmp[i][k]*t;
+ inverse[j*4+k] -= inverse[i*4+k]*t;
+ }
+ }
+ }
+ }
+}
+
+void transform_state_t::update_mvit()
+{
+ GLfloat r[16];
+ const GLfloat* const mv = modelview.top().elements();
+ invert(r, mv);
+ // convert to fixed-point and transpose
+ GLfixed* const x = mvit4.matrix.m;
+ for (int i=0 ; i<4 ; i++)
+ for (int j=0 ; j<4 ; j++)
+ x[I(i,j)] = gglFloatToFixed(r[I(j,i)]);
+ mvit4.picker();
+}
+
+void transform_state_t::update_mvui()
+{
+ const GLfloat* const mv = modelview.top().elements();
+
+ /*
+ When transforming normals, we can use the upper 3x3 matrix, see:
+ http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node26.html
+ */
+
+ // Also note that:
+ // l(obj) = tr(M).l(eye) for infinite light
+ // l(obj) = inv(M).l(eye) for local light
+
+ const uint32_t ops = modelview.top_ops() & ~OP_TRANSLATE;
+ if (ggl_likely((!(ops & ~OP_ROTATE)) ||
+ (rescaleNormals && modelview.isRigidBody()))) {
+ // if the modelview matrix is a rigid body transformation
+ // (translation, rotation, uniform scaling), then we can bypass
+ // the inverse by transposing the matrix.
+ GLfloat rescale = 1.0f;
+ if (rescaleNormals == GL_RESCALE_NORMAL) {
+ if (!(ops & ~OP_UNIFORM_SCALE)) {
+ rescale = reciprocalf(mv[I(0,0)]);
+ } else {
+ rescale = rsqrtf(
+ sqrf(mv[I(2,0)]) + sqrf(mv[I(2,1)]) + sqrf(mv[I(2,2)]));
+ }
+ }
+ GLfixed* const x = mvui.matrix.m;
+ for (int i=0 ; i<3 ; i++) {
+ x[I(i,0)] = gglFloatToFixed(mv[I(0,i)] * rescale);
+ x[I(i,1)] = gglFloatToFixed(mv[I(1,i)] * rescale);
+ x[I(i,2)] = gglFloatToFixed(mv[I(2,i)] * rescale);
+ }
+ mvui.picker();
+ return;
+ }
+
+ GLfloat r[3][3];
+ r[0][0] = det22(mv[I(1,1)], mv[I(2,1)], mv[I(1,2)], mv[I(2,2)]);
+ r[0][1] =ndet22(mv[I(0,1)], mv[I(2,1)], mv[I(0,2)], mv[I(2,2)]);
+ r[0][2] = det22(mv[I(0,1)], mv[I(1,1)], mv[I(0,2)], mv[I(1,2)]);
+ r[1][0] =ndet22(mv[I(1,0)], mv[I(2,0)], mv[I(1,2)], mv[I(2,2)]);
+ r[1][1] = det22(mv[I(0,0)], mv[I(2,0)], mv[I(0,2)], mv[I(2,2)]);
+ r[1][2] =ndet22(mv[I(0,0)], mv[I(1,0)], mv[I(0,2)], mv[I(1,2)]);
+ r[2][0] = det22(mv[I(1,0)], mv[I(2,0)], mv[I(1,1)], mv[I(2,1)]);
+ r[2][1] =ndet22(mv[I(0,0)], mv[I(2,0)], mv[I(0,1)], mv[I(2,1)]);
+ r[2][2] = det22(mv[I(0,0)], mv[I(1,0)], mv[I(0,1)], mv[I(1,1)]);
+
+ GLfloat rdet;
+ if (rescaleNormals == GL_RESCALE_NORMAL) {
+ rdet = rsqrtf(sqrf(r[0][2]) + sqrf(r[1][2]) + sqrf(r[2][2]));
+ } else {
+ rdet = reciprocalf(
+ r[0][0]*mv[I(0,0)] + r[0][1]*mv[I(1,0)] + r[0][2]*mv[I(2,0)]);
+ }
+
+ GLfixed* const x = mvui.matrix.m;
+ for (int i=0 ; i<3 ; i++) {
+ x[I(i,0)] = gglFloatToFixed(r[i][0] * rdet);
+ x[I(i,1)] = gglFloatToFixed(r[i][1] * rdet);
+ x[I(i,2)] = gglFloatToFixed(r[i][2] * rdet);
+ }
+ mvui.picker();
+}
+
+
+// ----------------------------------------------------------------------------
+// transformation and matrices API
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark transformation and matrices API
+#endif
+
+int ogles_surfaceport(ogles_context_t* c, GLint x, GLint y)
+{
+ c->viewport.surfaceport.x = x;
+ c->viewport.surfaceport.y = y;
+
+ ogles_viewport(c,
+ c->viewport.x,
+ c->viewport.y,
+ c->viewport.w,
+ c->viewport.h);
+
+ ogles_scissor(c,
+ c->viewport.scissor.x,
+ c->viewport.scissor.y,
+ c->viewport.scissor.w,
+ c->viewport.scissor.h);
+
+ return 0;
+}
+
+void ogles_scissor(ogles_context_t* c,
+ GLint x, GLint y, GLsizei w, GLsizei h)
+{
+ if ((w|h) < 0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ c->viewport.scissor.x = x;
+ c->viewport.scissor.y = y;
+ c->viewport.scissor.w = w;
+ c->viewport.scissor.h = h;
+
+ x += c->viewport.surfaceport.x;
+ y += c->viewport.surfaceport.y;
+
+ y = c->rasterizer.state.buffers.color.height - (y + h);
+ c->rasterizer.procs.scissor(c, x, y, w, h);
+}
+
+void ogles_viewport(ogles_context_t* c,
+ GLint x, GLint y, GLsizei w, GLsizei h)
+{
+ if ((w|h)<0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+
+ c->viewport.x = x;
+ c->viewport.y = y;
+ c->viewport.w = w;
+ c->viewport.h = h;
+
+ x += c->viewport.surfaceport.x;
+ y += c->viewport.surfaceport.y;
+
+ GLint H = c->rasterizer.state.buffers.color.height;
+ GLfloat sx = div2f(w);
+ GLfloat ox = sx + x;
+ GLfloat sy = div2f(h);
+ GLfloat oy = sy - y + (H - h);
+
+ GLfloat near = c->transforms.vpt.zNear;
+ GLfloat far = c->transforms.vpt.zFar;
+ GLfloat A = div2f(far - near);
+ GLfloat B = div2f(far + near);
+
+ // compute viewport matrix
+ GLfloat* const f = c->transforms.vpt.matrix.editElements();
+ f[0] = sx; f[4] = 0; f[ 8] = 0; f[12] = ox;
+ f[1] = 0; f[5] =-sy; f[ 9] = 0; f[13] = oy;
+ f[2] = 0; f[6] = 0; f[10] = A; f[14] = B;
+ f[3] = 0; f[7] = 0; f[11] = 0; f[15] = 1;
+ c->transforms.dirty |= transform_state_t::VIEWPORT;
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark matrix * vertex
+#endif
+
+void point2__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) {
+ const GLfixed* const m = mx->matrix.m;
+ const GLfixed rx = rhs->x;
+ const GLfixed ry = rhs->y;
+ lhs->x = mla2a(rx, m[ 0], ry, m[ 4], m[12]);
+ lhs->y = mla2a(rx, m[ 1], ry, m[ 5], m[13]);
+ lhs->z = mla2a(rx, m[ 2], ry, m[ 6], m[14]);
+ lhs->w = mla2a(rx, m[ 3], ry, m[ 7], m[15]);
+}
+
+void point3__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) {
+ const GLfixed* const m = mx->matrix.m;
+ const GLfixed rx = rhs->x;
+ const GLfixed ry = rhs->y;
+ const GLfixed rz = rhs->z;
+ lhs->x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]);
+ lhs->y = mla3a(rx, m[ 1], ry, m[ 5], rz, m[ 9], m[13]);
+ lhs->z = mla3a(rx, m[ 2], ry, m[ 6], rz, m[10], m[14]);
+ lhs->w = mla3a(rx, m[ 3], ry, m[ 7], rz, m[11], m[15]);
+}
+
+void point4__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) {
+ const GLfixed* const m = mx->matrix.m;
+ const GLfixed rx = rhs->x;
+ const GLfixed ry = rhs->y;
+ const GLfixed rz = rhs->z;
+ const GLfixed rw = rhs->w;
+ lhs->x = mla4(rx, m[ 0], ry, m[ 4], rz, m[ 8], rw, m[12]);
+ lhs->y = mla4(rx, m[ 1], ry, m[ 5], rz, m[ 9], rw, m[13]);
+ lhs->z = mla4(rx, m[ 2], ry, m[ 6], rz, m[10], rw, m[14]);
+ lhs->w = mla4(rx, m[ 3], ry, m[ 7], rz, m[11], rw, m[15]);
+}
+
+void normal__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) {
+ const GLfixed* const m = mx->matrix.m;
+ const GLfixed rx = rhs->x;
+ const GLfixed ry = rhs->y;
+ const GLfixed rz = rhs->z;
+ lhs->x = mla3(rx, m[ 0], ry, m[ 4], rz, m[ 8]);
+ lhs->y = mla3(rx, m[ 1], ry, m[ 5], rz, m[ 9]);
+ lhs->z = mla3(rx, m[ 2], ry, m[ 6], rz, m[10]);
+}
+
+
+void point2__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) {
+ lhs->z = 0;
+ lhs->w = 0x10000;
+ if (lhs != rhs) {
+ lhs->x = rhs->x;
+ lhs->y = rhs->y;
+ }
+}
+
+void point3__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) {
+ lhs->w = 0x10000;
+ if (lhs != rhs) {
+ lhs->x = rhs->x;
+ lhs->y = rhs->y;
+ lhs->z = rhs->z;
+ }
+}
+
+void point4__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) {
+ if (lhs != rhs)
+ *lhs = *rhs;
+}
+
+
+static void frustumf(
+ GLfloat left, GLfloat right,
+ GLfloat bottom, GLfloat top,
+ GLfloat zNear, GLfloat zFar,
+ ogles_context_t* c)
+ {
+ if (cmpf(left,right) ||
+ cmpf(top, bottom) ||
+ cmpf(zNear, zFar) ||
+ isZeroOrNegativef(zNear) ||
+ isZeroOrNegativef(zFar))
+ {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ const GLfloat r_width = reciprocalf(right - left);
+ const GLfloat r_height = reciprocalf(top - bottom);
+ const GLfloat r_depth = reciprocalf(zNear - zFar);
+ const GLfloat x = mul2f(zNear * r_width);
+ const GLfloat y = mul2f(zNear * r_height);
+ const GLfloat A = mul2f((right + left) * r_width);
+ const GLfloat B = (top + bottom) * r_height;
+ const GLfloat C = (zFar + zNear) * r_depth;
+ const GLfloat D = mul2f(zFar * zNear * r_depth);
+ GLfloat f[16];
+ f[ 0] = x;
+ f[ 5] = y;
+ f[ 8] = A;
+ f[ 9] = B;
+ f[10] = C;
+ f[14] = D;
+ f[11] = -1.0f;
+ f[ 1] = f[ 2] = f[ 3] =
+ f[ 4] = f[ 6] = f[ 7] =
+ f[12] = f[13] = f[15] = 0.0f;
+
+ matrixf_t rhs;
+ rhs.set(f);
+ c->transforms.current->multiply(rhs);
+ c->transforms.invalidate();
+}
+
+static void orthof(
+ GLfloat left, GLfloat right,
+ GLfloat bottom, GLfloat top,
+ GLfloat zNear, GLfloat zFar,
+ ogles_context_t* c)
+{
+ if (cmpf(left,right) ||
+ cmpf(top, bottom) ||
+ cmpf(zNear, zFar))
+ {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ const GLfloat r_width = reciprocalf(right - left);
+ const GLfloat r_height = reciprocalf(top - bottom);
+ const GLfloat r_depth = reciprocalf(zFar - zNear);
+ const GLfloat x = mul2f(r_width);
+ const GLfloat y = mul2f(r_height);
+ const GLfloat z = -mul2f(r_depth);
+ const GLfloat tx = -(right + left) * r_width;
+ const GLfloat ty = -(top + bottom) * r_height;
+ const GLfloat tz = -(zFar + zNear) * r_depth;
+ GLfloat f[16];
+ f[ 0] = x;
+ f[ 5] = y;
+ f[10] = z;
+ f[12] = tx;
+ f[13] = ty;
+ f[14] = tz;
+ f[15] = 1.0f;
+ f[ 1] = f[ 2] = f[ 3] =
+ f[ 4] = f[ 6] = f[ 7] =
+ f[ 8] = f[ 9] = f[11] = 0.0f;
+ matrixf_t rhs;
+ rhs.set(f);
+ c->transforms.current->multiply(rhs);
+ c->transforms.invalidate();
+}
+
+static void depthRangef(GLclampf zNear, GLclampf zFar, ogles_context_t* c)
+{
+ zNear = clampToZerof(zNear > 1 ? 1 : zNear);
+ zFar = clampToZerof(zFar > 1 ? 1 : zFar);
+ GLfloat* const f = c->transforms.vpt.matrix.editElements();
+ f[10] = div2f(zFar - zNear);
+ f[14] = div2f(zFar + zNear);
+ c->transforms.dirty |= transform_state_t::VIEWPORT;
+ c->transforms.vpt.zNear = zNear;
+ c->transforms.vpt.zFar = zFar;
+}
+
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+using namespace android;
+
+void glMatrixMode(GLenum mode)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ matrix_stack_t* stack = 0;
+ switch (mode) {
+ case GL_MODELVIEW:
+ stack = &c->transforms.modelview;
+ break;
+ case GL_PROJECTION:
+ stack = &c->transforms.projection;
+ break;
+ case GL_TEXTURE:
+ stack = &c->transforms.texture[c->textures.active];
+ break;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ c->transforms.matrixMode = mode;
+ c->transforms.current = stack;
+}
+
+void glLoadIdentity()
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->transforms.current->loadIdentity(); // also loads the GLfixed transform
+ c->transforms.invalidate();
+ c->transforms.current->dirty = 0;
+}
+
+void glLoadMatrixf(const GLfloat* m)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->transforms.current->load(m);
+ c->transforms.invalidate();
+}
+
+void glLoadMatrixx(const GLfixed* m)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->transforms.current->load(m); // also loads the GLfixed transform
+ c->transforms.invalidate();
+ c->transforms.current->dirty &= ~matrix_stack_t::DO_FLOAT_TO_FIXED;
+}
+
+void glMultMatrixf(const GLfloat* m)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ matrixf_t rhs;
+ rhs.set(m);
+ c->transforms.current->multiply(rhs);
+ c->transforms.invalidate();
+}
+
+void glMultMatrixx(const GLfixed* m)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ matrixf_t rhs;
+ rhs.set(m);
+ c->transforms.current->multiply(rhs);
+ c->transforms.invalidate();
+}
+
+void glPopMatrix()
+{
+ ogles_context_t* c = ogles_context_t::get();
+ GLint err = c->transforms.current->pop();
+ if (ggl_unlikely(err)) {
+ ogles_error(c, err);
+ return;
+ }
+ c->transforms.invalidate();
+}
+
+void glPushMatrix()
+{
+ ogles_context_t* c = ogles_context_t::get();
+ GLint err = c->transforms.current->push();
+ if (ggl_unlikely(err)) {
+ ogles_error(c, err);
+ return;
+ }
+ c->transforms.invalidate();
+}
+
+void glFrustumf(
+ GLfloat left, GLfloat right,
+ GLfloat bottom, GLfloat top,
+ GLfloat zNear, GLfloat zFar)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ frustumf(left, right, bottom, top, zNear, zFar, c);
+}
+
+void glFrustumx(
+ GLfixed left, GLfixed right,
+ GLfixed bottom, GLfixed top,
+ GLfixed zNear, GLfixed zFar)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ frustumf( fixedToFloat(left), fixedToFloat(right),
+ fixedToFloat(bottom), fixedToFloat(top),
+ fixedToFloat(zNear), fixedToFloat(zFar),
+ c);
+}
+
+void glOrthof(
+ GLfloat left, GLfloat right,
+ GLfloat bottom, GLfloat top,
+ GLfloat zNear, GLfloat zFar)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ orthof(left, right, bottom, top, zNear, zFar, c);
+}
+
+void glOrthox(
+ GLfixed left, GLfixed right,
+ GLfixed bottom, GLfixed top,
+ GLfixed zNear, GLfixed zFar)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ orthof( fixedToFloat(left), fixedToFloat(right),
+ fixedToFloat(bottom), fixedToFloat(top),
+ fixedToFloat(zNear), fixedToFloat(zFar),
+ c);
+}
+
+void glRotatef(GLfloat a, GLfloat x, GLfloat y, GLfloat z)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->transforms.current->rotate(a, x, y, z);
+ c->transforms.invalidate();
+}
+
+void glRotatex(GLfixed a, GLfixed x, GLfixed y, GLfixed z)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->transforms.current->rotate(
+ fixedToFloat(a), fixedToFloat(x),
+ fixedToFloat(y), fixedToFloat(z));
+ c->transforms.invalidate();
+}
+
+void glScalef(GLfloat x, GLfloat y, GLfloat z)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->transforms.current->scale(x, y, z);
+ c->transforms.invalidate();
+}
+
+void glScalex(GLfixed x, GLfixed y, GLfixed z)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->transforms.current->scale(
+ fixedToFloat(x), fixedToFloat(y), fixedToFloat(z));
+ c->transforms.invalidate();
+}
+
+void glTranslatef(GLfloat x, GLfloat y, GLfloat z)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->transforms.current->translate(x, y, z);
+ c->transforms.invalidate();
+}
+
+void glTranslatex(GLfixed x, GLfixed y, GLfixed z)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->transforms.current->translate(
+ fixedToFloat(x), fixedToFloat(y), fixedToFloat(z));
+ c->transforms.invalidate();
+}
+
+void glScissor(GLint x, GLint y, GLsizei w, GLsizei h)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ ogles_scissor(c, x, y, w, h);
+}
+
+void glViewport(GLint x, GLint y, GLsizei w, GLsizei h)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ ogles_viewport(c, x, y, w, h);
+}
+
+void glDepthRangef(GLclampf zNear, GLclampf zFar)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ depthRangef(zNear, zFar, c);
+}
+
+void glDepthRangex(GLclampx zNear, GLclampx zFar)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ depthRangef(fixedToFloat(zNear), fixedToFloat(zFar), c);
+}
+
+void glPolygonOffsetx(GLfixed factor, GLfixed units)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->polygonOffset.factor = factor;
+ c->polygonOffset.units = units;
+}
+
+void glPolygonOffset(GLfloat factor, GLfloat units)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->polygonOffset.factor = gglFloatToFixed(factor);
+ c->polygonOffset.units = gglFloatToFixed(units);
+}
+
+GLbitfield glQueryMatrixxOES(GLfixed* m, GLint* e)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ GLbitfield status = 0;
+ GLfloat const* f = c->transforms.current->top().elements();
+ for (int i=0 ; i<16 ; i++) {
+ if (isnan(f[i]) || isinf(f[i])) {
+ status |= 1<<i;
+ continue;
+ }
+ e[i] = exponent(f[i]) - 7;
+ m[i] = mantissa(f[i]);
+ }
+ return status;
+}
diff --git a/opengl/libagl/matrix.h b/opengl/libagl/matrix.h
new file mode 100644
index 0000000..c9a38a9
--- /dev/null
+++ b/opengl/libagl/matrix.h
@@ -0,0 +1,355 @@
+/* libs/opengles/matrix.h
+**
+** 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.
+*/
+
+#ifndef ANDROID_OPENGLES_MATRIX_H
+#define ANDROID_OPENGLES_MATRIX_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <utils/Log.h>
+
+#include <private/pixelflinger/ggl_context.h>
+
+#include <GLES/gl.h>
+
+namespace android {
+
+const int OGLES_MODELVIEW_STACK_DEPTH = 16;
+const int OGLES_PROJECTION_STACK_DEPTH = 2;
+const int OGLES_TEXTURE_STACK_DEPTH = 2;
+
+void ogles_init_matrix(ogles_context_t*);
+void ogles_uninit_matrix(ogles_context_t*);
+void ogles_invalidate_perspective(ogles_context_t* c);
+void ogles_validate_transform_impl(ogles_context_t* c, uint32_t want);
+
+int ogles_surfaceport(ogles_context_t* c, GLint x, GLint y);
+
+void ogles_scissor(ogles_context_t* c,
+ GLint x, GLint y, GLsizei w, GLsizei h);
+
+void ogles_viewport(ogles_context_t* c,
+ GLint x, GLint y, GLsizei w, GLsizei h);
+
+inline void ogles_validate_transform(
+ ogles_context_t* c, uint32_t want)
+{
+ if (c->transforms.dirty & want)
+ ogles_validate_transform_impl(c, want);
+}
+
+// ----------------------------------------------------------------------------
+
+inline
+GLfixed vsquare3(GLfixed a, GLfixed b, GLfixed c)
+{
+#if defined(__arm__) && !defined(__thumb__)
+
+ GLfixed r;
+ int32_t t;
+ asm(
+ "smull %0, %1, %2, %2 \n"
+ "smlal %0, %1, %3, %3 \n"
+ "smlal %0, %1, %4, %4 \n"
+ "movs %0, %0, lsr #16 \n"
+ "adc %0, %0, %1, lsl #16 \n"
+ : "=&r"(r), "=&r"(t)
+ : "%r"(a), "r"(b), "r"(c)
+ : "cc"
+ );
+ return r;
+
+#else
+
+ return (( int64_t(a)*a +
+ int64_t(b)*b +
+ int64_t(c)*c + 0x8000)>>16);
+
+#endif
+}
+
+static inline GLfixed mla2a( GLfixed a0, GLfixed b0,
+ GLfixed a1, GLfixed b1,
+ GLfixed c)
+{
+#if defined(__arm__) && !defined(__thumb__)
+
+ GLfixed r;
+ int32_t t;
+ asm(
+ "smull %0, %1, %2, %3 \n"
+ "smlal %0, %1, %4, %5 \n"
+ "add %0, %6, %0, lsr #16 \n"
+ "add %0, %0, %1, lsl #16 \n"
+ : "=&r"(r), "=&r"(t)
+ : "%r"(a0), "r"(b0),
+ "%r"(a1), "r"(b1),
+ "r"(c)
+ :
+ );
+ return r;
+
+#else
+
+ return (( int64_t(a0)*b0 +
+ int64_t(a1)*b1)>>16) + c;
+
+#endif
+}
+
+static inline GLfixed mla3a( GLfixed a0, GLfixed b0,
+ GLfixed a1, GLfixed b1,
+ GLfixed a2, GLfixed b2,
+ GLfixed c)
+{
+#if defined(__arm__) && !defined(__thumb__)
+
+ GLfixed r;
+ int32_t t;
+ asm(
+ "smull %0, %1, %2, %3 \n"
+ "smlal %0, %1, %4, %5 \n"
+ "smlal %0, %1, %6, %7 \n"
+ "add %0, %8, %0, lsr #16 \n"
+ "add %0, %0, %1, lsl #16 \n"
+ : "=&r"(r), "=&r"(t)
+ : "%r"(a0), "r"(b0),
+ "%r"(a1), "r"(b1),
+ "%r"(a2), "r"(b2),
+ "r"(c)
+ :
+ );
+ return r;
+
+#else
+
+ return (( int64_t(a0)*b0 +
+ int64_t(a1)*b1 +
+ int64_t(a2)*b2)>>16) + c;
+
+#endif
+}
+
+// b0, b1, b2 are signed 16-bit quanities
+// that have been shifted right by 'shift' bits relative to normal
+// S16.16 fixed point
+static inline GLfixed mla3a16( GLfixed a0, int32_t b1b0,
+ GLfixed a1,
+ GLfixed a2, int32_t b2,
+ GLint shift,
+ GLfixed c)
+{
+#if defined(__arm__) && !defined(__thumb__)
+
+ GLfixed r;
+ asm(
+ "smulwb %0, %1, %2 \n"
+ "smlawt %0, %3, %2, %0 \n"
+ "smlawb %0, %4, %5, %0 \n"
+ "add %0, %7, %0, lsl %6 \n"
+ : "=&r"(r)
+ : "r"(a0), "r"(b1b0),
+ "r"(a1),
+ "r"(a2), "r"(b2),
+ "r"(shift),
+ "r"(c)
+ :
+ );
+ return r;
+
+#else
+
+ int32_t accum;
+ int16_t b0 = b1b0 & 0xffff;
+ int16_t b1 = (b1b0 >> 16) & 0xffff;
+ accum = int64_t(a0)*int16_t(b0) >> 16;
+ accum += int64_t(a1)*int16_t(b1) >> 16;
+ accum += int64_t(a2)*int16_t(b2) >> 16;
+ accum = (accum << shift) + c;
+ return accum;
+
+#endif
+}
+
+
+static inline GLfixed mla3a16_btb( GLfixed a0,
+ GLfixed a1,
+ GLfixed a2,
+ int32_t b1b0, int32_t xxb2,
+ GLint shift,
+ GLfixed c)
+{
+#if defined(__arm__) && !defined(__thumb__)
+
+ GLfixed r;
+ asm(
+ "smulwb %0, %1, %4 \n"
+ "smlawt %0, %2, %4, %0 \n"
+ "smlawb %0, %3, %5, %0 \n"
+ "add %0, %7, %0, lsl %6 \n"
+ : "=&r"(r)
+ : "r"(a0),
+ "r"(a1),
+ "r"(a2),
+ "r"(b1b0), "r"(xxb2),
+ "r"(shift),
+ "r"(c)
+ :
+ );
+ return r;
+
+#else
+
+ int32_t accum;
+ int16_t b0 = b1b0 & 0xffff;
+ int16_t b1 = (b1b0 >> 16) & 0xffff;
+ int16_t b2 = xxb2 & 0xffff;
+ accum = int64_t(a0)*int16_t(b0) >> 16;
+ accum += int64_t(a1)*int16_t(b1) >> 16;
+ accum += int64_t(a2)*int16_t(b2) >> 16;
+ accum = (accum << shift) + c;
+ return accum;
+
+#endif
+}
+
+static inline GLfixed mla3a16_btt( GLfixed a0,
+ GLfixed a1,
+ GLfixed a2,
+ int32_t b1b0, int32_t b2xx,
+ GLint shift,
+ GLfixed c)
+{
+#if defined(__arm__) && !defined(__thumb__)
+
+ GLfixed r;
+ asm(
+ "smulwb %0, %1, %4 \n"
+ "smlawt %0, %2, %4, %0 \n"
+ "smlawt %0, %3, %5, %0 \n"
+ "add %0, %7, %0, lsl %6 \n"
+ : "=&r"(r)
+ : "r"(a0),
+ "r"(a1),
+ "r"(a2),
+ "r"(b1b0), "r"(b2xx),
+ "r"(shift),
+ "r"(c)
+ :
+ );
+ return r;
+
+#else
+
+ int32_t accum;
+ int16_t b0 = b1b0 & 0xffff;
+ int16_t b1 = (b1b0 >> 16) & 0xffff;
+ int16_t b2 = (b2xx >> 16) & 0xffff;
+ accum = int64_t(a0)*int16_t(b0) >> 16;
+ accum += int64_t(a1)*int16_t(b1) >> 16;
+ accum += int64_t(a2)*int16_t(b2) >> 16;
+ accum = (accum << shift) + c;
+ return accum;
+
+#endif
+}
+
+static inline GLfixed mla3( GLfixed a0, GLfixed b0,
+ GLfixed a1, GLfixed b1,
+ GLfixed a2, GLfixed b2)
+{
+#if defined(__arm__) && !defined(__thumb__)
+
+ GLfixed r;
+ int32_t t;
+ asm(
+ "smull %0, %1, %2, %3 \n"
+ "smlal %0, %1, %4, %5 \n"
+ "smlal %0, %1, %6, %7 \n"
+ "movs %0, %0, lsr #16 \n"
+ "adc %0, %0, %1, lsl #16 \n"
+ : "=&r"(r), "=&r"(t)
+ : "%r"(a0), "r"(b0),
+ "%r"(a1), "r"(b1),
+ "%r"(a2), "r"(b2)
+ : "cc"
+ );
+ return r;
+
+#else
+
+ return (( int64_t(a0)*b0 +
+ int64_t(a1)*b1 +
+ int64_t(a2)*b2 + 0x8000)>>16);
+
+#endif
+}
+
+static inline GLfixed mla4( GLfixed a0, GLfixed b0,
+ GLfixed a1, GLfixed b1,
+ GLfixed a2, GLfixed b2,
+ GLfixed a3, GLfixed b3)
+{
+#if defined(__arm__) && !defined(__thumb__)
+
+ GLfixed r;
+ int32_t t;
+ asm(
+ "smull %0, %1, %2, %3 \n"
+ "smlal %0, %1, %4, %5 \n"
+ "smlal %0, %1, %6, %7 \n"
+ "smlal %0, %1, %8, %9 \n"
+ "movs %0, %0, lsr #16 \n"
+ "adc %0, %0, %1, lsl #16 \n"
+ : "=&r"(r), "=&r"(t)
+ : "%r"(a0), "r"(b0),
+ "%r"(a1), "r"(b1),
+ "%r"(a2), "r"(b2),
+ "%r"(a3), "r"(b3)
+ : "cc"
+ );
+ return r;
+
+#else
+
+ return (( int64_t(a0)*b0 +
+ int64_t(a1)*b1 +
+ int64_t(a2)*b2 +
+ int64_t(a3)*b3 + 0x8000)>>16);
+
+#endif
+}
+
+inline
+GLfixed dot4(const GLfixed* a, const GLfixed* b)
+{
+ return mla4(a[0], b[0], a[1], b[1], a[2], b[2], a[3], b[3]);
+}
+
+
+inline
+GLfixed dot3(const GLfixed* a, const GLfixed* b)
+{
+ return mla3(a[0], b[0], a[1], b[1], a[2], b[2]);
+}
+
+
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_MATRIX_H
+
diff --git a/opengl/libagl/mipmap.cpp b/opengl/libagl/mipmap.cpp
new file mode 100644
index 0000000..ccd77b7
--- /dev/null
+++ b/opengl/libagl/mipmap.cpp
@@ -0,0 +1,192 @@
+/* libs/opengles/mipmap.cpp
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+
+#include "context.h"
+#include "state.h"
+#include "texture.h"
+#include "TextureObjectManager.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+status_t buildAPyramid(ogles_context_t* c, EGLTextureObject* tex)
+{
+ int level = 0;
+ const GGLSurface* base = &tex->surface;
+ const GGLFormat& pixelFormat(c->rasterizer.formats[base->format]);
+
+ int w = base->width;
+ int h = base->height;
+ if ((w&h) == 1)
+ return NO_ERROR;
+
+ w = (w>>1) ? : 1;
+ h = (h>>1) ? : 1;
+
+ while(true) {
+ ++level;
+ const int bpr = w * pixelFormat.size;
+ if (tex->reallocate(level, w, h, w,
+ base->format, base->compressedFormat, bpr) != NO_ERROR) {
+ return NO_MEMORY;
+ }
+
+ int stride = w;
+ int bs = base->stride;
+ GGLSurface& cur = tex->editMip(level);
+
+ if (base->format == GGL_PIXEL_FORMAT_RGB_565)
+ {
+ uint16_t const * src = (uint16_t const *)base->data;
+ uint16_t* dst = (uint16_t*)cur.data;
+ const uint32_t mask = 0x07E0F81F;
+ for (int y=0 ; y<h ; y++) {
+ size_t offset = (y*2) * bs;
+ for (int x=0 ; x<w ; x++) {
+ uint32_t p00 = src[offset];
+ uint32_t p10 = src[offset+1];
+ uint32_t p01 = src[offset+bs];
+ uint32_t p11 = src[offset+bs+1];
+ p00 = (p00 | (p00 << 16)) & mask;
+ p01 = (p01 | (p01 << 16)) & mask;
+ p10 = (p10 | (p10 << 16)) & mask;
+ p11 = (p11 | (p11 << 16)) & mask;
+ uint32_t grb = ((p00 + p10 + p01 + p11) >> 2) & mask;
+ uint32_t rgb = (grb & 0xFFFF) | (grb >> 16);
+ dst[x + y*stride] = rgb;
+ offset += 2;
+ }
+ }
+ }
+ else if (base->format == GGL_PIXEL_FORMAT_RGBA_5551)
+ {
+ uint16_t const * src = (uint16_t const *)base->data;
+ uint16_t* dst = (uint16_t*)cur.data;
+ for (int y=0 ; y<h ; y++) {
+ size_t offset = (y*2) * bs;
+ for (int x=0 ; x<w ; x++) {
+ uint32_t p00 = src[offset];
+ uint32_t p10 = src[offset+1];
+ uint32_t p01 = src[offset+bs];
+ uint32_t p11 = src[offset+bs+1];
+ uint32_t r = ((p00>>11)+(p10>>11)+(p01>>11)+(p11>>11)+2)>>2;
+ uint32_t g = (((p00>>6)+(p10>>6)+(p01>>6)+(p11>>6)+2)>>2)&0x3F;
+ uint32_t b = ((p00&0x3E)+(p10&0x3E)+(p01&0x3E)+(p11&0x3E)+4)>>3;
+ uint32_t a = ((p00&1)+(p10&1)+(p01&1)+(p11&1)+2)>>2;
+ dst[x + y*stride] = (r<<11)|(g<<6)|(b<<1)|a;
+ offset += 2;
+ }
+ }
+ }
+ else if (base->format == GGL_PIXEL_FORMAT_RGBA_8888)
+ {
+ uint32_t const * src = (uint32_t const *)base->data;
+ uint32_t* dst = (uint32_t*)cur.data;
+ for (int y=0 ; y<h ; y++) {
+ size_t offset = (y*2) * bs;
+ for (int x=0 ; x<w ; x++) {
+ uint32_t p00 = src[offset];
+ uint32_t p10 = src[offset+1];
+ uint32_t p01 = src[offset+bs];
+ uint32_t p11 = src[offset+bs+1];
+ uint32_t rb00 = p00 & 0x00FF00FF;
+ uint32_t rb01 = p01 & 0x00FF00FF;
+ uint32_t rb10 = p10 & 0x00FF00FF;
+ uint32_t rb11 = p11 & 0x00FF00FF;
+ uint32_t ga00 = (p00 >> 8) & 0x00FF00FF;
+ uint32_t ga01 = (p01 >> 8) & 0x00FF00FF;
+ uint32_t ga10 = (p10 >> 8) & 0x00FF00FF;
+ uint32_t ga11 = (p11 >> 8) & 0x00FF00FF;
+ uint32_t rb = (rb00 + rb01 + rb10 + rb11)>>2;
+ uint32_t ga = (ga00 + ga01 + ga10 + ga11)>>2;
+ uint32_t rgba = (rb & 0x00FF00FF) | ((ga & 0x00FF00FF)<<8);
+ dst[x + y*stride] = rgba;
+ offset += 2;
+ }
+ }
+ }
+ else if ((base->format == GGL_PIXEL_FORMAT_RGB_888) ||
+ (base->format == GGL_PIXEL_FORMAT_LA_88) ||
+ (base->format == GGL_PIXEL_FORMAT_A_8) ||
+ (base->format == GGL_PIXEL_FORMAT_L_8))
+ {
+ int skip;
+ switch (base->format) {
+ case GGL_PIXEL_FORMAT_RGB_888: skip = 3; break;
+ case GGL_PIXEL_FORMAT_LA_88: skip = 2; break;
+ default: skip = 1; break;
+ }
+ uint8_t const * src = (uint8_t const *)base->data;
+ uint8_t* dst = (uint8_t*)cur.data;
+ bs *= skip;
+ stride *= skip;
+ for (int y=0 ; y<h ; y++) {
+ size_t offset = (y*2) * bs;
+ for (int x=0 ; x<w ; x++) {
+ for (int c=0 ; c<skip ; c++) {
+ uint32_t p00 = src[c+offset];
+ uint32_t p10 = src[c+offset+skip];
+ uint32_t p01 = src[c+offset+bs];
+ uint32_t p11 = src[c+offset+bs+skip];
+ dst[x + y*stride + c] = (p00 + p10 + p01 + p11) >> 2;
+ }
+ offset += 2*skip;
+ }
+ }
+ }
+ else if (base->format == GGL_PIXEL_FORMAT_RGBA_4444)
+ {
+ uint16_t const * src = (uint16_t const *)base->data;
+ uint16_t* dst = (uint16_t*)cur.data;
+ for (int y=0 ; y<h ; y++) {
+ size_t offset = (y*2) * bs;
+ for (int x=0 ; x<w ; x++) {
+ uint32_t p00 = src[offset];
+ uint32_t p10 = src[offset+1];
+ uint32_t p01 = src[offset+bs];
+ uint32_t p11 = src[offset+bs+1];
+ p00 = ((p00 << 12) & 0x0F0F0000) | (p00 & 0x0F0F);
+ p10 = ((p10 << 12) & 0x0F0F0000) | (p10 & 0x0F0F);
+ p01 = ((p01 << 12) & 0x0F0F0000) | (p01 & 0x0F0F);
+ p11 = ((p11 << 12) & 0x0F0F0000) | (p11 & 0x0F0F);
+ uint32_t rbga = (p00 + p10 + p01 + p11) >> 2;
+ uint32_t rgba = (rbga & 0x0F0F) | ((rbga>>12) & 0xF0F0);
+ dst[x + y*stride] = rgba;
+ offset += 2;
+ }
+ }
+ } else {
+ LOGE("Unsupported format (%d)", base->format);
+ return BAD_TYPE;
+ }
+
+ // exit condition: we just processed the 1x1 LODs
+ if ((w&h) == 1)
+ break;
+
+ base = &cur;
+ w = (w>>1) ? : 1;
+ h = (h>>1) ? : 1;
+ }
+ return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/opengl/libagl/primitives.cpp b/opengl/libagl/primitives.cpp
new file mode 100644
index 0000000..f164c02
--- /dev/null
+++ b/opengl/libagl/primitives.cpp
@@ -0,0 +1,1111 @@
+/* libs/opengles/primitives.cpp
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "context.h"
+#include "primitives.h"
+#include "light.h"
+#include "matrix.h"
+#include "vertex.h"
+#include "fp.h"
+#include "TextureObjectManager.h"
+
+extern "C" void iterators0032(const void* that,
+ int32_t* it, int32_t c0, int32_t c1, int32_t c2);
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static void primitive_point(ogles_context_t* c, vertex_t* v);
+static void primitive_line(ogles_context_t* c, vertex_t* v0, vertex_t* v1);
+static void primitive_clip_triangle(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2);
+
+static void primitive_nop_point(ogles_context_t* c, vertex_t* v);
+static void primitive_nop_line(ogles_context_t* c, vertex_t* v0, vertex_t* v1);
+static void primitive_nop_triangle(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2);
+
+static inline bool cull_triangle(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2);
+
+static void lerp_triangle(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2);
+
+static void lerp_texcoords(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2);
+
+static void lerp_texcoords_w(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2);
+
+static void triangle(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2);
+
+static void clip_triangle(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2);
+
+static unsigned int clip_line(ogles_context_t* c,
+ vertex_t* s, vertex_t* p);
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+static void lightTriangleDarkSmooth(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ if (!(v0->flags & vertex_t::LIT)) {
+ v0->flags |= vertex_t::LIT;
+ const GLvoid* cp = c->arrays.color.element(
+ v0->index & vertex_cache_t::INDEX_MASK);
+ c->arrays.color.fetch(c, v0->color.v, cp);
+ }
+ if (!(v1->flags & vertex_t::LIT)) {
+ v1->flags |= vertex_t::LIT;
+ const GLvoid* cp = c->arrays.color.element(
+ v1->index & vertex_cache_t::INDEX_MASK);
+ c->arrays.color.fetch(c, v1->color.v, cp);
+ }
+ if(!(v2->flags & vertex_t::LIT)) {
+ v2->flags |= vertex_t::LIT;
+ const GLvoid* cp = c->arrays.color.element(
+ v2->index & vertex_cache_t::INDEX_MASK);
+ c->arrays.color.fetch(c, v2->color.v, cp);
+ }
+}
+
+static void lightTriangleDarkFlat(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ if (!(v2->flags & vertex_t::LIT)) {
+ v2->flags |= vertex_t::LIT;
+ const GLvoid* cp = c->arrays.color.element(
+ v2->index & vertex_cache_t::INDEX_MASK);
+ c->arrays.color.fetch(c, v2->color.v, cp);
+ }
+ // configure the rasterizer here, before we clip
+ c->rasterizer.procs.color4xv(c, v2->color.v);
+}
+
+static void lightTriangleSmooth(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ if (!(v0->flags & vertex_t::LIT))
+ c->lighting.lightVertex(c, v0);
+ if (!(v1->flags & vertex_t::LIT))
+ c->lighting.lightVertex(c, v1);
+ if(!(v2->flags & vertex_t::LIT))
+ c->lighting.lightVertex(c, v2);
+}
+
+static void lightTriangleFlat(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ if (!(v2->flags & vertex_t::LIT))
+ c->lighting.lightVertex(c, v2);
+ // configure the rasterizer here, before we clip
+ c->rasterizer.procs.color4xv(c, v2->color.v);
+}
+
+// The fog versions...
+
+static inline
+void lightVertexDarkSmoothFog(ogles_context_t* c, vertex_t* v)
+{
+ if (!(v->flags & vertex_t::LIT)) {
+ v->flags |= vertex_t::LIT;
+ v->fog = c->fog.fog(c, v->eye.z);
+ const GLvoid* cp = c->arrays.color.element(
+ v->index & vertex_cache_t::INDEX_MASK);
+ c->arrays.color.fetch(c, v->color.v, cp);
+ }
+}
+static inline
+void lightVertexDarkFlatFog(ogles_context_t* c, vertex_t* v)
+{
+ if (!(v->flags & vertex_t::LIT)) {
+ v->flags |= vertex_t::LIT;
+ v->fog = c->fog.fog(c, v->eye.z);
+ }
+}
+static inline
+void lightVertexSmoothFog(ogles_context_t* c, vertex_t* v)
+{
+ if (!(v->flags & vertex_t::LIT)) {
+ v->fog = c->fog.fog(c, v->eye.z);
+ c->lighting.lightVertex(c, v);
+ }
+}
+
+static void lightTriangleDarkSmoothFog(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ lightVertexDarkSmoothFog(c, v0);
+ lightVertexDarkSmoothFog(c, v1);
+ lightVertexDarkSmoothFog(c, v2);
+}
+
+static void lightTriangleDarkFlatFog(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ lightVertexDarkFlatFog(c, v0);
+ lightVertexDarkFlatFog(c, v1);
+ lightVertexDarkSmoothFog(c, v2);
+ // configure the rasterizer here, before we clip
+ c->rasterizer.procs.color4xv(c, v2->color.v);
+}
+
+static void lightTriangleSmoothFog(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ lightVertexSmoothFog(c, v0);
+ lightVertexSmoothFog(c, v1);
+ lightVertexSmoothFog(c, v2);
+}
+
+static void lightTriangleFlatFog(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ lightVertexDarkFlatFog(c, v0);
+ lightVertexDarkFlatFog(c, v1);
+ lightVertexSmoothFog(c, v2);
+ // configure the rasterizer here, before we clip
+ c->rasterizer.procs.color4xv(c, v2->color.v);
+}
+
+
+
+typedef void (*light_primitive_t)(ogles_context_t*,
+ vertex_t*, vertex_t*, vertex_t*);
+
+// fog 0x4, light 0x2, smooth 0x1
+static const light_primitive_t lightPrimitive[8] = {
+ lightTriangleDarkFlat, // no fog | dark | flat
+ lightTriangleDarkSmooth, // no fog | dark | smooth
+ lightTriangleFlat, // no fog | light | flat
+ lightTriangleSmooth, // no fog | light | smooth
+ lightTriangleDarkFlatFog, // fog | dark | flat
+ lightTriangleDarkSmoothFog, // fog | dark | smooth
+ lightTriangleFlatFog, // fog | light | flat
+ lightTriangleSmoothFog // fog | light | smooth
+};
+
+void ogles_validate_primitives(ogles_context_t* c)
+{
+ const uint32_t enables = c->rasterizer.state.enables;
+
+ // set up the lighting/shading/smoothing/fogging function
+ int index = enables & GGL_ENABLE_SMOOTH ? 0x1 : 0;
+ index |= c->lighting.enable ? 0x2 : 0;
+ index |= enables & GGL_ENABLE_FOG ? 0x4 : 0;
+ c->lighting.lightTriangle = lightPrimitive[index];
+
+ // set up the primitive renderers
+ if (ggl_likely(c->arrays.vertex.enable)) {
+ c->prims.renderPoint = primitive_point;
+ c->prims.renderLine = primitive_line;
+ c->prims.renderTriangle = primitive_clip_triangle;
+ } else {
+ c->prims.renderPoint = primitive_nop_point;
+ c->prims.renderLine = primitive_nop_line;
+ c->prims.renderTriangle = primitive_nop_triangle;
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+void compute_iterators_t::initTriangle(
+ vertex_t const* v0, vertex_t const* v1, vertex_t const* v2)
+{
+ m_dx01 = v1->window.x - v0->window.x;
+ m_dy10 = v0->window.y - v1->window.y;
+ m_dx20 = v0->window.x - v2->window.x;
+ m_dy02 = v2->window.y - v0->window.y;
+ m_area = m_dx01*m_dy02 + (-m_dy10)*m_dx20;
+}
+
+void compute_iterators_t::initLine(
+ vertex_t const* v0, vertex_t const* v1)
+{
+ m_dx01 = m_dy02 = v1->window.x - v0->window.x;
+ m_dy10 = m_dx20 = v0->window.y - v1->window.y;
+ m_area = m_dx01*m_dy02 + (-m_dy10)*m_dx20;
+}
+
+void compute_iterators_t::initLerp(vertex_t const* v0, uint32_t enables)
+{
+ m_x0 = v0->window.x;
+ m_y0 = v0->window.y;
+ const GGLcoord area = (m_area + TRI_HALF) >> TRI_FRACTION_BITS;
+ const GGLcoord minArea = 2; // cannot be inverted
+ // triangles with an area smaller than 1.0 are not smooth-shaded
+
+ int q=0, s=0, d=0;
+ if (abs(area) >= minArea) {
+ // Here we do some voodoo magic, to compute a suitable scale
+ // factor for deltas/area:
+
+ // First compute the 1/area with full 32-bits precision,
+ // gglRecipQNormalized returns a number [-0.5, 0.5[ and an exponent.
+ d = gglRecipQNormalized(area, &q);
+
+ // Then compute the minimum left-shift to not overflow the muls
+ // below.
+ s = 32 - gglClz(abs(m_dy02)|abs(m_dy10)|abs(m_dx01)|abs(m_dx20));
+
+ // We'll keep 16-bits of precision for deltas/area. So we need
+ // to shift everything left an extra 15 bits.
+ s += 15;
+
+ // make sure all final shifts are not > 32, because gglMulx
+ // can't handle it.
+ if (s < q) s = q;
+ if (s > 32) {
+ d >>= 32-s;
+ s = 32;
+ }
+ }
+
+ m_dx01 = gglMulx(m_dx01, d, s);
+ m_dy10 = gglMulx(m_dy10, d, s);
+ m_dx20 = gglMulx(m_dx20, d, s);
+ m_dy02 = gglMulx(m_dy02, d, s);
+ m_area_scale = 32 + q - s;
+ m_scale = 0;
+
+ if (enables & GGL_ENABLE_TMUS) {
+ const int A = gglClz(abs(m_dy02)|abs(m_dy10)|abs(m_dx01)|abs(m_dx20));
+ const int B = gglClz(abs(m_x0)|abs(m_y0));
+ m_scale = max(0, 32 - (A + 16)) +
+ max(0, 32 - (B + TRI_FRACTION_BITS)) + 1;
+ }
+}
+
+int compute_iterators_t::iteratorsScale(GGLfixed* it,
+ int32_t c0, int32_t c1, int32_t c2) const
+{
+ int32_t dc01 = c1 - c0;
+ int32_t dc02 = c2 - c0;
+ const int A = gglClz(abs(c0));
+ const int B = gglClz(abs(dc01)|abs(dc02));
+ const int scale = min(A, B - m_scale) - 2;
+ if (scale >= 0) {
+ c0 <<= scale;
+ dc01 <<= scale;
+ dc02 <<= scale;
+ } else {
+ c0 >>= -scale;
+ dc01 >>= -scale;
+ dc02 >>= -scale;
+ }
+ const int s = m_area_scale;
+ int32_t dcdx = gglMulAddx(dc01, m_dy02, gglMulx(dc02, m_dy10, s), s);
+ int32_t dcdy = gglMulAddx(dc02, m_dx01, gglMulx(dc01, m_dx20, s), s);
+ int32_t c = c0 - (gglMulAddx(dcdx, m_x0,
+ gglMulx(dcdy, m_y0, TRI_FRACTION_BITS), TRI_FRACTION_BITS));
+ it[0] = c;
+ it[1] = dcdx;
+ it[2] = dcdy;
+ return scale;
+}
+
+void compute_iterators_t::iterators1616(GGLfixed* it,
+ GGLfixed c0, GGLfixed c1, GGLfixed c2) const
+{
+ const GGLfixed dc01 = c1 - c0;
+ const GGLfixed dc02 = c2 - c0;
+ // 16.16 x 16.16 == 32.32 --> 16.16
+ const int s = m_area_scale;
+ int32_t dcdx = gglMulAddx(dc01, m_dy02, gglMulx(dc02, m_dy10, s), s);
+ int32_t dcdy = gglMulAddx(dc02, m_dx01, gglMulx(dc01, m_dx20, s), s);
+ int32_t c = c0 - (gglMulAddx(dcdx, m_x0,
+ gglMulx(dcdy, m_y0, TRI_FRACTION_BITS), TRI_FRACTION_BITS));
+ it[0] = c;
+ it[1] = dcdx;
+ it[2] = dcdy;
+}
+
+void compute_iterators_t::iterators0032(int64_t* it,
+ int32_t c0, int32_t c1, int32_t c2) const
+{
+ const int s = m_area_scale - 16;
+ int32_t dc01 = (c1 - c0)>>s;
+ int32_t dc02 = (c2 - c0)>>s;
+ // 16.16 x 16.16 == 32.32
+ int64_t dcdx = gglMulii(dc01, m_dy02) + gglMulii(dc02, m_dy10);
+ int64_t dcdy = gglMulii(dc02, m_dx01) + gglMulii(dc01, m_dx20);
+ it[ 0] = (c0<<16) - ((dcdx*m_x0 + dcdy*m_y0)>>4);
+ it[ 1] = dcdx;
+ it[ 2] = dcdy;
+}
+
+#if defined(__arm__) && !defined(__thumb__)
+inline void compute_iterators_t::iterators0032(int32_t* it,
+ int32_t c0, int32_t c1, int32_t c2) const
+{
+ ::iterators0032(this, it, c0, c1, c2);
+}
+#else
+void compute_iterators_t::iterators0032(int32_t* it,
+ int32_t c0, int32_t c1, int32_t c2) const
+{
+ int64_t it64[3];
+ iterators0032(it, c0, c1, c2);
+ it[0] = it64[0];
+ it[1] = it64[1];
+ it[2] = it64[2];
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
+static inline int32_t clampZ(GLfixed z) CONST;
+int32_t clampZ(GLfixed z) {
+ z = (z & ~(z>>31));
+ if (z >= 0x10000)
+ z = 0xFFFF;
+ return z;
+}
+
+static __attribute__((noinline))
+void fetch_texcoord_impl(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ vertex_t* const vtx[3] = { v0, v1, v2 };
+ array_t const * const texcoordArray = c->arrays.texture;
+
+ for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ if (!(c->rasterizer.state.texture[i].enable))
+ continue;
+
+ for (int j=0 ; j<3 ; j++) {
+ vertex_t* const v = vtx[j];
+ if (v->flags & vertex_t::TT)
+ continue;
+
+ // NOTE: here we could compute automatic texgen
+ // such as sphere/cube maps, instead of fetching them
+ // from the textcoord array.
+
+ vec4_t& coords = v->texture[i];
+ const GLubyte* tp = texcoordArray[i].element(
+ v->index & vertex_cache_t::INDEX_MASK);
+ texcoordArray[i].fetch(c, coords.v, tp);
+
+ // transform texture coordinates...
+ coords.Q = 0x10000;
+ const transform_t& tr = c->transforms.texture[i].transform;
+ if (ggl_unlikely(tr.ops)) {
+ c->arrays.tex_transform[i](&tr, &coords, &coords);
+ }
+
+ // divide by Q
+ const GGLfixed q = coords.Q;
+ if (ggl_unlikely(q != 0x10000)) {
+ const int32_t qinv = gglRecip28(q);
+ coords.S = gglMulx(coords.S, qinv, 28);
+ coords.T = gglMulx(coords.T, qinv, 28);
+ }
+ }
+ }
+ v0->flags |= vertex_t::TT;
+ v1->flags |= vertex_t::TT;
+ v2->flags |= vertex_t::TT;
+}
+
+inline void fetch_texcoord(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ const uint32_t enables = c->rasterizer.state.enables;
+ if (!(enables & GGL_ENABLE_TMUS))
+ return;
+
+ // Fetch & transform texture coordinates...
+ if (ggl_likely(v0->flags & v1->flags & v2->flags & vertex_t::TT)) {
+ // already done for all three vertices, bail...
+ return;
+ }
+ fetch_texcoord_impl(c, v0, v1, v2);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Point
+#endif
+
+void primitive_nop_point(ogles_context_t*, vertex_t*) {
+}
+
+void primitive_point(ogles_context_t* c, vertex_t* v)
+{
+ // lighting & clamping...
+ const uint32_t enables = c->rasterizer.state.enables;
+
+ if (ggl_unlikely(!(v->flags & vertex_t::LIT))) {
+ if (c->lighting.enable) {
+ c->lighting.lightVertex(c, v);
+ } else {
+ v->flags |= vertex_t::LIT;
+ const GLvoid* cp = c->arrays.color.element(
+ v->index & vertex_cache_t::INDEX_MASK);
+ c->arrays.color.fetch(c, v->color.v, cp);
+ }
+ if (enables & GGL_ENABLE_FOG) {
+ v->fog = c->fog.fog(c, v->eye.z);
+ }
+ }
+
+ // XXX: we don't need to do that each-time
+ // if color array and lighting not enabled
+ c->rasterizer.procs.color4xv(c, v->color.v);
+
+ // XXX: look into ES point-sprite extension
+ if (enables & GGL_ENABLE_TMUS) {
+ fetch_texcoord(c, v,v,v);
+ for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ if (!c->rasterizer.state.texture[i].enable)
+ continue;
+ int32_t itt[8];
+ itt[1] = itt[2] = itt[4] = itt[5] = 0;
+ itt[6] = itt[7] = 16; // XXX: check that
+ if (c->rasterizer.state.texture[i].s_wrap == GGL_CLAMP) {
+ int width = c->textures.tmu[i].texture->surface.width;
+ itt[0] = v->texture[i].S * width;
+ itt[6] = 0;
+ }
+ if (c->rasterizer.state.texture[i].t_wrap == GGL_CLAMP) {
+ int height = c->textures.tmu[i].texture->surface.height;
+ itt[3] = v->texture[i].T * height;
+ itt[7] = 0;
+ }
+ c->rasterizer.procs.texCoordGradScale8xv(c, i, itt);
+ }
+ }
+
+ if (enables & GGL_ENABLE_DEPTH_TEST) {
+ int32_t itz[3];
+ itz[0] = clampZ(v->window.z) * 0x00010001;
+ itz[1] = itz[2] = 0;
+ c->rasterizer.procs.zGrad3xv(c, itz);
+ }
+
+ if (enables & GGL_ENABLE_FOG) {
+ GLfixed itf[3];
+ itf[0] = v->fog;
+ itf[1] = itf[2] = 0;
+ c->rasterizer.procs.fogGrad3xv(c, itf);
+ }
+
+ // Render our point...
+ c->rasterizer.procs.pointx(c, v->window.v, c->point.size);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Line
+#endif
+
+void primitive_nop_line(ogles_context_t*, vertex_t*, vertex_t*) {
+}
+
+void primitive_line(ogles_context_t* c, vertex_t* v0, vertex_t* v1)
+{
+ // get texture coordinates
+ fetch_texcoord(c, v0, v1, v1);
+
+ // light/shade the vertices first (they're copied below)
+ c->lighting.lightTriangle(c, v0, v1, v1);
+
+ // clip the line if needed
+ if (ggl_unlikely((v0->flags | v1->flags) & vertex_t::CLIP_ALL)) {
+ unsigned int count = clip_line(c, v0, v1);
+ if (ggl_unlikely(count == 0))
+ return;
+ }
+
+ // compute iterators...
+ const uint32_t enables = c->rasterizer.state.enables;
+ const uint32_t mask = GGL_ENABLE_TMUS |
+ GGL_ENABLE_SMOOTH |
+ GGL_ENABLE_W |
+ GGL_ENABLE_FOG |
+ GGL_ENABLE_DEPTH_TEST;
+
+ if (ggl_unlikely(enables & mask)) {
+ c->lerp.initLine(v0, v1);
+ lerp_triangle(c, v0, v1, v0);
+ }
+
+ // render our line
+ c->rasterizer.procs.linex(c, v0->window.v, v1->window.v, c->line.width);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Triangle
+#endif
+
+void primitive_nop_triangle(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2) {
+}
+
+void primitive_clip_triangle(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ uint32_t cc = (v0->flags | v1->flags | v2->flags) & vertex_t::CLIP_ALL;
+ if (ggl_likely(!cc)) {
+ // code below must be as optimized as possible, this is the
+ // common code path.
+
+ // This triangle is not clipped, test if it's culled
+ // unclipped triangle...
+ c->lerp.initTriangle(v0, v1, v2);
+ if (cull_triangle(c, v0, v1, v2))
+ return; // culled!
+
+ // Fetch all texture coordinates if needed
+ fetch_texcoord(c, v0, v1, v2);
+
+ // light (or shade) our triangle!
+ c->lighting.lightTriangle(c, v0, v1, v2);
+
+ triangle(c, v0, v1, v2);
+ return;
+ }
+
+ // The assumption here is that we're not going to clip very often,
+ // and even more rarely will we clip a triangle that ends up
+ // being culled out. So it's okay to light the vertices here, even though
+ // in a few cases we won't render the triangle (if culled).
+
+ // Fetch texture coordinates...
+ fetch_texcoord(c, v0, v1, v2);
+
+ // light (or shade) our triangle!
+ c->lighting.lightTriangle(c, v0, v1, v2);
+
+ clip_triangle(c, v0, v1, v2);
+}
+
+// -----------------------------------------------------------------------
+
+void triangle(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ // compute iterators...
+ const uint32_t enables = c->rasterizer.state.enables;
+ const uint32_t mask = GGL_ENABLE_TMUS |
+ GGL_ENABLE_SMOOTH |
+ GGL_ENABLE_W |
+ GGL_ENABLE_FOG |
+ GGL_ENABLE_DEPTH_TEST;
+
+ if (ggl_likely(enables & mask))
+ lerp_triangle(c, v0, v1, v2);
+
+ c->rasterizer.procs.trianglex(c, v0->window.v, v1->window.v, v2->window.v);
+}
+
+void lerp_triangle(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ const uint32_t enables = c->rasterizer.state.enables;
+ c->lerp.initLerp(v0, enables);
+
+ // set up texture iterators
+ if (enables & GGL_ENABLE_TMUS) {
+ if (enables & GGL_ENABLE_W) {
+ lerp_texcoords_w(c, v0, v1, v2);
+ } else {
+ lerp_texcoords(c, v0, v1, v2);
+ }
+ }
+
+ // set up the color iterators
+ const compute_iterators_t& lerp = c->lerp;
+ if (enables & GGL_ENABLE_SMOOTH) {
+ GLfixed itc[12];
+ for (int i=0 ; i<4 ; i++) {
+ const GGLcolor c0 = v0->color.v[i] * 255;
+ const GGLcolor c1 = v1->color.v[i] * 255;
+ const GGLcolor c2 = v2->color.v[i] * 255;
+ lerp.iterators1616(&itc[i*3], c0, c1, c2);
+ }
+ c->rasterizer.procs.colorGrad12xv(c, itc);
+ }
+
+ if (enables & GGL_ENABLE_DEPTH_TEST) {
+ int32_t itz[3];
+ const int32_t v0z = clampZ(v0->window.z);
+ const int32_t v1z = clampZ(v1->window.z);
+ const int32_t v2z = clampZ(v2->window.z);
+ if (ggl_unlikely(c->polygonOffset.enable)) {
+ const int32_t units = (c->polygonOffset.units << 16);
+ const GLfixed factor = c->polygonOffset.factor;
+ if (factor) {
+ int64_t itz64[3];
+ lerp.iterators0032(itz64, v0z, v1z, v2z);
+ int64_t maxDepthSlope = max(itz64[1], itz64[2]);
+ itz[0] = uint32_t(itz64[0])
+ + uint32_t((maxDepthSlope*factor)>>16) + units;
+ itz[1] = uint32_t(itz64[1]);
+ itz[2] = uint32_t(itz64[2]);
+ } else {
+ lerp.iterators0032(itz, v0z, v1z, v2z);
+ itz[0] += units;
+ }
+ } else {
+ lerp.iterators0032(itz, v0z, v1z, v2z);
+ }
+ c->rasterizer.procs.zGrad3xv(c, itz);
+ }
+
+ if (ggl_unlikely(enables & GGL_ENABLE_FOG)) {
+ GLfixed itf[3];
+ lerp.iterators1616(itf, v0->fog, v1->fog, v2->fog);
+ c->rasterizer.procs.fogGrad3xv(c, itf);
+ }
+}
+
+
+static inline
+int compute_lod(ogles_context_t* c, int i,
+ int32_t s0, int32_t t0, int32_t s1, int32_t t1, int32_t s2, int32_t t2)
+{
+ // Compute mipmap level / primitive
+ // rho = sqrt( texelArea / area )
+ // lod = log2( rho )
+ // lod = log2( texelArea / area ) / 2
+ // lod = (log2( texelArea ) - log2( area )) / 2
+ const compute_iterators_t& lerp = c->lerp;
+ const GGLcoord area = abs(lerp.area());
+ const int w = c->textures.tmu[i].texture->surface.width;
+ const int h = c->textures.tmu[i].texture->surface.height;
+ const int shift = 16 + (16 - TRI_FRACTION_BITS);
+ int32_t texelArea = abs( gglMulx(s1-s0, t2-t0, shift) -
+ gglMulx(s2-s0, t1-t0, shift) )*w*h;
+ int log2TArea = (32-TRI_FRACTION_BITS -1) - gglClz(texelArea);
+ int log2Area = (32-TRI_FRACTION_BITS*2-1) - gglClz(area);
+ int lod = (log2TArea - log2Area + 1) >> 1;
+ return lod;
+}
+
+void lerp_texcoords(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ const compute_iterators_t& lerp = c->lerp;
+ int32_t itt[8] __attribute__((aligned(16)));
+ for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ const texture_t& tmu = c->rasterizer.state.texture[i];
+ if (!tmu.enable)
+ continue;
+
+ // compute the jacobians using block floating-point
+ int32_t s0 = v0->texture[i].S;
+ int32_t t0 = v0->texture[i].T;
+ int32_t s1 = v1->texture[i].S;
+ int32_t t1 = v1->texture[i].T;
+ int32_t s2 = v2->texture[i].S;
+ int32_t t2 = v2->texture[i].T;
+
+ const GLenum min_filter = c->textures.tmu[i].texture->min_filter;
+ if (ggl_unlikely(min_filter >= GL_NEAREST_MIPMAP_NEAREST)) {
+ int lod = compute_lod(c, i, s0, t0, s1, t1, s2, t2);
+ c->rasterizer.procs.bindTextureLod(c, i,
+ &c->textures.tmu[i].texture->mip(lod));
+ }
+
+ // premultiply (s,t) when clampling
+ if (tmu.s_wrap == GGL_CLAMP) {
+ const int width = tmu.surface.width;
+ s0 *= width;
+ s1 *= width;
+ s2 *= width;
+ }
+ if (tmu.t_wrap == GGL_CLAMP) {
+ const int height = tmu.surface.height;
+ t0 *= height;
+ t1 *= height;
+ t2 *= height;
+ }
+ itt[6] = -lerp.iteratorsScale(itt+0, s0, s1, s2);
+ itt[7] = -lerp.iteratorsScale(itt+3, t0, t1, t2);
+ c->rasterizer.procs.texCoordGradScale8xv(c, i, itt);
+ }
+}
+
+void lerp_texcoords_w(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ const compute_iterators_t& lerp = c->lerp;
+ int32_t itt[8] __attribute__((aligned(16)));
+ int32_t itw[3];
+
+ // compute W's scale to 2.30
+ int32_t w0 = v0->window.w;
+ int32_t w1 = v1->window.w;
+ int32_t w2 = v2->window.w;
+ int wscale = 32 - gglClz(w0|w1|w2);
+
+ // compute the jacobian using block floating-point
+ int sc = lerp.iteratorsScale(itw, w0, w1, w2);
+ sc += wscale - 16;
+ c->rasterizer.procs.wGrad3xv(c, itw);
+
+ for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ const texture_t& tmu = c->rasterizer.state.texture[i];
+ if (!tmu.enable)
+ continue;
+
+ // compute the jacobians using block floating-point
+ int32_t s0 = v0->texture[i].S;
+ int32_t t0 = v0->texture[i].T;
+ int32_t s1 = v1->texture[i].S;
+ int32_t t1 = v1->texture[i].T;
+ int32_t s2 = v2->texture[i].S;
+ int32_t t2 = v2->texture[i].T;
+
+ const GLenum min_filter = c->textures.tmu[i].texture->min_filter;
+ if (ggl_unlikely(min_filter >= GL_NEAREST_MIPMAP_NEAREST)) {
+ int lod = compute_lod(c, i, s0, t0, s1, t1, s2, t2);
+ c->rasterizer.procs.bindTextureLod(c, i,
+ &c->textures.tmu[i].texture->mip(lod));
+ }
+
+ // premultiply (s,t) when clampling
+ if (tmu.s_wrap == GGL_CLAMP) {
+ const int width = tmu.surface.width;
+ s0 *= width;
+ s1 *= width;
+ s2 *= width;
+ }
+ if (tmu.t_wrap == GGL_CLAMP) {
+ const int height = tmu.surface.height;
+ t0 *= height;
+ t1 *= height;
+ t2 *= height;
+ }
+
+ s0 = gglMulx(s0, w0, wscale);
+ t0 = gglMulx(t0, w0, wscale);
+ s1 = gglMulx(s1, w1, wscale);
+ t1 = gglMulx(t1, w1, wscale);
+ s2 = gglMulx(s2, w2, wscale);
+ t2 = gglMulx(t2, w2, wscale);
+
+ itt[6] = sc - lerp.iteratorsScale(itt+0, s0, s1, s2);
+ itt[7] = sc - lerp.iteratorsScale(itt+3, t0, t1, t2);
+ c->rasterizer.procs.texCoordGradScale8xv(c, i, itt);
+ }
+}
+
+
+static inline
+bool cull_triangle(ogles_context_t* c, vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ if (ggl_likely(c->cull.enable)) {
+ const GLenum winding = (c->lerp.area() > 0) ? GL_CW : GL_CCW;
+ const GLenum face = (winding == c->cull.frontFace) ? GL_FRONT : GL_BACK;
+ if (face == c->cull.cullFace)
+ return true; // culled!
+ }
+ return false;
+}
+
+static inline
+GLfixed frustumPlaneDist(int plane, const vec4_t& s)
+{
+ const GLfixed d = s.v[ plane >> 1 ];
+ return ((plane & 1) ? (s.w - d) : (s.w + d));
+}
+
+static inline
+int32_t clipDivide(GLfixed a, GLfixed b) {
+ // returns a 4.28 fixed-point
+ return gglMulDivi(1LU<<28, a, b);
+}
+
+void clip_triangle(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ uint32_t all_cc = (v0->flags | v1->flags | v2->flags) & vertex_t::CLIP_ALL;
+
+ vertex_t *p0, *p1, *p2;
+ const int MAX_CLIPPING_PLANES = 6 + OGLES_MAX_CLIP_PLANES;
+ const int MAX_VERTICES = 3;
+
+ // Temporary buffer to hold the new vertices. Each plane can add up to
+ // two new vertices (because the polygon is convex).
+ // We need one extra element, to handle an overflow case when
+ // the polygon degenerates into something non convex.
+ vertex_t buffer[MAX_CLIPPING_PLANES * 2 + 1]; // ~3KB
+ vertex_t* buf = buffer;
+
+ // original list of vertices (polygon to clip, in fact this
+ // function works with an arbitrary polygon).
+ vertex_t* in[3] = { v0, v1, v2 };
+
+ // output lists (we need 2, which we use back and forth)
+ // (maximum outpout list's size is MAX_CLIPPING_PLANES + MAX_VERTICES)
+ // 2 more elements for overflow when non convex polygons.
+ vertex_t* out[2][MAX_CLIPPING_PLANES + MAX_VERTICES + 2];
+ unsigned int outi = 0;
+
+ // current input list
+ vertex_t** ivl = in;
+
+ // 3 input vertices, 0 in the output list, first plane
+ unsigned int ic = 3;
+
+ // User clip-planes first, the clipping is always done in eye-coordinate
+ // this is basically the same algorithm than for the view-volume
+ // clipping, except for the computation of the distance (vertex, plane)
+ // and the fact that we need to compute the eye-coordinates of each
+ // new vertex we create.
+
+ if (ggl_unlikely(all_cc & vertex_t::USER_CLIP_ALL))
+ {
+ unsigned int plane = 0;
+ uint32_t cc = (all_cc & vertex_t::USER_CLIP_ALL) >> 8;
+ do {
+ if (cc & 1) {
+ // pointers to our output list (head and current)
+ vertex_t** const ovl = &out[outi][0];
+ vertex_t** output = ovl;
+ unsigned int oc = 0;
+ unsigned int sentinel = 0;
+ // previous vertex, compute distance to the plane
+ vertex_t* s = ivl[ic-1];
+ const vec4_t& equation = c->clipPlanes.plane[plane].equation;
+ GLfixed sd = dot4(equation.v, s->eye.v);
+ // clip each vertex against this plane...
+ for (unsigned int i=0 ; i<ic ; i++) {
+ vertex_t* p = ivl[i];
+ const GLfixed pd = dot4(equation.v, p->eye.v);
+ if (sd >= 0) {
+ if (pd >= 0) {
+ // both inside
+ *output++ = p;
+ oc++;
+ } else {
+ // s inside, p outside (exiting)
+ const GLfixed t = clipDivide(sd, sd-pd);
+ c->arrays.clipEye(c, buf, t, p, s);
+ *output++ = buf++;
+ oc++;
+ if (++sentinel >= 3)
+ return; // non-convex polygon!
+ }
+ } else {
+ if (pd >= 0) {
+ // s outside (entering)
+ if (pd) {
+ const GLfixed t = clipDivide(pd, pd-sd);
+ c->arrays.clipEye(c, buf, t, s, p);
+ *output++ = buf++;
+ oc++;
+ if (++sentinel >= 3)
+ return; // non-convex polygon!
+ }
+ *output++ = p;
+ oc++;
+ } else {
+ // both outside
+ }
+ }
+ s = p;
+ sd = pd;
+ }
+ // output list become the new input list
+ if (oc<3)
+ return; // less than 3 vertices left? we're done!
+ ivl = ovl;
+ ic = oc;
+ outi = 1-outi;
+ }
+ cc >>= 1;
+ plane++;
+ } while (cc);
+ }
+
+ // frustum clip-planes
+ if (all_cc & vertex_t::FRUSTUM_CLIP_ALL)
+ {
+ unsigned int plane = 0;
+ uint32_t cc = all_cc & vertex_t::FRUSTUM_CLIP_ALL;
+ do {
+ if (cc & 1) {
+ // pointers to our output list (head and current)
+ vertex_t** const ovl = &out[outi][0];
+ vertex_t** output = ovl;
+ unsigned int oc = 0;
+ unsigned int sentinel = 0;
+ // previous vertex, compute distance to the plane
+ vertex_t* s = ivl[ic-1];
+ GLfixed sd = frustumPlaneDist(plane, s->clip);
+ // clip each vertex against this plane...
+ for (unsigned int i=0 ; i<ic ; i++) {
+ vertex_t* p = ivl[i];
+ const GLfixed pd = frustumPlaneDist(plane, p->clip);
+ if (sd >= 0) {
+ if (pd >= 0) {
+ // both inside
+ *output++ = p;
+ oc++;
+ } else {
+ // s inside, p outside (exiting)
+ const GLfixed t = clipDivide(sd, sd-pd);
+ c->arrays.clipVertex(c, buf, t, p, s);
+ *output++ = buf++;
+ oc++;
+ if (++sentinel >= 3)
+ return; // non-convex polygon!
+ }
+ } else {
+ if (pd >= 0) {
+ // s outside (entering)
+ if (pd) {
+ const GLfixed t = clipDivide(pd, pd-sd);
+ c->arrays.clipVertex(c, buf, t, s, p);
+ *output++ = buf++;
+ oc++;
+ if (++sentinel >= 3)
+ return; // non-convex polygon!
+ }
+ *output++ = p;
+ oc++;
+ } else {
+ // both outside
+ }
+ }
+ s = p;
+ sd = pd;
+ }
+ // output list become the new input list
+ if (oc<3)
+ return; // less than 3 vertices left? we're done!
+ ivl = ovl;
+ ic = oc;
+ outi = 1-outi;
+ }
+ cc >>= 1;
+ plane++;
+ } while (cc);
+ }
+
+ // finally we can render our triangles...
+ p0 = ivl[0];
+ p1 = ivl[1];
+ for (unsigned int i=2 ; i<ic ; i++) {
+ p2 = ivl[i];
+ c->lerp.initTriangle(p0, p1, p2);
+ if (cull_triangle(c, p0, p1, p2)) {
+ p1 = p2;
+ continue; // culled!
+ }
+ triangle(c, p0, p1, p2);
+ p1 = p2;
+ }
+}
+
+unsigned int clip_line(ogles_context_t* c, vertex_t* s, vertex_t* p)
+{
+ const uint32_t all_cc = (s->flags | p->flags) & vertex_t::CLIP_ALL;
+
+ if (ggl_unlikely(all_cc & vertex_t::USER_CLIP_ALL))
+ {
+ unsigned int plane = 0;
+ uint32_t cc = (all_cc & vertex_t::USER_CLIP_ALL) >> 8;
+ do {
+ if (cc & 1) {
+ const vec4_t& equation = c->clipPlanes.plane[plane].equation;
+ const GLfixed sd = dot4(equation.v, s->eye.v);
+ const GLfixed pd = dot4(equation.v, p->eye.v);
+ if (sd >= 0) {
+ if (pd >= 0) {
+ // both inside
+ } else {
+ // s inside, p outside (exiting)
+ const GLfixed t = clipDivide(sd, sd-pd);
+ c->arrays.clipEye(c, p, t, p, s);
+ }
+ } else {
+ if (pd >= 0) {
+ // s outside (entering)
+ if (pd) {
+ const GLfixed t = clipDivide(pd, pd-sd);
+ c->arrays.clipEye(c, s, t, s, p);
+ }
+ } else {
+ // both outside
+ return 0;
+ }
+ }
+ }
+ cc >>= 1;
+ plane++;
+ } while (cc);
+ }
+
+ // frustum clip-planes
+ if (all_cc & vertex_t::FRUSTUM_CLIP_ALL)
+ {
+ unsigned int plane = 0;
+ uint32_t cc = all_cc & vertex_t::FRUSTUM_CLIP_ALL;
+ do {
+ if (cc & 1) {
+ const GLfixed sd = frustumPlaneDist(plane, s->clip);
+ const GLfixed pd = frustumPlaneDist(plane, p->clip);
+ if (sd >= 0) {
+ if (pd >= 0) {
+ // both inside
+ } else {
+ // s inside, p outside (exiting)
+ const GLfixed t = clipDivide(sd, sd-pd);
+ c->arrays.clipVertex(c, p, t, p, s);
+ }
+ } else {
+ if (pd >= 0) {
+ // s outside (entering)
+ if (pd) {
+ const GLfixed t = clipDivide(pd, pd-sd);
+ c->arrays.clipVertex(c, s, t, s, p);
+ }
+ } else {
+ // both outside
+ return 0;
+ }
+ }
+ }
+ cc >>= 1;
+ plane++;
+ } while (cc);
+ }
+
+ return 2;
+}
+
+
+}; // namespace android
diff --git a/opengl/libagl/primitives.h b/opengl/libagl/primitives.h
new file mode 100644
index 0000000..1bef604
--- /dev/null
+++ b/opengl/libagl/primitives.h
@@ -0,0 +1,37 @@
+/* libs/opengles/primitives.h
+**
+** 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.
+*/
+
+#ifndef ANDROID_OPENGLES_PRIMITIVES_H
+#define ANDROID_OPENGLES_PRIMITIVES_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+
+namespace android {
+
+namespace gl {
+struct ogles_context_t;
+};
+
+void ogles_validate_primitives(ogles_context_t* c);
+
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_PRIMITIVES_H
+
diff --git a/opengl/libagl/state.cpp b/opengl/libagl/state.cpp
new file mode 100644
index 0000000..5cbabea
--- /dev/null
+++ b/opengl/libagl/state.cpp
@@ -0,0 +1,586 @@
+/* libs/opengles/state.cpp
+**
+** 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 "context.h"
+#include "fp.h"
+#include "state.h"
+#include "array.h"
+#include "matrix.h"
+#include "vertex.h"
+#include "light.h"
+#include "texture.h"
+#include "BufferObjectManager.h"
+#include "TextureObjectManager.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static char const * const gVendorString = "Android";
+static char const * const gRendererString = "Android PixelFlinger 1.0";
+static char const * const gVersionString = "OpenGL ES-CM 1.0";
+static char const * const gExtensionsString =
+ "GL_OES_byte_coordinates " // OK
+ "GL_OES_fixed_point " // OK
+ "GL_OES_single_precision " // OK
+ "GL_OES_read_format " // OK
+ "GL_OES_compressed_paletted_texture " // OK
+ "GL_OES_draw_texture " // OK
+ "GL_OES_matrix_get " // OK
+ "GL_OES_query_matrix " // OK
+ // "GL_OES_point_size_array " // TODO
+ // "GL_OES_point_sprite " // TODO
+ "GL_ARB_texture_compression " // OK
+ "GL_ARB_texture_non_power_of_two " // OK
+ "GL_ANDROID_direct_texture " // OK
+ "GL_ANDROID_user_clip_plane " // OK
+ "GL_ANDROID_vertex_buffer_object " // OK
+ "GL_ANDROID_generate_mipmap " // OK
+ ;
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+ogles_context_t *ogles_init(size_t extra)
+{
+ void* const base = malloc(extra + sizeof(ogles_context_t) + 32);
+ if (!base) return 0;
+
+ ogles_context_t *c =
+ (ogles_context_t *)((ptrdiff_t(base) + extra + 31) & ~0x1FL);
+ memset(c, 0, sizeof(ogles_context_t));
+ ggl_init_context(&(c->rasterizer));
+
+ // XXX: this should be passed as an argument
+ sp<EGLSurfaceManager> smgr(new EGLSurfaceManager());
+ c->surfaceManager = smgr.get();
+ c->surfaceManager->incStrong(c);
+
+ sp<EGLBufferObjectManager> bomgr(new EGLBufferObjectManager());
+ c->bufferObjectManager = bomgr.get();
+ c->bufferObjectManager->incStrong(c);
+
+ ogles_init_array(c);
+ ogles_init_matrix(c);
+ ogles_init_vertex(c);
+ ogles_init_light(c);
+ ogles_init_texture(c);
+
+ c->rasterizer.base = base;
+ c->point.size = TRI_ONE;
+ c->line.width = TRI_ONE;
+
+ // in OpenGL, writing to the depth buffer is enabled by default.
+ c->rasterizer.procs.depthMask(c, 1);
+
+ // OpenGL enables dithering by default
+ c->rasterizer.procs.enable(c, GL_DITHER);
+
+ return c;
+}
+
+void ogles_uninit(ogles_context_t* c)
+{
+ ogles_uninit_array(c);
+ ogles_uninit_matrix(c);
+ ogles_uninit_vertex(c);
+ ogles_uninit_light(c);
+ ogles_uninit_texture(c);
+ c->surfaceManager->decStrong(c);
+ c->bufferObjectManager->decStrong(c);
+ ggl_uninit_context(&(c->rasterizer));
+ free(c->rasterizer.base);
+}
+
+void _ogles_error(ogles_context_t* c, GLenum error)
+{
+ if (c->error == GL_NO_ERROR)
+ c->error = error;
+}
+
+static bool stencilop_valid(GLenum op) {
+ switch (op) {
+ case GL_KEEP:
+ case GL_ZERO:
+ case GL_REPLACE:
+ case GL_INCR:
+ case GL_DECR:
+ case GL_INVERT:
+ return true;
+ }
+ return false;
+}
+
+static void enable_disable(ogles_context_t* c, GLenum cap, int enabled)
+{
+ if ((cap >= GL_LIGHT0) && (cap<GL_LIGHT0+OGLES_MAX_LIGHTS)) {
+ c->lighting.lights[cap-GL_LIGHT0].enable = enabled;
+ c->lighting.enabledLights &= ~(1<<(cap-GL_LIGHT0));
+ c->lighting.enabledLights |= (enabled<<(cap-GL_LIGHT0));
+ return;
+ }
+
+ switch (cap) {
+ case GL_POINT_SMOOTH:
+ c->point.smooth = enabled;
+ break;
+ case GL_LINE_SMOOTH:
+ c->line.smooth = enabled;
+ break;
+ case GL_POLYGON_OFFSET_FILL:
+ c->polygonOffset.enable = enabled;
+ break;
+ case GL_CULL_FACE:
+ c->cull.enable = enabled;
+ break;
+ case GL_LIGHTING:
+ c->lighting.enable = enabled;
+ break;
+ case GL_COLOR_MATERIAL:
+ c->lighting.colorMaterial.enable = enabled;
+ break;
+ case GL_NORMALIZE:
+ case GL_RESCALE_NORMAL:
+ c->transforms.rescaleNormals = enabled ? cap : 0;
+ // XXX: invalidate mvit
+ break;
+
+ case GL_CLIP_PLANE0:
+ case GL_CLIP_PLANE1:
+ case GL_CLIP_PLANE2:
+ case GL_CLIP_PLANE3:
+ case GL_CLIP_PLANE4:
+ case GL_CLIP_PLANE5:
+ c->clipPlanes.enable &= ~(1<<(cap-GL_CLIP_PLANE0));
+ c->clipPlanes.enable |= (enabled<<(cap-GL_CLIP_PLANE0));
+ ogles_invalidate_perspective(c);
+ break;
+
+ case GL_FOG:
+ case GL_DEPTH_TEST:
+ ogles_invalidate_perspective(c);
+ // fall-through...
+ case GL_BLEND:
+ case GL_SCISSOR_TEST:
+ case GL_ALPHA_TEST:
+ case GL_COLOR_LOGIC_OP:
+ case GL_DITHER:
+ case GL_STENCIL_TEST:
+ case GL_TEXTURE_2D:
+ // these need to fall through into the rasterizer
+ c->rasterizer.procs.enableDisable(c, cap, enabled);
+ break;
+
+ case GL_MULTISAMPLE:
+ case GL_SAMPLE_ALPHA_TO_COVERAGE:
+ case GL_SAMPLE_ALPHA_TO_ONE:
+ case GL_SAMPLE_COVERAGE:
+ // not supported in this implementation
+ break;
+
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+using namespace android;
+
+#if 0
+#pragma mark -
+#endif
+
+// These ones are super-easy, we're not supporting those features!
+void glSampleCoverage(GLclampf value, GLboolean invert) {
+}
+void glSampleCoveragex(GLclampx value, GLboolean invert) {
+}
+void glStencilFunc(GLenum func, GLint ref, GLuint mask) {
+ ogles_context_t* c = ogles_context_t::get();
+ if (func < GL_NEVER || func > GL_ALWAYS) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ // from OpenGL|ES 1.0 sepcification:
+ // If there is no stencil buffer, no stencil modification can occur
+ // and it is as if the stencil test always passes.
+}
+
+void glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) {
+ ogles_context_t* c = ogles_context_t::get();
+ if ((stencilop_valid(fail) &
+ stencilop_valid(zfail) &
+ stencilop_valid(zpass)) == 0) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+void glAlphaFunc(GLenum func, GLclampf ref)
+{
+ glAlphaFuncx(func, gglFloatToFixed(ref));
+}
+
+void glCullFace(GLenum mode)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ switch (mode) {
+ case GL_FRONT:
+ case GL_BACK:
+ case GL_FRONT_AND_BACK:
+ break;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ }
+ c->cull.cullFace = mode;
+}
+
+void glFrontFace(GLenum mode)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ switch (mode) {
+ case GL_CW:
+ case GL_CCW:
+ break;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ c->cull.frontFace = mode;
+}
+
+void glHint(GLenum target, GLenum mode)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ switch (target) {
+ case GL_FOG_HINT:
+ case GL_GENERATE_MIPMAP_HINT:
+ case GL_LINE_SMOOTH_HINT:
+ break;
+ case GL_POINT_SMOOTH_HINT:
+ c->rasterizer.procs.enableDisable(c,
+ GGL_POINT_SMOOTH_NICE, mode==GL_NICEST);
+ break;
+ case GL_PERSPECTIVE_CORRECTION_HINT:
+ c->perspective = (mode == GL_NICEST) ? 1 : 0;
+ break;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ }
+}
+
+void glEnable(GLenum cap) {
+ ogles_context_t* c = ogles_context_t::get();
+ enable_disable(c, cap, 1);
+}
+void glDisable(GLenum cap) {
+ ogles_context_t* c = ogles_context_t::get();
+ enable_disable(c, cap, 0);
+}
+
+void glFinish()
+{ // nothing to do for our software implementation
+}
+
+void glFlush()
+{ // nothing to do for our software implementation
+}
+
+GLenum glGetError()
+{
+ // From OpenGL|ES 1.0 specification:
+ // If more than one flag has recorded an error, glGetError returns
+ // and clears an arbitrary error flag value. Thus, glGetError should
+ // always be called in a loop, until it returns GL_NO_ERROR,
+ // if all error flags are to be reset.
+
+ ogles_context_t* c = ogles_context_t::get();
+ if (c->error) {
+ const GLenum ret(c->error);
+ c->error = 0;
+ return ret;
+ }
+
+ if (c->rasterizer.error) {
+ const GLenum ret(c->rasterizer.error);
+ c->rasterizer.error = 0;
+ return ret;
+ }
+
+ return GL_NO_ERROR;
+}
+
+const GLubyte* glGetString(GLenum string)
+{
+ switch (string) {
+ case GL_VENDOR: return (const GLubyte*)gVendorString;
+ case GL_RENDERER: return (const GLubyte*)gRendererString;
+ case GL_VERSION: return (const GLubyte*)gVersionString;
+ case GL_EXTENSIONS: return (const GLubyte*)gExtensionsString;
+ }
+ ogles_context_t* c = ogles_context_t::get();
+ ogles_error(c, GL_INVALID_ENUM);
+ return 0;
+}
+
+void glGetIntegerv(GLenum pname, GLint *params)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ switch (pname) {
+ case GL_ALIASED_POINT_SIZE_RANGE:
+ params[0] = 0;
+ params[1] = GGL_MAX_ALIASED_POINT_SIZE;
+ break;
+ case GL_ALIASED_LINE_WIDTH_RANGE:
+ params[0] = 0;
+ params[1] = GGL_MAX_ALIASED_POINT_SIZE;
+ break;
+ case GL_ALPHA_BITS: {
+ int index = c->rasterizer.state.buffers.color.format;
+ GGLFormat const * formats = gglGetPixelFormatTable();
+ params[0] = formats[index].ah - formats[index].al;
+ break;
+ }
+ case GL_RED_BITS: {
+ int index = c->rasterizer.state.buffers.color.format;
+ GGLFormat const * formats = gglGetPixelFormatTable();
+ params[0] = formats[index].rh - formats[index].rl;
+ break;
+ }
+ case GL_GREEN_BITS: {
+ int index = c->rasterizer.state.buffers.color.format;
+ GGLFormat const * formats = gglGetPixelFormatTable();
+ params[0] = formats[index].gh - formats[index].gl;
+ break;
+ }
+ case GL_BLUE_BITS: {
+ int index = c->rasterizer.state.buffers.color.format;
+ GGLFormat const * formats = gglGetPixelFormatTable();
+ params[0] = formats[index].bh - formats[index].bl;
+ break;
+ }
+ case GL_COMPRESSED_TEXTURE_FORMATS:
+ params[ 0] = GL_PALETTE4_RGB8_OES;
+ params[ 1] = GL_PALETTE4_RGBA8_OES;
+ params[ 2] = GL_PALETTE4_R5_G6_B5_OES;
+ params[ 3] = GL_PALETTE4_RGBA4_OES;
+ params[ 4] = GL_PALETTE4_RGB5_A1_OES;
+ params[ 5] = GL_PALETTE8_RGB8_OES;
+ params[ 6] = GL_PALETTE8_RGBA8_OES;
+ params[ 7] = GL_PALETTE8_R5_G6_B5_OES;
+ params[ 8] = GL_PALETTE8_RGBA4_OES;
+ params[ 9] = GL_PALETTE8_RGB5_A1_OES;
+ break;
+ case GL_DEPTH_BITS:
+ params[0] = c->rasterizer.state.buffers.depth.format ? 0 : 16;
+ break;
+ case GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES:
+ params[0] = GL_RGB;
+ break;
+ case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES:
+ params[0] = GL_UNSIGNED_SHORT_5_6_5;
+ break;
+ case GL_MAX_LIGHTS:
+ params[0] = OGLES_MAX_LIGHTS;
+ break;
+ case GL_MAX_CLIP_PLANES:
+ params[0] = OGLES_MAX_CLIP_PLANES;
+ break;
+ case GL_MAX_MODELVIEW_STACK_DEPTH:
+ params[0] = OGLES_MODELVIEW_STACK_DEPTH;
+ break;
+ case GL_MAX_PROJECTION_STACK_DEPTH:
+ params[0] = OGLES_PROJECTION_STACK_DEPTH;
+ break;
+ case GL_MAX_TEXTURE_STACK_DEPTH:
+ params[0] = OGLES_TEXTURE_STACK_DEPTH;
+ break;
+ case GL_MAX_TEXTURE_SIZE:
+ params[0] = GGL_MAX_TEXTURE_SIZE;
+ break;
+ case GL_MAX_TEXTURE_UNITS:
+ params[0] = GGL_TEXTURE_UNIT_COUNT;
+ break;
+ case GL_MAX_VIEWPORT_DIMS:
+ params[0] = GGL_MAX_VIEWPORT_DIMS;
+ params[1] = GGL_MAX_VIEWPORT_DIMS;
+ break;
+ case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
+ params[0] = OGLES_NUM_COMPRESSED_TEXTURE_FORMATS;
+ break;
+ case GL_SMOOTH_LINE_WIDTH_RANGE:
+ params[0] = 0;
+ params[1] = GGL_MAX_SMOOTH_LINE_WIDTH;
+ break;
+ case GL_SMOOTH_POINT_SIZE_RANGE:
+ params[0] = 0;
+ params[1] = GGL_MAX_SMOOTH_POINT_SIZE;
+ break;
+ case GL_STENCIL_BITS:
+ params[0] = 0;
+ break;
+ case GL_SUBPIXEL_BITS:
+ params[0] = GGL_SUBPIXEL_BITS;
+ break;
+
+ case GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES:
+ memcpy( params,
+ c->transforms.modelview.top().elements(),
+ 16*sizeof(GLint));
+ break;
+ case GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES:
+ memcpy( params,
+ c->transforms.projection.top().elements(),
+ 16*sizeof(GLint));
+ break;
+ case GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES:
+ memcpy( params,
+ c->transforms.texture[c->textures.active].top().elements(),
+ 16*sizeof(GLint));
+ break;
+
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ break;
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+void glPointSize(GLfloat size)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (size <= 0) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ c->point.size = TRI_FROM_FIXED(gglFloatToFixed(size));
+}
+
+void glPointSizex(GLfixed size)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (size <= 0) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ c->point.size = TRI_FROM_FIXED(size);
+}
+
+// ----------------------------------------------------------------------------
+
+void glLineWidth(GLfloat width)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (width <= 0) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ c->line.width = TRI_FROM_FIXED(gglFloatToFixed(width));
+}
+
+void glLineWidthx(GLfixed width)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (width <= 0) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ c->line.width = TRI_FROM_FIXED(width);
+}
+
+// ----------------------------------------------------------------------------
+
+void glColorMask(GLboolean r, GLboolean g, GLboolean b, GLboolean a) {
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.colorMask(c, r, g, b, a);
+}
+
+void glDepthMask(GLboolean flag) {
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.depthMask(c, flag);
+}
+
+void glStencilMask(GLuint mask) {
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.stencilMask(c, mask);
+}
+
+void glDepthFunc(GLenum func) {
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.depthFunc(c, func);
+}
+
+void glLogicOp(GLenum opcode) {
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.logicOp(c, opcode);
+}
+
+void glAlphaFuncx(GLenum func, GLclampx ref) {
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.alphaFuncx(c, func, ref);
+}
+
+void glBlendFunc(GLenum sfactor, GLenum dfactor) {
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.blendFunc(c, sfactor, dfactor);
+}
+
+void glClear(GLbitfield mask) {
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.clear(c, mask);
+}
+
+void glClearColorx(GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha) {
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.clearColorx(c, red, green, blue, alpha);
+}
+
+void glClearColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.clearColorx(c,
+ gglFloatToFixed(r),
+ gglFloatToFixed(g),
+ gglFloatToFixed(b),
+ gglFloatToFixed(a));
+}
+
+void glClearDepthx(GLclampx depth) {
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.clearDepthx(c, depth);
+}
+
+void glClearDepthf(GLclampf depth)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.clearDepthx(c, gglFloatToFixed(depth));
+}
+
+void glClearStencil(GLint s) {
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.clearStencil(c, s);
+}
diff --git a/opengl/libagl/state.h b/opengl/libagl/state.h
new file mode 100644
index 0000000..55a5ccb
--- /dev/null
+++ b/opengl/libagl/state.h
@@ -0,0 +1,54 @@
+/* libs/opengles/state.h
+**
+** 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.
+*/
+
+#ifndef ANDROID_OPENGLES_STATE_H
+#define ANDROID_OPENGLES_STATE_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <private/pixelflinger/ggl_context.h>
+
+#include <GLES/gl.h>
+
+#include <stdio.h>
+
+namespace android {
+
+ogles_context_t *ogles_init(size_t extra);
+void ogles_uninit(ogles_context_t* c);
+void _ogles_error(ogles_context_t* c, GLenum error);
+
+#ifndef TRACE_GL_ERRORS
+#define TRACE_GL_ERRORS 0
+#endif
+
+#if TRACE_GL_ERRORS
+#define ogles_error(c, error) \
+do { \
+ printf("ogles_error at file %s line %d\n", __FILE__, __LINE__); \
+ _ogles_error(c, error); \
+} while (0)
+#else /* !TRACE_GL_ERRORS */
+#define ogles_error(c, error) _ogles_error((c), (error))
+#endif
+
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_STATE_H
+
diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp
new file mode 100644
index 0000000..b6f534b
--- /dev/null
+++ b/opengl/libagl/texture.cpp
@@ -0,0 +1,1421 @@
+/* libs/opengles/texture.cpp
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+#include "context.h"
+#include "fp.h"
+#include "state.h"
+#include "texture.h"
+#include "TextureObjectManager.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static void bindTextureTmu(
+ ogles_context_t* c, int tmu, GLuint texture, const sp<EGLTextureObject>& tex);
+
+static __attribute__((noinline))
+void generateMipmap(ogles_context_t* c, GLint level);
+
+// ----------------------------------------------------------------------------
+
+#if 0
+#pragma mark -
+#pragma mark Init
+#endif
+
+void ogles_init_texture(ogles_context_t* c)
+{
+ c->textures.packAlignment = 4;
+ c->textures.unpackAlignment = 4;
+
+ // each context has a default named (0) texture (not shared)
+ c->textures.defaultTexture = new EGLTextureObject();
+ c->textures.defaultTexture->incStrong(c);
+
+ // bind the default texture to each texture unit
+ for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ bindTextureTmu(c, i, 0, c->textures.defaultTexture);
+ memset(c->current.texture[i].v, 0, sizeof(vec4_t));
+ c->current.texture[i].Q = 0x10000;
+ }
+}
+
+void ogles_uninit_texture(ogles_context_t* c)
+{
+ if (c->textures.ggl)
+ gglUninit(c->textures.ggl);
+ c->textures.defaultTexture->decStrong(c);
+ for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ if (c->textures.tmu[i].texture)
+ c->textures.tmu[i].texture->decStrong(c);
+ }
+}
+
+static __attribute__((noinline))
+void validate_tmu(ogles_context_t* c, int i)
+{
+ texture_unit_t& u(c->textures.tmu[i]);
+ if (u.dirty) {
+ u.dirty = 0;
+ c->rasterizer.procs.activeTexture(c, i);
+ c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
+ c->rasterizer.procs.texGeni(c, GGL_S,
+ GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC);
+ c->rasterizer.procs.texGeni(c, GGL_T,
+ GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC);
+ c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
+ GGL_TEXTURE_WRAP_S, u.texture->wraps);
+ c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
+ GGL_TEXTURE_WRAP_T, u.texture->wrapt);
+ c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
+ GGL_TEXTURE_MIN_FILTER, u.texture->min_filter);
+ c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
+ GGL_TEXTURE_MAG_FILTER, u.texture->mag_filter);
+
+ // disable this texture unit if it's not complete
+ if (!u.texture->isComplete()) {
+ c->rasterizer.procs.disable(c, GGL_TEXTURE_2D);
+ }
+ }
+}
+
+void ogles_validate_texture_impl(ogles_context_t* c)
+{
+ for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ if (c->rasterizer.state.texture[i].enable)
+ validate_tmu(c, i);
+ }
+ c->rasterizer.procs.activeTexture(c, c->textures.active);
+}
+
+static
+void invalidate_texture(ogles_context_t* c, int tmu, uint8_t flags = 0xFF) {
+ c->textures.tmu[tmu].dirty = flags;
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Format conversion
+#endif
+
+static uint32_t gl2format_table[6][4] = {
+ // BYTE, 565, 4444, 5551
+ { GGL_PIXEL_FORMAT_A_8,
+ 0, 0, 0 }, // GL_ALPHA
+ { GGL_PIXEL_FORMAT_RGB_888,
+ GGL_PIXEL_FORMAT_RGB_565,
+ 0, 0 }, // GL_RGB
+ { GGL_PIXEL_FORMAT_RGBA_8888,
+ 0,
+ GGL_PIXEL_FORMAT_RGBA_4444,
+ GGL_PIXEL_FORMAT_RGBA_5551 }, // GL_RGBA
+ { GGL_PIXEL_FORMAT_L_8,
+ 0, 0, 0 }, // GL_LUMINANCE
+ { GGL_PIXEL_FORMAT_LA_88,
+ 0, 0, 0 }, // GL_LUMINANCE_ALPHA
+};
+
+static int32_t convertGLPixelFormat(GLint format, GLenum type)
+{
+ int32_t fi = -1;
+ int32_t ti = -1;
+ switch (format) {
+ case GL_ALPHA: fi = 0; break;
+ case GL_RGB: fi = 1; break;
+ case GL_RGBA: fi = 2; break;
+ case GL_LUMINANCE: fi = 3; break;
+ case GL_LUMINANCE_ALPHA: fi = 4; break;
+ }
+ switch (type) {
+ case GL_UNSIGNED_BYTE: ti = 0; break;
+ case GL_UNSIGNED_SHORT_5_6_5: ti = 1; break;
+ case GL_UNSIGNED_SHORT_4_4_4_4: ti = 2; break;
+ case GL_UNSIGNED_SHORT_5_5_5_1: ti = 3; break;
+ }
+ if (fi==-1 || ti==-1)
+ return 0;
+ return gl2format_table[fi][ti];
+}
+
+// ----------------------------------------------------------------------------
+
+static GLenum validFormatType(ogles_context_t* c, GLenum format, GLenum type)
+{
+ GLenum error = 0;
+ if (format<GL_ALPHA || format>GL_LUMINANCE_ALPHA) {
+ error = GL_INVALID_ENUM;
+ }
+ if (type != GL_UNSIGNED_BYTE && type != GL_UNSIGNED_SHORT_4_4_4_4 &&
+ type != GL_UNSIGNED_SHORT_5_5_5_1 && type != GL_UNSIGNED_SHORT_5_6_5) {
+ error = GL_INVALID_ENUM;
+ }
+ if (type == GL_UNSIGNED_SHORT_5_6_5 && format != GL_RGB) {
+ error = GL_INVALID_OPERATION;
+ }
+ if ((type == GL_UNSIGNED_SHORT_4_4_4_4 ||
+ type == GL_UNSIGNED_SHORT_5_5_5_1) && format != GL_RGBA) {
+ error = GL_INVALID_OPERATION;
+ }
+ if (error) {
+ ogles_error(c, error);
+ }
+ return error;
+}
+
+// ----------------------------------------------------------------------------
+
+GGLContext* getRasterizer(ogles_context_t* c)
+{
+ GGLContext* ggl = c->textures.ggl;
+ if (ggl_unlikely(!ggl)) {
+ // this is quite heavy the first time...
+ gglInit(&ggl);
+ if (!ggl) {
+ return 0;
+ }
+ GGLfixed colors[4] = { 0, 0, 0, 0x10000 };
+ c->textures.ggl = ggl;
+ ggl->activeTexture(ggl, 0);
+ ggl->enable(ggl, GGL_TEXTURE_2D);
+ ggl->texEnvi(ggl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
+ ggl->disable(ggl, GGL_DITHER);
+ ggl->shadeModel(ggl, GGL_FLAT);
+ ggl->color4xv(ggl, colors);
+ }
+ return ggl;
+}
+
+static __attribute__((noinline))
+int copyPixels(
+ ogles_context_t* c,
+ const GGLSurface& dst,
+ GLint xoffset, GLint yoffset,
+ const GGLSurface& src,
+ GLint x, GLint y, GLsizei w, GLsizei h)
+{
+ if ((dst.format == src.format) &&
+ (dst.stride == src.stride) &&
+ (dst.width == src.width) &&
+ (dst.height == src.height) &&
+ (dst.stride > 0) &&
+ ((x|y) == 0) &&
+ ((xoffset|yoffset) == 0))
+ {
+ // this is a common case...
+ const GGLFormat& pixelFormat(c->rasterizer.formats[src.format]);
+ const size_t size = src.height * src.stride * pixelFormat.size;
+ memcpy(dst.data, src.data, size);
+ return 0;
+ }
+
+ // use pixel-flinger to handle all the conversions
+ GGLContext* ggl = getRasterizer(c);
+ if (!ggl) {
+ // the only reason this would fail is because we ran out of memory
+ return GL_OUT_OF_MEMORY;
+ }
+
+ ggl->colorBuffer(ggl, &dst);
+ ggl->bindTexture(ggl, &src);
+ ggl->texCoord2i(ggl, x-xoffset, y-yoffset);
+ ggl->recti(ggl, xoffset, yoffset, xoffset+w, yoffset+h);
+ return 0;
+}
+
+// ----------------------------------------------------------------------------
+
+static __attribute__((noinline))
+sp<EGLTextureObject> getAndBindActiveTextureObject(ogles_context_t* c)
+{
+ sp<EGLTextureObject> tex;
+ const int active = c->textures.active;
+ const GLuint name = c->textures.tmu[active].name;
+
+ // free the reference to the previously bound object
+ texture_unit_t& u(c->textures.tmu[active]);
+ if (u.texture)
+ u.texture->decStrong(c);
+
+ if (name == 0) {
+ // 0 is our local texture object, not shared with anyone.
+ // But it affects all bound TMUs immediately.
+ // (we need to invalidate all units bound to this texture object)
+ tex = c->textures.defaultTexture;
+ for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ if (c->textures.tmu[i].texture == tex.get())
+ invalidate_texture(c, i);
+ }
+ } else {
+ // get a new texture object for that name
+ tex = c->surfaceManager->replaceTexture(name);
+ }
+
+ // bind this texture to the current active texture unit
+ // and add a reference to this texture object
+ u.texture = tex.get();
+ u.texture->incStrong(c);
+ u.name = name;
+ invalidate_texture(c, active);
+ return tex;
+}
+
+void bindTextureTmu(
+ ogles_context_t* c, int tmu, GLuint texture, const sp<EGLTextureObject>& tex)
+{
+ if (tex.get() == c->textures.tmu[tmu].texture)
+ return;
+
+ // free the reference to the previously bound object
+ texture_unit_t& u(c->textures.tmu[tmu]);
+ if (u.texture)
+ u.texture->decStrong(c);
+
+ // bind this texture to the current active texture unit
+ // and add a reference to this texture object
+ u.texture = tex.get();
+ u.texture->incStrong(c);
+ u.name = texture;
+ invalidate_texture(c, tmu);
+}
+
+int createTextureSurface(ogles_context_t* c,
+ GGLSurface** outSurface, int32_t* outSize, GLint level,
+ GLenum format, GLenum type, GLsizei width, GLsizei height,
+ GLenum compressedFormat = 0)
+{
+ // find out which texture is bound to the current unit
+ const int active = c->textures.active;
+ const GLuint name = c->textures.tmu[active].name;
+
+ // convert the pixelformat to one we can handle
+ const int32_t formatIdx = convertGLPixelFormat(format, type);
+ if (formatIdx == 0) { // we don't know what to do with this
+ return GL_INVALID_OPERATION;
+ }
+
+ // figure out the size we need as well as the stride
+ const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
+ const int32_t align = c->textures.unpackAlignment-1;
+ const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
+ const size_t size = bpr * height;
+ const int32_t stride = bpr / pixelFormat.size;
+
+ if (level > 0) {
+ const int active = c->textures.active;
+ EGLTextureObject* tex = c->textures.tmu[active].texture;
+ status_t err = tex->reallocate(level,
+ width, height, stride, formatIdx, compressedFormat, bpr);
+ if (err != NO_ERROR)
+ return GL_OUT_OF_MEMORY;
+ GGLSurface& surface = tex->editMip(level);
+ *outSurface = &surface;
+ *outSize = size;
+ return 0;
+ }
+
+ sp<EGLTextureObject> tex = getAndBindActiveTextureObject(c);
+ status_t err = tex->reallocate(level,
+ width, height, stride, formatIdx, compressedFormat, bpr);
+ if (err != NO_ERROR)
+ return GL_OUT_OF_MEMORY;
+
+ tex->internalformat = format;
+ *outSurface = &tex->surface;
+ *outSize = size;
+ return 0;
+}
+
+static void decodePalette4(const GLvoid *data, int level, int width, int height,
+ void *surface, int stride, int format)
+
+{
+ int indexBits = 8;
+ int entrySize = 0;
+ switch (format) {
+ case GL_PALETTE4_RGB8_OES:
+ indexBits = 4;
+ /* FALLTHROUGH */
+ case GL_PALETTE8_RGB8_OES:
+ entrySize = 3;
+ break;
+
+ case GL_PALETTE4_RGBA8_OES:
+ indexBits = 4;
+ /* FALLTHROUGH */
+ case GL_PALETTE8_RGBA8_OES:
+ entrySize = 4;
+ break;
+
+ case GL_PALETTE4_R5_G6_B5_OES:
+ case GL_PALETTE4_RGBA4_OES:
+ case GL_PALETTE4_RGB5_A1_OES:
+ indexBits = 4;
+ /* FALLTHROUGH */
+ case GL_PALETTE8_R5_G6_B5_OES:
+ case GL_PALETTE8_RGBA4_OES:
+ case GL_PALETTE8_RGB5_A1_OES:
+ entrySize = 2;
+ break;
+ }
+
+ const int paletteSize = (1 << indexBits) * entrySize;
+ uint8_t const* pixels = (uint8_t *)data + paletteSize;
+ for (int i=0 ; i<level ; i++) {
+ int w = (width >> i) ? : 1;
+ int h = (height >> i) ? : 1;
+ pixels += h * ((w * indexBits) / 8);
+ }
+ width = (width >> level) ? : 1;
+ height = (height >> level) ? : 1;
+
+ if (entrySize == 2) {
+ uint8_t const* const palette = (uint8_t*)data;
+ for (int y=0 ; y<height ; y++) {
+ uint8_t* p = (uint8_t*)surface + y*stride*2;
+ if (indexBits == 8) {
+ for (int x=0 ; x<width ; x++) {
+ int index = 2 * (*pixels++);
+ *p++ = palette[index + 0];
+ *p++ = palette[index + 1];
+ }
+ } else {
+ for (int x=0 ; x<width ; x+=2) {
+ int v = *pixels++;
+ int index = 2 * (v >> 4);
+ *p++ = palette[index + 0];
+ *p++ = palette[index + 1];
+ if (x+1 < width) {
+ index = 2 * (v & 0xF);
+ *p++ = palette[index + 0];
+ *p++ = palette[index + 1];
+ }
+ }
+ }
+ }
+ } else if (entrySize == 3) {
+ uint8_t const* const palette = (uint8_t*)data;
+ for (int y=0 ; y<height ; y++) {
+ uint8_t* p = (uint8_t*)surface + y*stride*3;
+ if (indexBits == 8) {
+ for (int x=0 ; x<width ; x++) {
+ int index = 3 * (*pixels++);
+ *p++ = palette[index + 0];
+ *p++ = palette[index + 1];
+ *p++ = palette[index + 2];
+ }
+ } else {
+ for (int x=0 ; x<width ; x+=2) {
+ int v = *pixels++;
+ int index = 3 * (v >> 4);
+ *p++ = palette[index + 0];
+ *p++ = palette[index + 1];
+ *p++ = palette[index + 2];
+ if (x+1 < width) {
+ index = 3 * (v & 0xF);
+ *p++ = palette[index + 0];
+ *p++ = palette[index + 1];
+ *p++ = palette[index + 2];
+ }
+ }
+ }
+ }
+ } else if (entrySize == 4) {
+ uint8_t const* const palette = (uint8_t*)data;
+ for (int y=0 ; y<height ; y++) {
+ uint8_t* p = (uint8_t*)surface + y*stride*4;
+ if (indexBits == 8) {
+ for (int x=0 ; x<width ; x++) {
+ int index = 4 * (*pixels++);
+ *p++ = palette[index + 0];
+ *p++ = palette[index + 1];
+ *p++ = palette[index + 2];
+ *p++ = palette[index + 3];
+ }
+ } else {
+ for (int x=0 ; x<width ; x+=2) {
+ int v = *pixels++;
+ int index = 4 * (v >> 4);
+ *p++ = palette[index + 0];
+ *p++ = palette[index + 1];
+ *p++ = palette[index + 2];
+ *p++ = palette[index + 3];
+ if (x+1 < width) {
+ index = 4 * (v & 0xF);
+ *p++ = palette[index + 0];
+ *p++ = palette[index + 1];
+ *p++ = palette[index + 2];
+ *p++ = palette[index + 3];
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+static __attribute__((noinline))
+void set_depth_and_fog(ogles_context_t* c, GLint z)
+{
+ const uint32_t enables = c->rasterizer.state.enables;
+ // we need to compute Zw
+ int32_t iterators[3];
+ iterators[1] = iterators[2] = 0;
+ GGLfixed Zw;
+ GGLfixed n = gglFloatToFixed(c->transforms.vpt.zNear);
+ GGLfixed f = gglFloatToFixed(c->transforms.vpt.zFar);
+ if (z<=0) Zw = n;
+ else if (z>=1) Zw = f;
+ else Zw = gglMulAddx(z, (f-n), n);
+ if (enables & GGL_ENABLE_FOG) {
+ // set up fog if needed...
+ iterators[0] = c->fog.fog(c, Zw);
+ c->rasterizer.procs.fogGrad3xv(c, iterators);
+ }
+ if (enables & GGL_ENABLE_DEPTH_TEST) {
+ // set up z-test if needed...
+ int32_t z = (Zw & ~(Zw>>31));
+ if (z >= 0x10000)
+ z = 0xFFFF;
+ iterators[0] = (z << 16) | z;
+ c->rasterizer.procs.zGrad3xv(c, iterators);
+ }
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Generate mimaps
+#endif
+
+extern status_t buildAPyramid(ogles_context_t* c, EGLTextureObject* tex);
+
+void generateMipmap(ogles_context_t* c, GLint level)
+{
+ if (level == 0) {
+ const int active = c->textures.active;
+ EGLTextureObject* tex = c->textures.tmu[active].texture;
+ if (tex->generate_mipmap) {
+ if (buildAPyramid(c, tex) != NO_ERROR) {
+ ogles_error(c, GL_OUT_OF_MEMORY);
+ return;
+ }
+ }
+ }
+}
+
+
+static void texParameterx(
+ GLenum target, GLenum pname, GLfixed param, ogles_context_t* c)
+{
+ if (target != GL_TEXTURE_2D) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+
+ EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture;
+ switch (pname) {
+ case GL_TEXTURE_WRAP_S:
+ if ((param == GL_REPEAT) ||
+ (param == GL_CLAMP_TO_EDGE)) {
+ textureObject->wraps = param;
+ } else {
+ goto invalid_enum;
+ }
+ break;
+ case GL_TEXTURE_WRAP_T:
+ if ((param == GL_REPEAT) ||
+ (param == GL_CLAMP_TO_EDGE)) {
+ textureObject->wrapt = param;
+ } else {
+ goto invalid_enum;
+ }
+ break;
+ case GL_TEXTURE_MIN_FILTER:
+ if ((param == GL_NEAREST) ||
+ (param == GL_LINEAR) ||
+ (param == GL_NEAREST_MIPMAP_NEAREST) ||
+ (param == GL_LINEAR_MIPMAP_NEAREST) ||
+ (param == GL_NEAREST_MIPMAP_LINEAR) ||
+ (param == GL_LINEAR_MIPMAP_LINEAR)) {
+ textureObject->min_filter = param;
+ } else {
+ goto invalid_enum;
+ }
+ break;
+ case GL_TEXTURE_MAG_FILTER:
+ if ((param == GL_NEAREST) ||
+ (param == GL_LINEAR)) {
+ textureObject->mag_filter = param;
+ } else {
+ goto invalid_enum;
+ }
+ break;
+ case GL_GENERATE_MIPMAP:
+ textureObject->generate_mipmap = param;
+ break;
+ default:
+invalid_enum:
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ invalidate_texture(c, c->textures.active);
+}
+
+
+static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
+ ogles_context_t* c)
+{
+ // quickly reject empty rects
+ if ((w|h) <= 0)
+ return;
+
+ const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
+ y = gglIntToFixed(cbSurface.height) - (y + h);
+ w >>= FIXED_BITS;
+ h >>= FIXED_BITS;
+
+ // set up all texture units
+ for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ if (!c->rasterizer.state.texture[i].enable)
+ continue;
+
+ int32_t texcoords[8];
+ texture_unit_t& u(c->textures.tmu[i]);
+
+ // validate this tmu (bind, wrap, filter)
+ validate_tmu(c, i);
+ // we CLAMP here, which works with premultiplied (s,t)
+ c->rasterizer.procs.texParameteri(c,
+ GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_S, GGL_CLAMP);
+ c->rasterizer.procs.texParameteri(c,
+ GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_T, GGL_CLAMP);
+ u.dirty = 0xFF; // XXX: should be more subtle
+
+ EGLTextureObject* textureObject = u.texture;
+ const GLint Ucr = textureObject->crop_rect[0] << 16;
+ const GLint Vcr = textureObject->crop_rect[1] << 16;
+ const GLint Wcr = textureObject->crop_rect[2] << 16;
+ const GLint Hcr = textureObject->crop_rect[3] << 16;
+
+ // computes texture coordinates (pre-multiplied)
+ int32_t dsdx = Wcr / w; // dsdx = ((Wcr/w)/Wt)*Wt
+ int32_t dtdy =-Hcr / h; // dtdy = -((Hcr/h)/Ht)*Ht
+ int32_t s0 = Ucr - gglMulx(dsdx, x); // s0 = Ucr - x * dsdx
+ int32_t t0 = (Vcr+Hcr) - gglMulx(dtdy, y); // t0 = (Vcr+Hcr) - y*dtdy
+ texcoords[0] = s0;
+ texcoords[1] = dsdx;
+ texcoords[2] = 0;
+ texcoords[3] = t0;
+ texcoords[4] = 0;
+ texcoords[5] = dtdy;
+ texcoords[6] = 0;
+ texcoords[7] = 0;
+ c->rasterizer.procs.texCoordGradScale8xv(c, i, texcoords);
+ }
+
+ const uint32_t enables = c->rasterizer.state.enables;
+ if (ggl_unlikely(enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)))
+ set_depth_and_fog(c, z);
+
+ c->rasterizer.procs.activeTexture(c, c->textures.active);
+ c->rasterizer.procs.color4xv(c, c->currentColorClamped.v);
+ c->rasterizer.procs.disable(c, GGL_W_LERP);
+ c->rasterizer.procs.disable(c, GGL_AA);
+ c->rasterizer.procs.shadeModel(c, GL_FLAT);
+ c->rasterizer.procs.recti(c,
+ gglFixedToIntRound(x),
+ gglFixedToIntRound(y),
+ gglFixedToIntRound(x)+w,
+ gglFixedToIntRound(y)+h);
+}
+
+static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_context_t* c)
+{
+ // All coordinates are integer, so if we have only one
+ // texture unit active and no scaling is required
+ // THEN, we can use our special 1:1 mapping
+ // which is a lot faster.
+
+ if (ggl_likely(c->rasterizer.state.enabled_tmu == 1)) {
+ const int tmu = 0;
+ texture_unit_t& u(c->textures.tmu[tmu]);
+ EGLTextureObject* textureObject = u.texture;
+ const GLint Wcr = textureObject->crop_rect[2];
+ const GLint Hcr = textureObject->crop_rect[3];
+
+ if ((w == Wcr) && (h == -Hcr)) {
+ if ((w|h) <= 0) return; // quickly reject empty rects
+
+ if (u.dirty) {
+ c->rasterizer.procs.activeTexture(c, tmu);
+ c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
+ c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
+ GGL_TEXTURE_MIN_FILTER, u.texture->min_filter);
+ c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
+ GGL_TEXTURE_MAG_FILTER, u.texture->mag_filter);
+ }
+ c->rasterizer.procs.texGeni(c, GGL_S,
+ GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
+ c->rasterizer.procs.texGeni(c, GGL_T,
+ GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
+ u.dirty = 0xFF; // XXX: should be more subtle
+ c->rasterizer.procs.activeTexture(c, c->textures.active);
+
+ const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
+ y = cbSurface.height - (y + h);
+ const GLint Ucr = textureObject->crop_rect[0];
+ const GLint Vcr = textureObject->crop_rect[1];
+ const GLint s0 = Ucr - x;
+ const GLint t0 = (Vcr + Hcr) - y;
+
+ const GLuint tw = textureObject->surface.width;
+ const GLuint th = textureObject->surface.height;
+ if ((uint32_t(s0+x+w) > tw) || (uint32_t(t0+y+h) > th)) {
+ // The GL spec is unclear about what should happen
+ // in this case, so we just use the slow case, which
+ // at least won't crash
+ goto slow_case;
+ }
+
+ c->rasterizer.procs.texCoord2i(c, s0, t0);
+ const uint32_t enables = c->rasterizer.state.enables;
+ if (ggl_unlikely(enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)))
+ set_depth_and_fog(c, z);
+
+ c->rasterizer.procs.color4xv(c, c->currentColorClamped.v);
+ c->rasterizer.procs.disable(c, GGL_W_LERP);
+ c->rasterizer.procs.disable(c, GGL_AA);
+ c->rasterizer.procs.shadeModel(c, GL_FLAT);
+ c->rasterizer.procs.recti(c, x, y, x+w, y+h);
+ return;
+ }
+ }
+
+slow_case:
+ drawTexxOES(
+ gglIntToFixed(x), gglIntToFixed(y), gglIntToFixed(z),
+ gglIntToFixed(w), gglIntToFixed(h),
+ c);
+}
+
+
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+
+#if 0
+#pragma mark -
+#pragma mark Texture API
+#endif
+
+void glActiveTexture(GLenum texture)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (uint32_t(texture-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ c->textures.active = texture - GL_TEXTURE0;
+ c->rasterizer.procs.activeTexture(c, c->textures.active);
+}
+
+void glBindTexture(GLenum target, GLuint texture)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (target != GL_TEXTURE_2D) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+
+ // Bind or create a texture
+ sp<EGLTextureObject> tex;
+ if (texture == 0) {
+ // 0 is our local texture object
+ tex = c->textures.defaultTexture;
+ } else {
+ tex = c->surfaceManager->texture(texture);
+ if (ggl_unlikely(tex == 0)) {
+ tex = c->surfaceManager->createTexture(texture);
+ if (tex == 0) {
+ ogles_error(c, GL_OUT_OF_MEMORY);
+ return;
+ }
+ }
+ }
+ bindTextureTmu(c, c->textures.active, texture, tex);
+}
+
+void glGenTextures(GLsizei n, GLuint *textures)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (n<0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ // generate unique (shared) texture names
+ c->surfaceManager->getToken(n, textures);
+}
+
+void glDeleteTextures(GLsizei n, const GLuint *textures)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (n<0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+
+ // If deleting a bound texture, bind this unit to 0
+ for (int t=0 ; t<GGL_TEXTURE_UNIT_COUNT ; t++) {
+ if (c->textures.tmu[t].name == 0)
+ continue;
+ for (int i=0 ; i<n ; i++) {
+ if (textures[i] && (textures[i] == c->textures.tmu[t].name)) {
+ // bind this tmu to texture 0
+ sp<EGLTextureObject> tex(c->textures.defaultTexture);
+ bindTextureTmu(c, t, 0, tex);
+ }
+ }
+ }
+ c->surfaceManager->deleteTextures(n, textures);
+ c->surfaceManager->recycleTokens(n, textures);
+}
+
+void glMultiTexCoord4f(
+ GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (uint32_t(target-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ const int tmu = target-GL_TEXTURE0;
+ c->current.texture[tmu].S = gglFloatToFixed(s);
+ c->current.texture[tmu].T = gglFloatToFixed(t);
+ c->current.texture[tmu].R = gglFloatToFixed(r);
+ c->current.texture[tmu].Q = gglFloatToFixed(q);
+}
+
+void glMultiTexCoord4x(
+ GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (uint32_t(target-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ const int tmu = target-GL_TEXTURE0;
+ c->current.texture[tmu].S = s;
+ c->current.texture[tmu].T = t;
+ c->current.texture[tmu].R = r;
+ c->current.texture[tmu].Q = q;
+}
+
+void glPixelStorei(GLenum pname, GLint param)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if ((pname != GL_PACK_ALIGNMENT) && (pname != GL_UNPACK_ALIGNMENT)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ if ((param<=0 || param>8) || (param & (param-1))) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ if (pname == GL_PACK_ALIGNMENT)
+ c->textures.packAlignment = param;
+ if (pname == GL_UNPACK_ALIGNMENT)
+ c->textures.unpackAlignment = param;
+}
+
+void glTexEnvf(GLenum target, GLenum pname, GLfloat param)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.texEnvi(c, target, pname, GLint(param));
+}
+
+void glTexEnvfv(
+ GLenum target, GLenum pname, const GLfloat *params)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (pname == GL_TEXTURE_ENV_MODE) {
+ c->rasterizer.procs.texEnvi(c, target, pname, GLint(*params));
+ return;
+ }
+ if (pname == GL_TEXTURE_ENV_COLOR) {
+ GGLfixed fixed[4];
+ for (int i=0 ; i<4 ; i++)
+ fixed[i] = gglFloatToFixed(params[i]);
+ c->rasterizer.procs.texEnvxv(c, target, pname, fixed);
+ return;
+ }
+ ogles_error(c, GL_INVALID_ENUM);
+}
+
+void glTexEnvx(GLenum target, GLenum pname, GLfixed param)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.texEnvi(c, target, pname, param);
+}
+
+void glTexEnvxv(
+ GLenum target, GLenum pname, const GLfixed *params)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.texEnvxv(c, target, pname, params);
+}
+
+void glTexParameteriv(
+ GLenum target, GLenum pname, const GLint* params)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (target != GGL_TEXTURE_2D) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+
+ EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture;
+ switch (pname) {
+ case GL_TEXTURE_CROP_RECT_OES:
+ memcpy(textureObject->crop_rect, params, 4*sizeof(GLint));
+ break;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+}
+
+void glTexParameterf(
+ GLenum target, GLenum pname, GLfloat param)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ texParameterx(target, pname, GLfixed(param), c);
+}
+
+void glTexParameterx(
+ GLenum target, GLenum pname, GLfixed param)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ texParameterx(target, pname, param, c);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+void glCompressedTexImage2D(
+ GLenum target, GLint level, GLenum internalformat,
+ GLsizei width, GLsizei height, GLint border,
+ GLsizei imageSize, const GLvoid *data)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (target != GL_TEXTURE_2D) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ if ((internalformat < GL_PALETTE4_RGB8_OES ||
+ internalformat > GL_PALETTE8_RGB5_A1_OES)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ if (width<0 || height<0 || border!=0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+
+ // "uncompress" the texture since pixelflinger doesn't support
+ // any compressed texture format natively.
+ GLenum format;
+ GLenum type;
+ switch (internalformat) {
+ case GL_PALETTE8_RGB8_OES:
+ case GL_PALETTE4_RGB8_OES:
+ format = GL_RGB;
+ type = GL_UNSIGNED_BYTE;
+ break;
+ case GL_PALETTE8_RGBA8_OES:
+ case GL_PALETTE4_RGBA8_OES:
+ format = GL_RGBA;
+ type = GL_UNSIGNED_BYTE;
+ break;
+ case GL_PALETTE8_R5_G6_B5_OES:
+ case GL_PALETTE4_R5_G6_B5_OES:
+ format = GL_RGB;
+ type = GL_UNSIGNED_SHORT_5_6_5;
+ break;
+ case GL_PALETTE8_RGBA4_OES:
+ case GL_PALETTE4_RGBA4_OES:
+ format = GL_RGBA;
+ type = GL_UNSIGNED_SHORT_4_4_4_4;
+ break;
+ case GL_PALETTE8_RGB5_A1_OES:
+ case GL_PALETTE4_RGB5_A1_OES:
+ format = GL_RGBA;
+ type = GL_UNSIGNED_SHORT_5_5_5_1;
+ break;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+
+ if (!data || !width || !height) {
+ // unclear if this is an error or not...
+ return;
+ }
+
+ int32_t size;
+ GGLSurface* surface;
+ // all mipmap levels are specified at once.
+ const int numLevels = level<0 ? -level : 1;
+ for (int i=0 ; i<numLevels ; i++) {
+ int lod_w = (width >> i) ? : 1;
+ int lod_h = (height >> i) ? : 1;
+ int error = createTextureSurface(c, &surface, &size,
+ i, format, type, lod_w, lod_h);
+ if (error) {
+ ogles_error(c, error);
+ return;
+ }
+ decodePalette4(data, i, width, height,
+ surface->data, surface->stride, internalformat);
+ }
+}
+
+
+void glTexImage2D(
+ GLenum target, GLint level, GLint internalformat,
+ GLsizei width, GLsizei height, GLint border,
+ GLenum format, GLenum type, const GLvoid *pixels)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (target != GL_TEXTURE_2D && target != GL_DIRECT_TEXTURE_2D_QUALCOMM) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ if (width<0 || height<0 || border!=0 || level < 0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ if (format != internalformat) {
+ ogles_error(c, GL_INVALID_OPERATION);
+ return;
+ }
+ if (validFormatType(c, format, type)) {
+ return;
+ }
+
+ int32_t size = 0;
+ GGLSurface* surface = 0;
+ if (target != GL_DIRECT_TEXTURE_2D_QUALCOMM) {
+ int error = createTextureSurface(c, &surface, &size,
+ level, format, type, width, height);
+ if (error) {
+ ogles_error(c, error);
+ return;
+ }
+ } else if (pixels == 0 || level != 0) {
+ // pixel can't be null for direct texture
+ ogles_error(c, GL_INVALID_OPERATION);
+ return;
+ }
+
+ if (pixels) {
+ const int32_t formatIdx = convertGLPixelFormat(format, type);
+ const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
+ const int32_t align = c->textures.unpackAlignment-1;
+ const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
+ const size_t size = bpr * height;
+ const int32_t stride = bpr / pixelFormat.size;
+
+ GGLSurface userSurface;
+ userSurface.version = sizeof(userSurface);
+ userSurface.width = width;
+ userSurface.height = height;
+ userSurface.stride = stride;
+ userSurface.format = formatIdx;
+ userSurface.compressedFormat = 0;
+ userSurface.data = (GLubyte*)pixels;
+
+ if (target != GL_DIRECT_TEXTURE_2D_QUALCOMM) {
+ int err = copyPixels(c, *surface, 0, 0, userSurface, 0, 0, width, height);
+ if (err) {
+ ogles_error(c, err);
+ return;
+ }
+ generateMipmap(c, level);
+ } else {
+ // bind it to the texture unit
+ sp<EGLTextureObject> tex = getAndBindActiveTextureObject(c);
+ tex->setSurface(&userSurface);
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+void glCompressedTexSubImage2D(
+ GLenum target, GLint level, GLint xoffset,
+ GLint yoffset, GLsizei width, GLsizei height,
+ GLenum format, GLsizei imageSize,
+ const GLvoid *data)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ ogles_error(c, GL_INVALID_ENUM);
+}
+
+void glTexSubImage2D(
+ GLenum target, GLint level, GLint xoffset,
+ GLint yoffset, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, const GLvoid *pixels)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (target != GL_TEXTURE_2D) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ if (validFormatType(c, format, type)) {
+ return;
+ }
+
+ // find out which texture is bound to the current unit
+ const int active = c->textures.active;
+ EGLTextureObject* tex = c->textures.tmu[active].texture;
+ const GGLSurface& surface(tex->mip(level));
+
+ if (!tex->internalformat || tex->direct) {
+ ogles_error(c, GL_INVALID_OPERATION);
+ return;
+ }
+ if ((xoffset + width > GLsizei(surface.width)) ||
+ (yoffset + height > GLsizei(surface.height))) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ if (!width || !height) {
+ return; // okay, but no-op.
+ }
+
+ // figure out the size we need as well as the stride
+ const int32_t formatIdx = convertGLPixelFormat(format, type);
+ if (formatIdx == 0) { // we don't know what to do with this
+ ogles_error(c, GL_INVALID_OPERATION);
+ return;
+ }
+
+ const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
+ const int32_t align = c->textures.unpackAlignment-1;
+ const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
+ const size_t size = bpr * height;
+ const int32_t stride = bpr / pixelFormat.size;
+ GGLSurface userSurface;
+ userSurface.version = sizeof(userSurface);
+ userSurface.width = width;
+ userSurface.height = height;
+ userSurface.stride = stride;
+ userSurface.format = formatIdx;
+ userSurface.compressedFormat = 0;
+ userSurface.data = (GLubyte*)pixels;
+
+ int err = copyPixels(c,
+ surface, xoffset, yoffset,
+ userSurface, 0, 0, width, height);
+ if (err) {
+ ogles_error(c, err);
+ return;
+ }
+
+ generateMipmap(c, level);
+
+ // since we only changed the content of the texture, we don't need
+ // to call bindTexture on the main rasterizer.
+}
+
+// ----------------------------------------------------------------------------
+
+void glCopyTexImage2D(
+ GLenum target, GLint level, GLenum internalformat,
+ GLint x, GLint y, GLsizei width, GLsizei height,
+ GLint border)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (target != GL_TEXTURE_2D) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ if (internalformat<GL_ALPHA || internalformat>GL_LUMINANCE_ALPHA) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ if (width<0 || height<0 || border!=0 || level<0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+
+ GLenum format = 0;
+ GLenum type = GL_UNSIGNED_BYTE;
+ const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
+ const int cbFormatIdx = cbSurface.format;
+ switch (cbFormatIdx) {
+ case GGL_PIXEL_FORMAT_RGB_565:
+ type = GL_UNSIGNED_SHORT_5_6_5;
+ break;
+ case GGL_PIXEL_FORMAT_RGBA_5551:
+ type = GL_UNSIGNED_SHORT_5_5_5_1;
+ break;
+ case GGL_PIXEL_FORMAT_RGBA_4444:
+ type = GL_UNSIGNED_SHORT_4_4_4_4;
+ break;
+ }
+ switch (internalformat) {
+ case GL_ALPHA:
+ case GL_LUMINANCE_ALPHA:
+ case GL_LUMINANCE:
+ type = GL_UNSIGNED_BYTE;
+ break;
+ }
+
+ // figure out the format to use for the new texture
+ switch (cbFormatIdx) {
+ case GGL_PIXEL_FORMAT_RGBA_8888:
+ case GGL_PIXEL_FORMAT_A_8:
+ case GGL_PIXEL_FORMAT_RGBA_5551:
+ case GGL_PIXEL_FORMAT_RGBA_4444:
+ format = internalformat;
+ break;
+ case GGL_PIXEL_FORMAT_RGBX_8888:
+ case GGL_PIXEL_FORMAT_RGB_888:
+ case GGL_PIXEL_FORMAT_RGB_565:
+ case GGL_PIXEL_FORMAT_L_8:
+ switch (internalformat) {
+ case GL_LUMINANCE:
+ case GL_RGB:
+ format = internalformat;
+ break;
+ }
+ break;
+ }
+
+ if (format == 0) {
+ // invalid combination
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+
+ // create the new texture...
+ int32_t size;
+ GGLSurface* surface;
+ int error = createTextureSurface(c, &surface, &size,
+ level, format, type, width, height);
+ if (error) {
+ ogles_error(c, error);
+ return;
+ }
+
+ // The bottom row is stored first in textures
+ GGLSurface txSurface(*surface);
+ txSurface.stride = -txSurface.stride;
+
+ // (x,y) is the lower-left corner of colorBuffer
+ y = cbSurface.height - (y + height);
+
+ int err = copyPixels(c,
+ txSurface, 0, 0,
+ cbSurface, x, y, cbSurface.width, cbSurface.height);
+ if (err) {
+ ogles_error(c, err);
+ }
+
+ generateMipmap(c, level);
+}
+
+void glCopyTexSubImage2D(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ GLint x, GLint y, GLsizei width, GLsizei height)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (target != GL_TEXTURE_2D) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ if (!width || !height) {
+ return; // okay, but no-op.
+ }
+
+ // find out which texture is bound to the current unit
+ const int active = c->textures.active;
+ EGLTextureObject* tex = c->textures.tmu[active].texture;
+ const GGLSurface& surface(tex->mip(level));
+
+ if (!tex->internalformat) {
+ ogles_error(c, GL_INVALID_OPERATION);
+ return;
+ }
+ if ((xoffset + width > GLsizei(surface.width)) ||
+ (yoffset + height > GLsizei(surface.height))) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+
+ // The bottom row is stored first in textures
+ GGLSurface txSurface(surface);
+ txSurface.stride = -txSurface.stride;
+
+ // (x,y) is the lower-left corner of colorBuffer
+ const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
+ y = cbSurface.height - (y + height);
+
+ int err = copyPixels(c,
+ surface, xoffset, yoffset,
+ cbSurface, x, y, width, height);
+ if (err) {
+ ogles_error(c, err);
+ return;
+ }
+
+ generateMipmap(c, level);
+}
+
+void glReadPixels(
+ GLint x, GLint y, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, GLvoid *pixels)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if ((format != GL_RGBA) && (format != GL_RGB)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ if ((type != GL_UNSIGNED_BYTE) && (type != GL_UNSIGNED_SHORT_5_6_5)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ if (width<0 || height<0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ if (x<0 || x<0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+
+ int32_t formatIdx = GGL_PIXEL_FORMAT_NONE;
+ if ((format == GL_RGBA) && (type == GL_UNSIGNED_BYTE)) {
+ formatIdx = GGL_PIXEL_FORMAT_RGBA_8888;
+ } else if ((format == GL_RGB) && (type == GL_UNSIGNED_SHORT_5_6_5)) {
+ formatIdx = GGL_PIXEL_FORMAT_RGB_565;
+ } else {
+ ogles_error(c, GL_INVALID_OPERATION);
+ return;
+ }
+
+ const GGLSurface& readSurface = c->rasterizer.state.buffers.read.s;
+ if ((x+width > GLint(readSurface.width)) ||
+ (y+height > GLint(readSurface.height))) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+
+ const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
+ const int32_t align = c->textures.packAlignment-1;
+ const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
+ const int32_t stride = bpr / pixelFormat.size;
+
+ GGLSurface userSurface;
+ userSurface.version = sizeof(userSurface);
+ userSurface.width = width;
+ userSurface.height = height;
+ userSurface.stride = -stride; // bottom row is transfered first
+ userSurface.format = formatIdx;
+ userSurface.compressedFormat = 0;
+ userSurface.data = (GLubyte*)pixels;
+
+ // use pixel-flinger to handle all the conversions
+ GGLContext* ggl = getRasterizer(c);
+ if (!ggl) {
+ // the only reason this would fail is because we ran out of memory
+ ogles_error(c, GL_OUT_OF_MEMORY);
+ return;
+ }
+
+ ggl->colorBuffer(ggl, &userSurface); // destination is user buffer
+ ggl->bindTexture(ggl, &readSurface); // source is read-buffer
+ ggl->texCoord2i(ggl, x, readSurface.height - (y + height));
+ ggl->recti(ggl, 0, 0, width, height);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark DrawTexture Extension
+#endif
+
+void glDrawTexsvOES(const GLshort* coords) {
+ ogles_context_t* c = ogles_context_t::get();
+ drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
+}
+void glDrawTexivOES(const GLint* coords) {
+ ogles_context_t* c = ogles_context_t::get();
+ drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
+}
+void glDrawTexsOES(GLshort x , GLshort y, GLshort z, GLshort w, GLshort h) {
+ ogles_context_t* c = ogles_context_t::get();
+ drawTexiOES(x, y, z, w, h, c);
+}
+void glDrawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h) {
+ ogles_context_t* c = ogles_context_t::get();
+ drawTexiOES(x, y, z, w, h, c);
+}
+
+void glDrawTexfvOES(const GLfloat* coords) {
+ ogles_context_t* c = ogles_context_t::get();
+ drawTexxOES(
+ gglFloatToFixed(coords[0]),
+ gglFloatToFixed(coords[1]),
+ gglFloatToFixed(coords[2]),
+ gglFloatToFixed(coords[3]),
+ gglFloatToFixed(coords[4]),
+ c);
+}
+void glDrawTexxvOES(const GLfixed* coords) {
+ ogles_context_t* c = ogles_context_t::get();
+ drawTexxOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
+}
+void glDrawTexfOES(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h){
+ ogles_context_t* c = ogles_context_t::get();
+ drawTexxOES(
+ gglFloatToFixed(x), gglFloatToFixed(y), gglFloatToFixed(z),
+ gglFloatToFixed(w), gglFloatToFixed(h),
+ c);
+}
+void glDrawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h) {
+ ogles_context_t* c = ogles_context_t::get();
+ drawTexxOES(x, y, z, w, h, c);
+}
diff --git a/opengl/libagl/texture.h b/opengl/libagl/texture.h
new file mode 100644
index 0000000..5c57948
--- /dev/null
+++ b/opengl/libagl/texture.h
@@ -0,0 +1,45 @@
+/* libs/opengles/texture.h
+**
+** 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.
+*/
+
+#ifndef ANDROID_OPENGLES_TEXTURE_H
+#define ANDROID_OPENGLES_TEXTURE_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <private/pixelflinger/ggl_context.h>
+
+#include <GLES/gl.h>
+
+#include "context.h"
+
+namespace android {
+
+void ogles_init_texture(ogles_context_t* c);
+void ogles_uninit_texture(ogles_context_t* c);
+void ogles_validate_texture_impl(ogles_context_t* c);
+
+inline void ogles_validate_texture(ogles_context_t* c) {
+ if (c->rasterizer.state.enables & GGL_ENABLE_TMUS)
+ ogles_validate_texture_impl(c);
+}
+
+
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_TEXTURE_H
diff --git a/opengl/libagl/vertex.cpp b/opengl/libagl/vertex.cpp
new file mode 100644
index 0000000..dad04d6
--- /dev/null
+++ b/opengl/libagl/vertex.cpp
@@ -0,0 +1,247 @@
+/* libs/opengles/vertex.cpp
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+#include "context.h"
+#include "fp.h"
+#include "vertex.h"
+#include "state.h"
+#include "matrix.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+void ogles_init_vertex(ogles_context_t* c)
+{
+ c->cull.enable = GL_FALSE;
+ c->cull.cullFace = GL_BACK;
+ c->cull.frontFace = GL_CCW;
+
+ c->current.color.r = 0x10000;
+ c->current.color.g = 0x10000;
+ c->current.color.b = 0x10000;
+ c->current.color.a = 0x10000;
+
+ c->currentNormal.z = 0x10000;
+}
+
+void ogles_uninit_vertex(ogles_context_t* c)
+{
+}
+
+// ----------------------------------------------------------------------------
+// vertex processing
+// ----------------------------------------------------------------------------
+
+// Divides a vertex clip coordinates by W
+static inline
+void perspective(ogles_context_t* c, vertex_t* v, uint32_t enables)
+{
+ // [x,y,z]window = vpt * ([x,y,z]clip / clip.w)
+ // [w]window = 1/w
+
+ // With a regular projection generated by glFrustum(),
+ // we have w=-z, therefore, w is in [zNear, zFar].
+ // Also, zNear and zFar are stricly positive,
+ // and 1/w (window.w) is in [1/zFar, 1/zNear], usually this
+ // means ]0, +inf[ -- however, it is always recommended
+ // to use as large values as possible for zNear.
+ // All in all, w is usually smaller than 1.0 (assuming
+ // zNear is at least 1.0); and even if zNear is smaller than 1.0
+ // values of w won't be too big.
+
+ const int32_t rw = gglRecip28(v->clip.w);
+ const GLfixed* const m = c->transforms.vpt.transform.matrix.m;
+ v->window.w = rw;
+ v->window.x = gglMulAddx(gglMulx(v->clip.x, rw, 16), m[ 0], m[12], 28);
+ v->window.y = gglMulAddx(gglMulx(v->clip.y, rw, 16), m[ 5], m[13], 28);
+ v->window.x = TRI_FROM_FIXED(v->window.x);
+ v->window.y = TRI_FROM_FIXED(v->window.y);
+ if (enables & GGL_ENABLE_DEPTH_TEST) {
+ v->window.z = gglMulAddx(gglMulx(v->clip.z, rw, 16), m[10], m[14], 28);
+ }
+}
+
+// frustum clipping and W-divide
+static inline
+void clipFrustumPerspective(ogles_context_t* c, vertex_t* v, uint32_t enables)
+{
+ // ndc = clip / W
+ // window = ncd * viewport
+
+ // clip to the view-volume
+ uint32_t clip = v->flags & vertex_t::CLIP_ALL;
+ const GLfixed w = v->clip.w;
+ 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;
+
+ if (ggl_likely(!clip)) {
+ // if the vertex is clipped, we don't do the perspective
+ // divide, since we don't need its window coordinates.
+ perspective(c, v, enables);
+ }
+}
+
+// frustum clipping, user clipping and W-divide
+static inline
+void clipAllPerspective(ogles_context_t* c, vertex_t* v, uint32_t enables)
+{
+ // compute eye coordinates
+ c->arrays.mv_transform(
+ &c->transforms.modelview.transform, &v->eye, &v->obj);
+ v->flags |= vertex_t::EYE;
+
+ // clip this vertex against each user clip plane
+ uint32_t clip = 0;
+ int planes = c->clipPlanes.enable;
+ while (planes) {
+ const int i = 31 - gglClz(planes);
+ planes &= ~(1<<i);
+ // XXX: we should have a special dot() for 2,3,4 coords vertices
+ GLfixed d = dot4(c->clipPlanes.plane[i].equation.v, v->eye.v);
+ if (d < 0) {
+ clip |= 0x100<<i;
+ }
+ }
+ v->flags |= clip;
+
+ clipFrustumPerspective(c, v, enables);
+}
+
+// ----------------------------------------------------------------------------
+
+void ogles_vertex_project(ogles_context_t* c, vertex_t* v) {
+ perspective(c, v, c->rasterizer.state.enables);
+}
+
+void ogles_vertex_perspective2D(ogles_context_t* c, vertex_t* v)
+{
+ // here we assume w=1.0 and the viewport transformation
+ // has been applied already.
+ c->arrays.cull = 0;
+ v->window.x = TRI_FROM_FIXED(v->clip.x);
+ v->window.y = TRI_FROM_FIXED(v->clip.y);
+ v->window.z = v->clip.z;
+ v->window.w = v->clip.w << 12;
+}
+
+void ogles_vertex_perspective3DZ(ogles_context_t* c, vertex_t* v) {
+ clipFrustumPerspective(c, v, GGL_ENABLE_DEPTH_TEST);
+}
+void ogles_vertex_perspective3D(ogles_context_t* c, vertex_t* v) {
+ clipFrustumPerspective(c, v, 0);
+}
+void ogles_vertex_clipAllPerspective3DZ(ogles_context_t* c, vertex_t* v) {
+ clipAllPerspective(c, v, GGL_ENABLE_DEPTH_TEST);
+}
+void ogles_vertex_clipAllPerspective3D(ogles_context_t* c, vertex_t* v) {
+ clipAllPerspective(c, v, 0);
+}
+
+static void clipPlanex(GLenum plane, const GLfixed* equ, ogles_context_t* c)
+{
+ const int p = plane - GL_CLIP_PLANE0;
+ if (ggl_unlikely(uint32_t(p) > (GL_CLIP_PLANE5 - GL_CLIP_PLANE0))) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+
+ vec4_t& equation = c->clipPlanes.plane[p].equation;
+ memcpy(equation.v, equ, sizeof(vec4_t));
+
+ ogles_validate_transform(c, transform_state_t::MVIT);
+ transform_t& mvit = c->transforms.mvit4;
+ mvit.point4(&mvit, &equation, &equation);
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+
+void glColor4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->current.color.r = gglFloatToFixed(r);
+ c->currentColorClamped.r = gglClampx(c->current.color.r);
+ c->current.color.g = gglFloatToFixed(g);
+ c->currentColorClamped.g = gglClampx(c->current.color.g);
+ c->current.color.b = gglFloatToFixed(b);
+ c->currentColorClamped.b = gglClampx(c->current.color.b);
+ c->current.color.a = gglFloatToFixed(a);
+ c->currentColorClamped.a = gglClampx(c->current.color.a);
+}
+
+void glColor4x(GLfixed r, GLfixed g, GLfixed b, GLfixed a)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->current.color.r = r;
+ c->current.color.g = g;
+ c->current.color.b = b;
+ c->current.color.a = a;
+ c->currentColorClamped.r = gglClampx(r);
+ c->currentColorClamped.g = gglClampx(g);
+ c->currentColorClamped.b = gglClampx(b);
+ c->currentColorClamped.a = gglClampx(a);
+}
+
+void glNormal3f(GLfloat x, GLfloat y, GLfloat z)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->currentNormal.x = gglFloatToFixed(x);
+ c->currentNormal.y = gglFloatToFixed(y);
+ c->currentNormal.z = gglFloatToFixed(z);
+}
+
+void glNormal3x(GLfixed x, GLfixed y, GLfixed z)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->currentNormal.x = x;
+ c->currentNormal.y = y;
+ c->currentNormal.z = z;
+}
+
+// ----------------------------------------------------------------------------
+
+void glClipPlanef(GLenum plane, const GLfloat* equ)
+{
+ const GLfixed equx[4] = {
+ gglFloatToFixed(equ[0]),
+ gglFloatToFixed(equ[1]),
+ gglFloatToFixed(equ[2]),
+ gglFloatToFixed(equ[3])
+ };
+ ogles_context_t* c = ogles_context_t::get();
+ clipPlanex(plane, equx, c);
+}
+
+void glClipPlanex(GLenum plane, const GLfixed* equ)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ clipPlanex(plane, equ, c);
+}
diff --git a/opengl/libagl/vertex.h b/opengl/libagl/vertex.h
new file mode 100644
index 0000000..55e6213
--- /dev/null
+++ b/opengl/libagl/vertex.h
@@ -0,0 +1,48 @@
+/* libs/opengles/vertex.h
+**
+** 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.
+*/
+
+#ifndef ANDROID_OPENGLES_VERTEX_H
+#define ANDROID_OPENGLES_VERTEX_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+namespace android {
+
+namespace gl {
+struct vertex_t;
+struct ogles_context_t;
+};
+
+void ogles_init_vertex(ogles_context_t* c);
+void ogles_uninit_vertex(ogles_context_t* c);
+
+void ogles_vertex_perspective2D(ogles_context_t*, vertex_t*);
+
+void ogles_vertex_perspective3D(ogles_context_t*, vertex_t*);
+void ogles_vertex_perspective3DZ(ogles_context_t*, vertex_t*);
+void ogles_vertex_clipAllPerspective3D(ogles_context_t*, vertex_t*);
+void ogles_vertex_clipAllPerspective3DZ(ogles_context_t*, vertex_t*);
+
+
+void ogles_vertex_project(ogles_context_t* c, vertex_t*);
+
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_VERTEX_H
+