From cc8c35cee5de7fdf2d79a1a3716120b64301cdfe Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Queru Date: Thu, 12 Nov 2009 18:45:53 -0800 Subject: eclair snapshot --- opengl/libagl/Android.mk | 24 +- opengl/libagl/TextureObjectManager.cpp | 47 +- opengl/libagl/TextureObjectManager.h | 70 +-- opengl/libagl/array.cpp | 130 +++-- opengl/libagl/copybit.cpp | 631 ++++++++++++++++++++++ opengl/libagl/copybit.h | 75 +++ opengl/libagl/egl.cpp | 951 ++++++++++++++++++++++++++------- opengl/libagl/light.cpp | 11 +- opengl/libagl/matrix.cpp | 15 +- opengl/libagl/primitives.cpp | 2 +- opengl/libagl/state.cpp | 82 ++- opengl/libagl/texture.cpp | 301 ++++++++--- opengl/libagl/texture.h | 10 +- 13 files changed, 1944 insertions(+), 405 deletions(-) create mode 100644 opengl/libagl/copybit.cpp create mode 100644 opengl/libagl/copybit.h (limited to 'opengl/libagl') diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk index 3ce0414..9837845 100644 --- a/opengl/libagl/Android.mk +++ b/opengl/libagl/Android.mk @@ -6,6 +6,9 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +# Set to 1 to use gralloc and copybits +LIBAGL_USE_GRALLOC_COPYBITS := 1 + LOCAL_SRC_FILES:= \ egl.cpp \ state.cpp \ @@ -22,6 +25,13 @@ LOCAL_SRC_FILES:= \ primitives.cpp.arm \ vertex.cpp.arm +LOCAL_CFLAGS += -DLOG_TAG=\"libagl\" +LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES +LOCAL_CFLAGS += -fvisibility=hidden + +LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils libpixelflinger +LOCAL_LDLIBS := -lpthread -ldl + ifeq ($(TARGET_ARCH),arm) LOCAL_SRC_FILES += fixed_asm.S iterators.S LOCAL_CFLAGS += -fstrict-aliasing @@ -29,13 +39,17 @@ endif ifneq ($(TARGET_SIMULATOR),true) # we need to access the private Bionic header - LOCAL_CFLAGS += -I$(LOCAL_PATH)/../../../../bionic/libc/private + LOCAL_C_INCLUDES += bionic/libc/private endif -LOCAL_SHARED_LIBRARIES := libcutils libutils libpixelflinger -LOCAL_CFLAGS += -fvisibility=hidden +ifeq ($(LIBAGL_USE_GRALLOC_COPYBITS),1) + LOCAL_CFLAGS += -DLIBAGL_USE_GRALLOC_COPYBITS + LOCAL_SRC_FILES += copybit.cpp + LOCAL_SHARED_LIBRARIES += libui +endif -LOCAL_LDLIBS := -lpthread -ldl -LOCAL_MODULE:= libagl + +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/egl +LOCAL_MODULE:= libGLES_android include $(BUILD_SHARED_LIBRARY) diff --git a/opengl/libagl/TextureObjectManager.cpp b/opengl/libagl/TextureObjectManager.cpp index ce31854..255ccac 100644 --- a/opengl/libagl/TextureObjectManager.cpp +++ b/opengl/libagl/TextureObjectManager.cpp @@ -1,16 +1,16 @@ /* ** 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 + ** 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 + ** 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 + ** 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. */ @@ -19,11 +19,13 @@ #include "context.h" #include "TextureObjectManager.h" +#include + namespace android { // ---------------------------------------------------------------------------- EGLTextureObject::EGLTextureObject() - : mCount(0), mSize(0) + : mSize(0) { init(); } @@ -53,6 +55,10 @@ void EGLTextureObject::init() memset(crop_rect, 0, sizeof(crop_rect)); generate_mipmap = GL_FALSE; direct = GL_FALSE; +#ifdef LIBAGL_USE_GRALLOC_COPYBITS + try_copybit = false; +#endif // LIBAGL_USE_GRALLOC_COPYBITS + buffer = 0; } void EGLTextureObject::copyParameters(const sp& old) @@ -123,6 +129,7 @@ status_t EGLTextureObject::setSurface(GGLSurface const* s) } surface = *s; internalformat = 0; + buffer = 0; // we should keep the crop_rect, but it's delicate because // the new size of the surface could make it invalid. @@ -141,12 +148,26 @@ status_t EGLTextureObject::setSurface(GGLSurface const* s) return NO_ERROR; } +status_t EGLTextureObject::setImage(android_native_buffer_t* native_buffer) +{ + GGLSurface sur; + sur.version = sizeof(GGLSurface); + sur.width = native_buffer->width; + sur.height= native_buffer->height; + sur.stride= native_buffer->stride; + sur.format= native_buffer->format; + sur.data = 0; + setSurface(&sur); + buffer = native_buffer; + 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 (level == 0) { if (size!=mSize || !surface.data) { if (mSize && surface.data) { @@ -177,9 +198,9 @@ status_t EGLTextureObject::reallocate( return NO_MEMORY; } - LOGW_IF(level-1 >= mNumExtraLod, + LOGW_IF(level-1 >= mNumExtraLod, "specifying mipmap level %d, but # of level is %d", - level, mNumExtraLod+1); + level, mNumExtraLod+1); GGLSurface& mipmap = editMip(level); if (mipmap.data) @@ -224,7 +245,7 @@ status_t EGLTextureObject::reallocate( // ---------------------------------------------------------------------------- EGLSurfaceManager::EGLSurfaceManager() - : TokenManager(), mCount(0) + : TokenManager() { } diff --git a/opengl/libagl/TextureObjectManager.h b/opengl/libagl/TextureObjectManager.h index 74ed1a4..279e040 100644 --- a/opengl/libagl/TextureObjectManager.h +++ b/opengl/libagl/TextureObjectManager.h @@ -1,16 +1,16 @@ /* ** 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 +** 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 +** 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 +** 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. */ @@ -30,6 +30,8 @@ #include #include +#include +#include #include "Tokenizer.h" #include "TokenManager.h" @@ -39,22 +41,20 @@ namespace android { // ---------------------------------------------------------------------------- -class EGLTextureObject +class EGLTextureObject : public LightRefBase { 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 setImage(android_native_buffer_t* buffer); + void setImageBits(void* vaddr) { surface.data = (GGLubyte*)vaddr; } - 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; + inline size_t size() const { return mSize; } const GGLSurface& mip(int lod) const; GGLSurface& editMip(int lod); bool hasMipmaps() const { return mMipmaps!=0; } @@ -65,7 +65,6 @@ private: status_t allocateMipmaps(); void freeMipmaps(); void init(); - mutable int32_t mCount; size_t mSize; GGLSurface *mMipmaps; int mNumExtraLod; @@ -81,36 +80,22 @@ public: GLint crop_rect[4]; GLint generate_mipmap; GLint direct; +#ifdef LIBAGL_USE_GRALLOC_COPYBITS + bool try_copybit; +#endif // LIBAGL_USE_GRALLOC_COPYBITS + android_native_buffer_t* buffer; }; -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 +class EGLSurfaceManager : + public LightRefBase, + 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 createTexture(GLuint name); sp removeTexture(GLuint name); sp replaceTexture(GLuint name); @@ -118,21 +103,10 @@ public: sp texture(GLuint name); private: - mutable int32_t mCount; mutable Mutex mLock; KeyedVector< GLuint, sp > 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 diff --git a/opengl/libagl/array.cpp b/opengl/libagl/array.cpp index 3e9c6a5..4878722 100644 --- a/opengl/libagl/array.cpp +++ b/opengl/libagl/array.cpp @@ -1,16 +1,16 @@ -/* +/* ** 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 +** 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 +** 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 +** 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. */ @@ -26,6 +26,9 @@ #include "primitives.h" #include "texture.h" #include "BufferObjectManager.h" +#ifdef LIBAGL_USE_GRALLOC_COPYBITS +#include "copybit.h" +#endif // LIBAGL_USE_GRALLOC_COPYBITS // ---------------------------------------------------------------------------- @@ -250,7 +253,7 @@ static void fetchExpand3s(ogles_context_t*, GLfixed* v, const GLshort* p) { v[2] = GGL_S_TO_X(p[2]); } -typedef array_t::fetcher_t fn_t; +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, @@ -334,7 +337,7 @@ void array_t::init( this->bounds = count; } -inline void array_t::resolve() +inline void array_t::resolve() { physical_pointer = (bo) ? (bo->data + uintptr_t(pointer)) : pointer; } @@ -465,7 +468,7 @@ vertex_t* cache_vertex(ogles_context_t* c, vertex_t* v, uint32_t index) // 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); + v += v[0].locked | (v[1].locked<<1); } // note: compileElement clears v->flags c->arrays.compileElement(c, v, index); @@ -480,7 +483,7 @@ vertex_t* fetch_vertex(ogles_context_t* c, size_t index) #if VC_CACHE_TYPE == VC_CACHE_TYPE_INDEXED - vertex_t* const v = c->vc.vCache + + vertex_t* const v = c->vc.vCache + (index & (vertex_cache_t::VERTEX_CACHE_SIZE-1)); if (ggl_likely(v->index == index)) { @@ -491,7 +494,7 @@ vertex_t* fetch_vertex(ogles_context_t* c, size_t index) #elif VC_CACHE_TYPE == VC_CACHE_TYPE_LRU - vertex_t* v = c->vc.vCache + + vertex_t* v = c->vc.vCache + (index & ((vertex_cache_t::VERTEX_CACHE_SIZE-1)>>1))*2; // always record LRU in v[0] @@ -532,12 +535,12 @@ void drawPrimitivesPoints(ogles_context_t* c, GLint first, GLsizei count) return; // vertex cache size must be multiple of 1 - const GLsizei vcs = + 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; + GLsizei num = count > vcs ? vcs : count; c->arrays.cull = vertex_t::CLIP_ALL; c->arrays.compileElements(c, v, first, num); first += num; @@ -569,13 +572,13 @@ void drawPrimitivesLineStrip(ogles_context_t* c, GLint first, GLsizei count) count -= 1; // vertex cache size must be multiple of 1 - const GLsizei vcs = + const GLsizei vcs = (vertex_cache_t::VERTEX_BUFFER_SIZE + vertex_cache_t::VERTEX_CACHE_SIZE - 1); do { - v0 = c->vc.vBuffer + 0; + v0 = c->vc.vBuffer + 0; v = c->vc.vBuffer + 1; - GLsizei num = count > vcs ? vcs : count; + GLsizei num = count > vcs ? vcs : count; c->arrays.compileElements(c, v, first, num); first += num; count -= num; @@ -602,7 +605,7 @@ void drawPrimitivesLineLoop(ogles_context_t* c, GLint first, GLsizei count) return; drawPrimitivesLineStrip(c, first, count); if (ggl_likely(count >= 3)) { - vertex_t* v0 = c->vc.vBuffer; + 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; @@ -617,12 +620,12 @@ void drawPrimitivesLines(ogles_context_t* c, GLint first, GLsizei count) return; // vertex cache size must be multiple of 2 - const GLsizei vcs = + 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; + GLsizei num = count > vcs ? vcs : count; c->arrays.cull = vertex_t::CLIP_ALL; c->arrays.compileElements(c, v, first, num); first += num; @@ -662,14 +665,14 @@ static void drawPrimitivesTriangleFanOrStrip(ogles_context_t* c, // 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 = + 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; + v0 = c->vc.vBuffer + 0; + v1 = c->vc.vBuffer + 1; v = c->vc.vBuffer + 2; - GLsizei num = count > vcs ? vcs : count; + GLsizei num = count > vcs ? vcs : count; c->arrays.compileElements(c, v, first, num); first += num; count -= num; @@ -697,13 +700,19 @@ static void drawPrimitivesTriangleFanOrStrip(ogles_context_t* c, } while (count > 0); } -void drawPrimitivesTriangleStrip(ogles_context_t* c, +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) { +#ifdef LIBAGL_USE_GRALLOC_COPYBITS + if (drawTriangleFanWithCopybit(c, first, count)) { + return; + } +#endif // LIBAGL_USE_GRALLOC_COPYBITS + drawPrimitivesTriangleFanOrStrip(c, first, count, 2); } @@ -713,12 +722,12 @@ void drawPrimitivesTriangles(ogles_context_t* c, GLint first, GLsizei count) return; // vertex cache size must be multiple of 3 - const GLsizei vcs = + 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; + GLsizei num = count > vcs ? vcs : count; c->arrays.cull = vertex_t::CLIP_ALL; c->arrays.compileElements(c, v, first, num); first += num; @@ -779,11 +788,11 @@ void drawIndexedPrimitivesLineStrip(ogles_context_t* c, { 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; @@ -806,11 +815,11 @@ void drawIndexedPrimitivesLineLoop(ogles_context_t* c, 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; @@ -825,7 +834,7 @@ void drawIndexedPrimitivesLineLoop(ogles_context_t* c, } while (count); v1->locked = 0; - v1 = c->vc.vBuffer; + 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); @@ -861,7 +870,7 @@ static void drawIndexedPrimitivesTriangleFanOrStrip(ogles_context_t* c, if (ggl_unlikely(count < 3)) return; - + vertex_t * const v = c->vc.vBuffer; vertex_t* v0 = v; vertex_t* v1 = v+1; @@ -985,17 +994,17 @@ void compileElements__3x_full(ogles_context_t* c, 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.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]); @@ -1023,7 +1032,7 @@ void compileElements__3x_full(ogles_context_t* c, #pragma mark clippers #endif -static void clipVec4(vec4_t& nv, +static void clipVec4(vec4_t& nv, GLfixed t, const vec4_t& s, const vec4_t& p) { for (int i=0; i<4 ; i++) @@ -1086,10 +1095,10 @@ void validate_arrays(ogles_context_t* c, GLenum mode) // 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 = + 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) { @@ -1120,7 +1129,7 @@ void validate_arrays(ogles_context_t* c, GLenum mode) if (enables & GGL_ENABLE_TMUS) { // needs texture transforms want |= transform_state_t::TEXTURE; } - if (c->clipPlanes.enable || (enables & GGL_ENABLE_FOG)) { + if (c->clipPlanes.enable || (enables & GGL_ENABLE_FOG)) { want |= transform_state_t::MODELVIEW; // needs eye coords } ogles_validate_transform(c, want); @@ -1139,18 +1148,18 @@ void validate_arrays(ogles_context_t* c, GLenum mode) 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) { @@ -1257,9 +1266,7 @@ 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) { + if (size!=4 || stride<0) { ogles_error(c, GL_INVALID_VALUE); return; } @@ -1366,9 +1373,18 @@ void glDrawArrays(GLenum mode, GLint first, GLsizei count) if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK)) return; // all triangles are culled + validate_arrays(c, mode); + + const uint32_t enables = c->rasterizer.state.enables; + if (enables & GGL_ENABLE_TMUS) + ogles_lock_textures(c); + drawArraysPrims[mode](c, first, count); + if (enables & GGL_ENABLE_TMUS) + ogles_unlock_textures(c); + #if VC_CACHE_STATISTICS c->vc.total = count; c->vc.dump_stats(mode); @@ -1413,15 +1429,23 @@ void glDrawElements( // 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); } + const uint32_t enables = c->rasterizer.state.enables; + if (enables & GGL_ENABLE_TMUS) + ogles_lock_textures(c); + drawElementsPrims[mode](c, count, indices); + + if (enables & GGL_ENABLE_TMUS) + ogles_unlock_textures(c); + #if VC_CACHE_STATISTICS c->vc.total = count; c->vc.dump_stats(mode); @@ -1448,7 +1472,7 @@ void glBindBuffer(GLenum target, GLuint buffer) return; } } - ((target == GL_ARRAY_BUFFER) ? + ((target == GL_ARRAY_BUFFER) ? c->arrays.array_buffer : c->arrays.element_array_buffer) = bo; } @@ -1467,7 +1491,7 @@ void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usa ogles_error(c, GL_INVALID_ENUM); return; } - buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ? + buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ? c->arrays.array_buffer : c->arrays.element_array_buffer); if (bo == 0) { @@ -1497,7 +1521,7 @@ void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvo ogles_error(c, GL_INVALID_VALUE); return; } - buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ? + buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ? c->arrays.array_buffer : c->arrays.element_array_buffer); if (bo == 0) { @@ -1545,7 +1569,7 @@ void glDeleteBuffers(GLsizei n, const GLuint* buffers) } } } - } + } c->bufferObjectManager->deleteBuffers(n, buffers); c->bufferObjectManager->recycleTokens(n, buffers); } diff --git a/opengl/libagl/copybit.cpp b/opengl/libagl/copybit.cpp new file mode 100644 index 0000000..a68750e --- /dev/null +++ b/opengl/libagl/copybit.cpp @@ -0,0 +1,631 @@ +/* +** +** Copyright 2009, 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 +#include + +#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" +#include "TextureObjectManager.h" + +#include +#include +#include + +#include +#include +#include + + +#define DEBUG_COPYBIT true + +// ---------------------------------------------------------------------------- + +namespace android { + +static void textureToCopyBitImage( + const GGLSurface* surface, int32_t opFormat, + android_native_buffer_t* buffer, copybit_image_t* img) +{ + uint32_t vstride = 0; + if (opFormat == COPYBIT_FORMAT_YCbCr_422_SP || + opFormat == COPYBIT_FORMAT_YCbCr_420_SP) { + // NOTE: this static_cast is really not safe b/c we can't know for + // sure the buffer passed is of the right type. + // However, since we do this only for YUV formats, we should be safe + // since only SurfaceFlinger makes use of them. + GraphicBuffer* graphicBuffer = static_cast(buffer); + vstride = graphicBuffer->getVerticalStride(); + } + + img->w = surface->stride; + img->h = vstride ? vstride : surface->height; + img->format = opFormat; + img->base = surface->data; + img->handle = (native_handle_t *)buffer->handle; +} + +struct clipRectRegion : public copybit_region_t { + clipRectRegion(ogles_context_t* c) + { + scissor_t const* scissor = &c->rasterizer.state.scissor; + r.l = scissor->left; + r.t = scissor->top; + r.r = scissor->right; + r.b = scissor->bottom; + next = iterate; + } +private: + static int iterate(copybit_region_t const * self, copybit_rect_t* rect) { + *rect = static_cast(self)->r; + const_cast(self)->next = iterate_done; + return 1; + } + static int iterate_done(copybit_region_t const *, copybit_rect_t*) { + return 0; + } +public: + copybit_rect_t r; +}; + +static bool supportedCopybitsFormat(int format) { + switch (format) { + case COPYBIT_FORMAT_RGBA_8888: + case COPYBIT_FORMAT_RGBX_8888: + case COPYBIT_FORMAT_RGB_888: + case COPYBIT_FORMAT_RGB_565: + case COPYBIT_FORMAT_BGRA_8888: + case COPYBIT_FORMAT_RGBA_5551: + case COPYBIT_FORMAT_RGBA_4444: + case COPYBIT_FORMAT_YCbCr_422_SP: + case COPYBIT_FORMAT_YCbCr_420_SP: + return true; + default: + return false; + } +} + +static bool hasAlpha(int format) { + switch (format) { + case COPYBIT_FORMAT_RGBA_8888: + case COPYBIT_FORMAT_BGRA_8888: + case COPYBIT_FORMAT_RGBA_5551: + case COPYBIT_FORMAT_RGBA_4444: + return true; + default: + return false; + } +} + +static inline int fixedToByte(GGLfixed val) { + return (val - (val >> 8)) >> 8; +} + +/** + * Performs a quick check of the rendering state. If this function returns + * false we cannot use the copybit driver. + */ + +static bool checkContext(ogles_context_t* c) { + + // By convention copybitQuickCheckContext() has already returned true. + // avoid checking the same information again. + + if (c->copybits.blitEngine == NULL) { + LOGD_IF(DEBUG_COPYBIT, "no copybit hal"); + return false; + } + + if (c->rasterizer.state.enables + & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)) { + LOGD_IF(DEBUG_COPYBIT, "depth test and/or fog"); + return false; + } + + // Note: The drawSurfaceBuffer is only set for destination + // surfaces types that are supported by the hardware and + // do not have an alpha channel. So we don't have to re-check that here. + + static const int tmu = 0; + texture_unit_t& u(c->textures.tmu[tmu]); + EGLTextureObject* textureObject = u.texture; + + if (!supportedCopybitsFormat(textureObject->surface.format)) { + LOGD_IF(DEBUG_COPYBIT, "texture format not supported"); + return false; + } + return true; +} + + +static bool copybit(GLint x, GLint y, + GLint w, GLint h, + EGLTextureObject* textureObject, + const GLint* crop_rect, + int transform, + ogles_context_t* c) +{ + status_t err = NO_ERROR; + + // We assume checkContext has already been called and has already + // returned true. + + const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s; + + y = cbSurface.height - (y + h); + + const GLint Ucr = crop_rect[0]; + const GLint Vcr = crop_rect[1]; + const GLint Wcr = crop_rect[2]; + const GLint Hcr = crop_rect[3]; + + GLint screen_w = w; + GLint screen_h = h; + int32_t dsdx = Wcr << 16; // dsdx = ((Wcr/screen_w)/Wt)*Wt + int32_t dtdy = Hcr << 16; // dtdy = -((Hcr/screen_h)/Ht)*Ht + if (transform & COPYBIT_TRANSFORM_ROT_90) { + swap(screen_w, screen_h); + } + if (dsdx!=screen_w || dtdy!=screen_h) { + // in most cases the divide is not needed + dsdx /= screen_w; + dtdy /= screen_h; + } + dtdy = -dtdy; // see equation of dtdy above + + // copybit doesn't say anything about filtering, so we can't + // discriminate. On msm7k, copybit will always filter. + // the code below handles min/mag filters, we keep it as a reference. + +#ifdef MIN_MAG_FILTER + int32_t texelArea = gglMulx(dtdy, dsdx); + if (texelArea < FIXED_ONE && textureObject->mag_filter != GL_LINEAR) { + // Non-linear filtering on a texture enlargement. + LOGD_IF(DEBUG_COPYBIT, "mag filter is not GL_LINEAR"); + return false; + } + if (texelArea > FIXED_ONE && textureObject->min_filter != GL_LINEAR) { + // Non-linear filtering on an texture shrink. + LOGD_IF(DEBUG_COPYBIT, "min filter is not GL_LINEAR"); + return false; + } +#endif + + const uint32_t enables = c->rasterizer.state.enables; + int planeAlpha = 255; + bool alphaPlaneWorkaround = false; + static const int tmu = 0; + texture_t& tev(c->rasterizer.state.texture[tmu]); + int32_t opFormat = textureObject->surface.format; + const bool srcTextureHasAlpha = hasAlpha(opFormat); + if (!srcTextureHasAlpha) { + planeAlpha = fixedToByte(c->currentColorClamped.a); + } + + const bool cbHasAlpha = hasAlpha(cbSurface.format); + bool blending = false; + if ((enables & GGL_ENABLE_BLENDING) + && !(c->rasterizer.state.blend.src == GL_ONE + && c->rasterizer.state.blend.dst == GL_ZERO)) { + // Blending is OK if it is + // the exact kind of blending that the copybits hardware supports. + // Note: The hardware only supports + // GL_SRC_ALPHA / GL_ONE_MINUS_SRC_ALPHA, + // But the surface flinger uses GL_ONE / GL_ONE_MINUS_SRC_ALPHA. + // We substitute GL_SRC_ALPHA / GL_ONE_MINUS_SRC_ALPHA in that case, + // because the performance is worth it, even if the results are + // not correct. + if (!((c->rasterizer.state.blend.src == GL_SRC_ALPHA + || c->rasterizer.state.blend.src == GL_ONE) + && c->rasterizer.state.blend.dst == GL_ONE_MINUS_SRC_ALPHA + && c->rasterizer.state.blend.alpha_separate == 0)) { + // Incompatible blend mode. + LOGD_IF(DEBUG_COPYBIT, "incompatible blend mode"); + return false; + } + blending = true; + } else { + if (cbHasAlpha) { + // NOTE: the result will be slightly wrong in this case because + // the destination alpha channel will be set to 1.0 instead of + // the iterated alpha value. *shrug*. + } + // disable plane blending and src blending for supported formats + planeAlpha = 255; + if (opFormat == COPYBIT_FORMAT_RGBA_8888) { + opFormat = COPYBIT_FORMAT_RGBX_8888; + } else { + if (srcTextureHasAlpha) { + LOGD_IF(DEBUG_COPYBIT, "texture format requires blending"); + return false; + } + } + } + + switch (tev.env) { + case GGL_REPLACE: + break; + case GGL_MODULATE: + // only cases allowed is: + // RGB source, color={1,1,1,a} -> can be done with GL_REPLACE + // RGBA source, color={1,1,1,1} -> can be done with GL_REPLACE + if (blending) { + if (c->currentColorClamped.r == c->currentColorClamped.a && + c->currentColorClamped.g == c->currentColorClamped.a && + c->currentColorClamped.b == c->currentColorClamped.a) { + // TODO: RGBA source, color={1,1,1,a} / regular-blending + // is equivalent + alphaPlaneWorkaround = true; + break; + } + } + LOGD_IF(DEBUG_COPYBIT, "GGL_MODULATE"); + return false; + default: + // Incompatible texture environment. + LOGD_IF(DEBUG_COPYBIT, "incompatible texture environment"); + return false; + } + + copybit_device_t* copybit = c->copybits.blitEngine; + copybit_image_t src; + textureToCopyBitImage(&textureObject->surface, opFormat, + textureObject->buffer, &src); + copybit_rect_t srect = { Ucr, Vcr + Hcr, Ucr + Wcr, Vcr }; + + /* + * Below we perform extra passes needed to emulate things the h/w + * cannot do. + */ + + const GLfixed minScaleInv = gglDivQ(0x10000, c->copybits.minScale, 16); + const GLfixed maxScaleInv = gglDivQ(0x10000, c->copybits.maxScale, 16); + + sp tempBitmap; + + if (dsdx < maxScaleInv || dsdx > minScaleInv || + dtdy < maxScaleInv || dtdy > minScaleInv) + { + // The requested scale is out of the range the hardware + // can support. + LOGD_IF(DEBUG_COPYBIT, + "scale out of range dsdx=%08x (Wcr=%d / w=%d), " + "dtdy=%08x (Hcr=%d / h=%d), Ucr=%d, Vcr=%d", + dsdx, Wcr, w, dtdy, Hcr, h, Ucr, Vcr); + + int32_t xscale=0x10000, yscale=0x10000; + if (dsdx > minScaleInv) xscale = c->copybits.minScale; + else if (dsdx < maxScaleInv) xscale = c->copybits.maxScale; + if (dtdy > minScaleInv) yscale = c->copybits.minScale; + else if (dtdy < maxScaleInv) yscale = c->copybits.maxScale; + dsdx = gglMulx(dsdx, xscale); + dtdy = gglMulx(dtdy, yscale); + + /* we handle only one step of resizing below. Handling an arbitrary + * number is relatively easy (replace "if" above by "while"), but requires + * two intermediate buffers and so far we never had the need. + */ + + if (dsdx < maxScaleInv || dsdx > minScaleInv || + dtdy < maxScaleInv || dtdy > minScaleInv) { + LOGD_IF(DEBUG_COPYBIT, + "scale out of range dsdx=%08x (Wcr=%d / w=%d), " + "dtdy=%08x (Hcr=%d / h=%d), Ucr=%d, Vcr=%d", + dsdx, Wcr, w, dtdy, Hcr, h, Ucr, Vcr); + return false; + } + + const int tmp_w = gglMulx(srect.r - srect.l, xscale, 16); + const int tmp_h = gglMulx(srect.b - srect.t, yscale, 16); + + LOGD_IF(DEBUG_COPYBIT, + "xscale=%08x, yscale=%08x, dsdx=%08x, dtdy=%08x, tmp_w=%d, tmp_h=%d", + xscale, yscale, dsdx, dtdy, tmp_w, tmp_h); + + tempBitmap = new GraphicBuffer( + tmp_w, tmp_h, src.format, + GraphicBuffer::USAGE_HW_2D); + + err = tempBitmap->initCheck(); + if (err == NO_ERROR) { + copybit_image_t tmp_dst; + copybit_rect_t tmp_rect; + tmp_dst.w = tmp_w; + tmp_dst.h = tmp_h; + tmp_dst.format = tempBitmap->format; + tmp_dst.handle = (native_handle_t*)tempBitmap->getNativeBuffer()->handle; + tmp_rect.l = 0; + tmp_rect.t = 0; + tmp_rect.r = tmp_dst.w; + tmp_rect.b = tmp_dst.h; + region_iterator tmp_it(Region(Rect(tmp_rect.r, tmp_rect.b))); + copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0); + copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF); + copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE); + err = copybit->stretch(copybit, + &tmp_dst, &src, &tmp_rect, &srect, &tmp_it); + src = tmp_dst; + srect = tmp_rect; + } + } + + copybit_image_t dst; + textureToCopyBitImage(&cbSurface, cbSurface.format, + c->copybits.drawSurfaceBuffer, &dst); + copybit_rect_t drect = {x, y, x+w, y+h}; + + + /* and now the alpha-plane hack. This handles the "Fade" case of a + * texture with an alpha channel. + */ + if (alphaPlaneWorkaround) { + sp tempCb = new GraphicBuffer( + w, h, COPYBIT_FORMAT_RGB_565, + GraphicBuffer::USAGE_HW_2D); + + err = tempCb->initCheck(); + + copybit_image_t tmpCbImg; + copybit_rect_t tmpCbRect; + copybit_rect_t tmpdrect = drect; + tmpCbImg.w = w; + tmpCbImg.h = h; + tmpCbImg.format = tempCb->format; + tmpCbImg.handle = (native_handle_t*)tempCb->getNativeBuffer()->handle; + tmpCbRect.l = 0; + tmpCbRect.t = 0; + + if (drect.l < 0) { + tmpCbRect.l = -tmpdrect.l; + tmpdrect.l = 0; + } + if (drect.t < 0) { + tmpCbRect.t = -tmpdrect.t; + tmpdrect.t = 0; + } + if (drect.l + tmpCbImg.w > dst.w) { + tmpCbImg.w = dst.w - drect.l; + tmpdrect.r = dst.w; + } + if (drect.t + tmpCbImg.h > dst.h) { + tmpCbImg.h = dst.h - drect.t; + tmpdrect.b = dst.h; + } + + tmpCbRect.r = tmpCbImg.w; + tmpCbRect.b = tmpCbImg.h; + + if (!err) { + // first make a copy of the destination buffer + region_iterator tmp_it(Region(Rect(w, h))); + copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0); + copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF); + copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE); + err = copybit->stretch(copybit, + &tmpCbImg, &dst, &tmpCbRect, &tmpdrect, &tmp_it); + } + if (!err) { + // then proceed as usual, but without the alpha plane + copybit->set_parameter(copybit, COPYBIT_TRANSFORM, transform); + copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF); + copybit->set_parameter(copybit, COPYBIT_DITHER, + (enables & GGL_ENABLE_DITHER) ? + COPYBIT_ENABLE : COPYBIT_DISABLE); + clipRectRegion it(c); + err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it); + } + if (!err) { + // finally copy back the destination on top with 1-alphaplane + int invPlaneAlpha = 0xFF - fixedToByte(c->currentColorClamped.a); + clipRectRegion it(c); + copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0); + copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, invPlaneAlpha); + copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE); + err = copybit->stretch(copybit, + &dst, &tmpCbImg, &tmpdrect, &tmpCbRect, &it); + } + } else { + copybit->set_parameter(copybit, COPYBIT_TRANSFORM, transform); + copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, planeAlpha); + copybit->set_parameter(copybit, COPYBIT_DITHER, + (enables & GGL_ENABLE_DITHER) ? + COPYBIT_ENABLE : COPYBIT_DISABLE); + clipRectRegion it(c); + + LOGD_IF(0, + "dst={%d, %d, %d, %p, %p}, " + "src={%d, %d, %d, %p, %p}, " + "drect={%d,%d,%d,%d}, " + "srect={%d,%d,%d,%d}, " + "it={%d,%d,%d,%d}, " , + dst.w, dst.h, dst.format, dst.base, dst.handle, + src.w, src.h, src.format, src.base, src.handle, + drect.l, drect.t, drect.r, drect.b, + srect.l, srect.t, srect.r, srect.b, + it.r.l, it.r.t, it.r.r, it.r.b + ); + + err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it); + } + if (err != NO_ERROR) { + c->textures.tmu[0].texture->try_copybit = false; + } + return err == NO_ERROR ? true : false; +} + +/* + * Try to draw a triangle fan with copybit, return false if we fail. + */ +bool drawTriangleFanWithCopybit_impl(ogles_context_t* c, GLint first, GLsizei count) +{ + if (!checkContext(c)) { + return false; + } + + // FIXME: we should handle culling here + c->arrays.compileElements(c, c->vc.vBuffer, 0, 4); + + // we detect if we're dealing with a rectangle, by comparing the + // rectangles {v0,v2} and {v1,v3} which should be identical. + + // NOTE: we should check that the rectangle is window aligned, however + // if we do that, the optimization won't be taken in a lot of cases. + // Since this code is intended to be used with SurfaceFlinger only, + // so it's okay... + + const vec4_t& v0 = c->vc.vBuffer[0].window; + const vec4_t& v1 = c->vc.vBuffer[1].window; + const vec4_t& v2 = c->vc.vBuffer[2].window; + const vec4_t& v3 = c->vc.vBuffer[3].window; + int l = min(v0.x, v2.x); + int b = min(v0.y, v2.y); + int r = max(v0.x, v2.x); + int t = max(v0.y, v2.y); + if ((l != min(v1.x, v3.x)) || (b != min(v1.y, v3.y)) || + (r != max(v1.x, v3.x)) || (t != max(v1.y, v3.y))) { + LOGD_IF(DEBUG_COPYBIT, "geometry not a rectangle"); + return false; + } + + // fetch and transform texture coordinates + // NOTE: maybe it would be better to have a "compileElementsAll" method + // that would ensure all vertex data are fetched and transformed + const transform_t& tr = c->transforms.texture[0].transform; + for (size_t i=0 ; i<4 ; i++) { + const GLubyte* tp = c->arrays.texture[0].element(i); + vertex_t* const v = &c->vc.vBuffer[i]; + c->arrays.texture[0].fetch(c, v->texture[0].v, tp); + // FIXME: we should bail if q!=1 + c->arrays.tex_transform[0](&tr, &v->texture[0], &v->texture[0]); + } + + const vec4_t& t0 = c->vc.vBuffer[0].texture[0]; + const vec4_t& t1 = c->vc.vBuffer[1].texture[0]; + const vec4_t& t2 = c->vc.vBuffer[2].texture[0]; + const vec4_t& t3 = c->vc.vBuffer[3].texture[0]; + int txl = min(t0.x, t2.x); + int txb = min(t0.y, t2.y); + int txr = max(t0.x, t2.x); + int txt = max(t0.y, t2.y); + if ((txl != min(t1.x, t3.x)) || (txb != min(t1.y, t3.y)) || + (txr != max(t1.x, t3.x)) || (txt != max(t1.y, t3.y))) { + LOGD_IF(DEBUG_COPYBIT, "texcoord not a rectangle"); + return false; + } + if ((txl != 0) || (txb != 0) || + (txr != FIXED_ONE) || (txt != FIXED_ONE)) { + // we could probably handle this case, if we wanted to + LOGD_IF(DEBUG_COPYBIT, "texture is cropped: %08x,%08x,%08x,%08x", + txl, txb, txr, txt); + return false; + } + + // at this point, we know we are dealing with a rectangle, so we + // only need to consider 3 vertices for computing the jacobians + + const int dx01 = v1.x - v0.x; + const int dx02 = v2.x - v0.x; + const int dy01 = v1.y - v0.y; + const int dy02 = v2.y - v0.y; + const int ds01 = t1.S - t0.S; + const int ds02 = t2.S - t0.S; + const int dt01 = t1.T - t0.T; + const int dt02 = t2.T - t0.T; + const int area = dx01*dy02 - dy01*dx02; + int dsdx, dsdy, dtdx, dtdy; + if (area >= 0) { + dsdx = ds01*dy02 - ds02*dy01; + dtdx = dt01*dy02 - dt02*dy01; + dsdy = ds02*dx01 - ds01*dx02; + dtdy = dt02*dx01 - dt01*dx02; + } else { + dsdx = ds02*dy01 - ds01*dy02; + dtdx = dt02*dy01 - dt01*dy02; + dsdy = ds01*dx02 - ds02*dx01; + dtdy = dt01*dx02 - dt02*dx01; + } + + // here we rely on the fact that we know the transform is + // a rigid-body transform AND that it can only rotate in 90 degrees + // increments + + int transform = 0; + if (dsdx == 0) { + // 90 deg rotation case + // [ 0 dtdx ] + // [ dsdx 0 ] + transform |= COPYBIT_TRANSFORM_ROT_90; + // FIXME: not sure if FLIP_H and FLIP_V shouldn't be inverted + if (dtdx > 0) + transform |= COPYBIT_TRANSFORM_FLIP_H; + if (dsdy < 0) + transform |= COPYBIT_TRANSFORM_FLIP_V; + } else { + // [ dsdx 0 ] + // [ 0 dtdy ] + if (dsdx < 0) + transform |= COPYBIT_TRANSFORM_FLIP_H; + if (dtdy < 0) + transform |= COPYBIT_TRANSFORM_FLIP_V; + } + + //LOGD("l=%d, b=%d, w=%d, h=%d, tr=%d", x, y, w, h, transform); + //LOGD("A=%f\tB=%f\nC=%f\tD=%f", + // dsdx/65536.0, dtdx/65536.0, dsdy/65536.0, dtdy/65536.0); + + int x = l >> 4; + int y = b >> 4; + int w = (r-l) >> 4; + int h = (t-b) >> 4; + texture_unit_t& u(c->textures.tmu[0]); + EGLTextureObject* textureObject = u.texture; + GLint tWidth = textureObject->surface.width; + GLint tHeight = textureObject->surface.height; + GLint crop_rect[4] = {0, tHeight, tWidth, -tHeight}; + const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s; + y = cbSurface.height - (y + h); + return copybit(x, y, w, h, textureObject, crop_rect, transform, c); +} + +/* + * Try to drawTexiOESWithCopybit, return false if we fail. + */ + +bool drawTexiOESWithCopybit_impl(GLint x, GLint y, GLint z, + GLint w, GLint h, ogles_context_t* c) +{ + // quickly process empty rects + if ((w|h) <= 0) { + return true; + } + if (!checkContext(c)) { + return false; + } + texture_unit_t& u(c->textures.tmu[0]); + EGLTextureObject* textureObject = u.texture; + return copybit(x, y, w, h, textureObject, textureObject->crop_rect, 0, c); +} + +} // namespace android + diff --git a/opengl/libagl/copybit.h b/opengl/libagl/copybit.h new file mode 100644 index 0000000..b8b5afd --- /dev/null +++ b/opengl/libagl/copybit.h @@ -0,0 +1,75 @@ +/* +** +** Copyright 2009, 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_COPYBIT_H +#define ANDROID_OPENGLES_COPYBIT_H + +#include + +#include + +#include "TextureObjectManager.h" +namespace android { +#ifdef LIBAGL_USE_GRALLOC_COPYBITS + +bool drawTexiOESWithCopybit_impl(GLint x, GLint y, GLint z, + GLint w, GLint h, ogles_context_t* c); + +bool drawTriangleFanWithCopybit_impl(ogles_context_t* c, GLint first, + GLsizei count); + +inline bool copybitQuickCheckContext(ogles_context_t* c) { + return c->copybits.drawSurfaceBuffer != 0 + && c->rasterizer.state.enabled_tmu == 1 + && c->textures.tmu[0].texture->try_copybit; +} + +/* + * Tries to draw a drawTexiOES using copybit hardware. + * Returns true if successful. + */ +inline bool drawTexiOESWithCopybit(GLint x, GLint y, GLint z, + GLint w, GLint h, ogles_context_t* c) { + if (!copybitQuickCheckContext(c)) { + return false; + } + + return drawTexiOESWithCopybit_impl(x, y, z, w, h, c); +} + +/* + * Tries to draw a triangle fan using copybit hardware. + * Returns true if successful. + */ +inline bool drawTriangleFanWithCopybit(ogles_context_t* c, GLint first, + GLsizei count) { + /* + * We are looking for the glDrawArrays call made by SurfaceFlinger. + */ + + if ((count!=4) || first || !copybitQuickCheckContext(c)) + return false; + + return drawTriangleFanWithCopybit_impl(c, first, count); +} + + +#endif // LIBAGL_USE_GRALLOC_COPYBITS + +} // namespace android + +#endif // ANDROID_OPENGLES_COPYBIT_H diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp index 4461567..673c174 100644 --- a/opengl/libagl/egl.cpp +++ b/opengl/libagl/egl.cpp @@ -15,8 +15,6 @@ ** limitations under the License. */ -#define LOG_TAG "EGL" - #include #include #include @@ -41,6 +39,11 @@ #include #include +#include +#include + +#include + #include "context.h" #include "state.h" #include "texture.h" @@ -89,9 +92,9 @@ static GLint getError() { 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; } @@ -139,19 +142,23 @@ struct egl_surface_t egl_surface_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat); virtual ~egl_surface_t(); - virtual bool isValid() const = 0; - + bool isValid() const; + virtual bool initCheck() const = 0; + virtual EGLBoolean bindDrawSurface(ogles_context_t* gl) = 0; virtual EGLBoolean bindReadSurface(ogles_context_t* gl) = 0; + virtual EGLBoolean connect() { return EGL_TRUE; } + virtual void disconnect() {} 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(); + virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h); + virtual EGLClientBuffer getRenderBuffer() const; protected: GGLSurface depth; }; @@ -170,6 +177,11 @@ egl_surface_t::~egl_surface_t() magic = 0; free(depth.data); } +bool egl_surface_t::isValid() const { + LOGE_IF(magic != MAGIC, "invalid EGLSurface (%p)", this); + return magic == MAGIC; +} + EGLBoolean egl_surface_t::swapBuffers() { return EGL_FALSE; } @@ -185,119 +197,519 @@ EGLint egl_surface_t::getRefreshRate() const { EGLint egl_surface_t::getSwapBehavior() const { return EGL_BUFFER_PRESERVED; } +EGLBoolean egl_surface_t::setSwapRectangle( + EGLint l, EGLint t, EGLint w, EGLint h) +{ + return EGL_FALSE; +} +EGLClientBuffer egl_surface_t::getRenderBuffer() const { + return 0; +} // ---------------------------------------------------------------------------- -struct egl_window_surface_t : public egl_surface_t +struct egl_window_surface_v2_t : public egl_surface_t { - egl_window_surface_t( + egl_window_surface_v2_t( EGLDisplay dpy, EGLConfig config, int32_t depthFormat, - egl_native_window_t* window); + android_native_window_t* window); - ~egl_window_surface_t(); + ~egl_window_surface_v2_t(); - virtual bool isValid() const { return nativeWindow->magic == 0x600913; } + virtual bool initCheck() const { return true; } // TODO: report failure if ctor fails 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 EGLBoolean connect(); + virtual void disconnect(); + virtual EGLint getWidth() const { return width; } + virtual EGLint getHeight() const { return height; } virtual EGLint getHorizontalResolution() const; virtual EGLint getVerticalResolution() const; virtual EGLint getRefreshRate() const; virtual EGLint getSwapBehavior() const; + virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h); + virtual EGLClientBuffer getRenderBuffer() const; + private: - egl_native_window_t* nativeWindow; + status_t lock(android_native_buffer_t* buf, int usage, void** vaddr); + status_t unlock(android_native_buffer_t* buf); + android_native_window_t* nativeWindow; + android_native_buffer_t* buffer; + android_native_buffer_t* previousBuffer; + gralloc_module_t const* module; + copybit_device_t* blitengine; + int width; + int height; + void* bits; + GGLFormat const* pixelFormatTable; + + struct Rect { + inline Rect() { }; + inline Rect(int32_t w, int32_t h) + : left(0), top(0), right(w), bottom(h) { } + inline Rect(int32_t l, int32_t t, int32_t r, int32_t b) + : left(l), top(t), right(r), bottom(b) { } + Rect& andSelf(const Rect& r) { + left = max(left, r.left); + top = max(top, r.top); + right = min(right, r.right); + bottom = min(bottom, r.bottom); + return *this; + } + bool isEmpty() const { + return (left>=right || top>=bottom); + } + void dump(char const* what) { + LOGD("%s { %5d, %5d, w=%5d, h=%5d }", + what, left, top, right-left, bottom-top); + } + + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; + }; + + struct Region { + inline Region() : count(0) { } + typedef Rect const* const_iterator; + const_iterator begin() const { return storage; } + const_iterator end() const { return storage+count; } + static Region subtract(const Rect& lhs, const Rect& rhs) { + Region reg; + Rect* storage = reg.storage; + if (!lhs.isEmpty()) { + if (lhs.top < rhs.top) { // top rect + storage->left = lhs.left; + storage->top = lhs.top; + storage->right = lhs.right; + storage->bottom = rhs.top; + storage++; + } + const int32_t top = max(lhs.top, rhs.top); + const int32_t bot = min(lhs.bottom, rhs.bottom); + if (top < bot) { + if (lhs.left < rhs.left) { // left-side rect + storage->left = lhs.left; + storage->top = top; + storage->right = rhs.left; + storage->bottom = bot; + storage++; + } + if (lhs.right > rhs.right) { // right-side rect + storage->left = rhs.right; + storage->top = top; + storage->right = lhs.right; + storage->bottom = bot; + storage++; + } + } + if (lhs.bottom > rhs.bottom) { // bottom rect + storage->left = lhs.left; + storage->top = rhs.bottom; + storage->right = lhs.right; + storage->bottom = lhs.bottom; + storage++; + } + reg.count = storage - reg.storage; + } + return reg; + } + bool isEmpty() const { + return count<=0; + } + private: + Rect storage[4]; + ssize_t count; + }; + + struct region_iterator : public copybit_region_t { + region_iterator(const Region& region) + : b(region.begin()), e(region.end()) { + this->next = iterate; + } + private: + static int iterate(copybit_region_t const * self, copybit_rect_t* rect) { + region_iterator const* me = static_cast(self); + if (me->b != me->e) { + *reinterpret_cast(rect) = *me->b++; + return 1; + } + return 0; + } + mutable Region::const_iterator b; + Region::const_iterator const e; + }; + + void copyBlt( + android_native_buffer_t* dst, void* dst_vaddr, + android_native_buffer_t* src, void const* src_vaddr, + const Region& clip); + + Rect dirtyRegion; + Rect oldDirtyRegion; }; -egl_window_surface_t::egl_window_surface_t(EGLDisplay dpy, +egl_window_surface_v2_t::egl_window_surface_v2_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat, - egl_native_window_t* window) - : egl_surface_t(dpy, config, depthFormat), nativeWindow(window) + android_native_window_t* window) + : egl_surface_t(dpy, config, depthFormat), + nativeWindow(window), buffer(0), previousBuffer(0), module(0), + blitengine(0), bits(NULL) { - if (depthFormat) { - depth.width = window->width; - depth.height = window->height; + hw_module_t const* pModule; + hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule); + module = reinterpret_cast(pModule); + + if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &pModule) == 0) { + copybit_open(pModule, &blitengine); + } + + pixelFormatTable = gglGetPixelFormatTable(); + + // keep a reference on the window + nativeWindow->common.incRef(&nativeWindow->common); + nativeWindow->query(nativeWindow, NATIVE_WINDOW_WIDTH, &width); + nativeWindow->query(nativeWindow, NATIVE_WINDOW_HEIGHT, &height); +} + +egl_window_surface_v2_t::~egl_window_surface_v2_t() { + if (buffer) { + buffer->common.decRef(&buffer->common); + } + if (previousBuffer) { + previousBuffer->common.decRef(&previousBuffer->common); + } + nativeWindow->common.decRef(&nativeWindow->common); + if (blitengine) { + copybit_close(blitengine); + } +} + +EGLBoolean egl_window_surface_v2_t::connect() +{ + // we're intending to do software rendering + native_window_set_usage(nativeWindow, + GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); + + // dequeue a buffer + if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) != NO_ERROR) { + return setError(EGL_BAD_ALLOC, EGL_FALSE); + } + + // allocate a corresponding depth-buffer + width = buffer->width; + height = buffer->height; + if (depth.format) { + depth.width = width; + depth.height = 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; + return setError(EGL_BAD_ALLOC, EGL_FALSE); } } - nativeWindow->incRef(nativeWindow); + + // keep a reference on the buffer + buffer->common.incRef(&buffer->common); + + // Lock the buffer + nativeWindow->lockBuffer(nativeWindow, buffer); + // pin the buffer down + if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN | + GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) { + LOGE("connect() failed to lock buffer %p (%ux%u)", + buffer, buffer->width, buffer->height); + return setError(EGL_BAD_ACCESS, EGL_FALSE); + // FIXME: we should make sure we're not accessing the buffer anymore + } + return EGL_TRUE; } -egl_window_surface_t::~egl_window_surface_t() { - nativeWindow->decRef(nativeWindow); + +void egl_window_surface_v2_t::disconnect() +{ + if (buffer && bits) { + bits = NULL; + unlock(buffer); + } + // enqueue the last frame + nativeWindow->queueBuffer(nativeWindow, buffer); + if (buffer) { + buffer->common.decRef(&buffer->common); + buffer = 0; + } + if (previousBuffer) { + previousBuffer->common.decRef(&previousBuffer->common); + previousBuffer = 0; + } +} + +status_t egl_window_surface_v2_t::lock( + android_native_buffer_t* buf, int usage, void** vaddr) +{ + int err; + if (sw_gralloc_handle_t::validate(buf->handle) < 0) { + err = module->lock(module, buf->handle, + usage, 0, 0, buf->width, buf->height, vaddr); + } else { + sw_gralloc_handle_t const* hnd = + reinterpret_cast(buf->handle); + *vaddr = (void*)hnd->base; + err = NO_ERROR; + } + return err; +} + +status_t egl_window_surface_v2_t::unlock(android_native_buffer_t* buf) +{ + if (!buf) return BAD_VALUE; + int err = NO_ERROR; + if (sw_gralloc_handle_t::validate(buf->handle) < 0) { + err = module->unlock(module, buf->handle); + } + return err; +} + +void egl_window_surface_v2_t::copyBlt( + android_native_buffer_t* dst, void* dst_vaddr, + android_native_buffer_t* src, void const* src_vaddr, + const Region& clip) +{ + // FIXME: use copybit if possible + // NOTE: dst and src must be the same format + + status_t err = NO_ERROR; + copybit_device_t* const copybit = blitengine; + if (copybit) { + copybit_image_t simg; + simg.w = src->width; + simg.h = src->height; + simg.format = src->format; + simg.handle = const_cast(src->handle); + + copybit_image_t dimg; + dimg.w = dst->width; + dimg.h = dst->height; + dimg.format = dst->format; + dimg.handle = const_cast(dst->handle); + + copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0); + copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 255); + copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE); + region_iterator it(clip); + err = copybit->blit(copybit, &dimg, &simg, &it); + if (err != NO_ERROR) { + LOGE("copybit failed (%s)", strerror(err)); + } + } + + if (!copybit || err) { + Region::const_iterator cur = clip.begin(); + Region::const_iterator end = clip.end(); + + const size_t bpp = pixelFormatTable[src->format].size; + const size_t dbpr = dst->stride * bpp; + const size_t sbpr = src->stride * bpp; + + uint8_t const * const src_bits = (uint8_t const *)src_vaddr; + uint8_t * const dst_bits = (uint8_t *)dst_vaddr; + + while (cur != end) { + const Rect& r(*cur++); + ssize_t w = r.right - r.left; + ssize_t h = r.bottom - r.top; + if (w <= 0 || h<=0) continue; + size_t size = w * bpp; + uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp; + uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp; + if (dbpr==sbpr && size==sbpr) { + size *= h; + h = 1; + } + do { + memcpy(d, s, size); + d += dbpr; + s += sbpr; + } while (--h > 0); + } + } } -EGLBoolean egl_window_surface_t::swapBuffers() +EGLBoolean egl_window_surface_v2_t::swapBuffers() { - uint32_t flags = nativeWindow->swapBuffers(nativeWindow); - if (flags & EGL_NATIVES_FLAG_SIZE_CHANGED) { + if (!buffer) { + return setError(EGL_BAD_ACCESS, EGL_FALSE); + } + + /* + * Handle eglSetSwapRectangleANDROID() + * We copyback from the front buffer + */ + if (!dirtyRegion.isEmpty()) { + dirtyRegion.andSelf(Rect(buffer->width, buffer->height)); + if (previousBuffer) { + const Region copyBack(Region::subtract(oldDirtyRegion, dirtyRegion)); + if (!copyBack.isEmpty()) { + void* prevBits; + if (lock(previousBuffer, + GRALLOC_USAGE_SW_READ_OFTEN, &prevBits) == NO_ERROR) { + // copy from previousBuffer to buffer + copyBlt(buffer, bits, previousBuffer, prevBits, copyBack); + unlock(previousBuffer); + } + } + } + oldDirtyRegion = dirtyRegion; + } + + if (previousBuffer) { + previousBuffer->common.decRef(&previousBuffer->common); + previousBuffer = 0; + } + + unlock(buffer); + previousBuffer = buffer; + nativeWindow->queueBuffer(nativeWindow, buffer); + buffer = 0; + + // dequeue a new buffer + nativeWindow->dequeueBuffer(nativeWindow, &buffer); + + // TODO: lockBuffer should rather be executed when the very first + // direct rendering occurs. + nativeWindow->lockBuffer(nativeWindow, buffer); + + // reallocate the depth-buffer if needed + if ((width != buffer->width) || (height != buffer->height)) { // TODO: we probably should reset the swap rect here // if the window size has changed + width = buffer->width; + height = buffer->height; if (depth.data) { free(depth.data); - depth.width = nativeWindow->width; - depth.height = nativeWindow->height; - depth.stride = nativeWindow->stride; + depth.width = width; + depth.height = height; + depth.stride = buffer->stride; depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2); if (depth.data == 0) { - setError(EGL_BAD_ALLOC, EGL_NO_SURFACE); + setError(EGL_BAD_ALLOC, EGL_FALSE); return EGL_FALSE; } } } + + // keep a reference on the buffer + buffer->common.incRef(&buffer->common); + + // finally pin the buffer down + if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN | + GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) { + LOGE("eglSwapBuffers() failed to lock buffer %p (%ux%u)", + buffer, buffer->width, buffer->height); + return setError(EGL_BAD_ACCESS, EGL_FALSE); + // FIXME: we should make sure we're not accessing the buffer anymore + } + + return EGL_TRUE; +} + +EGLBoolean egl_window_surface_v2_t::setSwapRectangle( + EGLint l, EGLint t, EGLint w, EGLint h) +{ + dirtyRegion = Rect(l, t, l+w, t+h); return EGL_TRUE; } -EGLBoolean egl_window_surface_t::bindDrawSurface(ogles_context_t* gl) +EGLClientBuffer egl_window_surface_v2_t::getRenderBuffer() const +{ + return buffer; +} + +#ifdef LIBAGL_USE_GRALLOC_COPYBITS + +static bool supportedCopybitsDestinationFormat(int format) { + // Hardware supported + switch (format) { + case HAL_PIXEL_FORMAT_RGB_565: + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_RGBX_8888: + case HAL_PIXEL_FORMAT_RGBA_4444: + case HAL_PIXEL_FORMAT_RGBA_5551: + case HAL_PIXEL_FORMAT_BGRA_8888: + return true; + } + return false; +} +#endif + +EGLBoolean egl_window_surface_v2_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; + buffer.width = this->buffer->width; + buffer.height = this->buffer->height; + buffer.stride = this->buffer->stride; + buffer.data = (GGLubyte*)bits; + buffer.format = this->buffer->format; gl->rasterizer.procs.colorBuffer(gl, &buffer); if (depth.data != gl->rasterizer.state.buffers.depth.data) gl->rasterizer.procs.depthBuffer(gl, &depth); + +#ifdef LIBAGL_USE_GRALLOC_COPYBITS + gl->copybits.drawSurfaceBuffer = 0; + if (gl->copybits.blitEngine != NULL) { + if (supportedCopybitsDestinationFormat(buffer.format)) { + buffer_handle_t handle = this->buffer->handle; + if (handle != NULL) { + gl->copybits.drawSurfaceBuffer = this->buffer; + } + } + } +#endif // LIBAGL_USE_GRALLOC_COPYBITS + return EGL_TRUE; } -EGLBoolean egl_window_surface_t::bindReadSurface(ogles_context_t* gl) +EGLBoolean egl_window_surface_v2_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; + buffer.width = this->buffer->width; + buffer.height = this->buffer->height; + buffer.stride = this->buffer->stride; + buffer.data = (GGLubyte*)bits; // FIXME: hopefully is is LOCKED!!! + buffer.format = this->buffer->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 { +EGLint egl_window_surface_v2_t::getHorizontalResolution() const { return (nativeWindow->xdpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f); } -EGLint egl_window_surface_t::getVerticalResolution() const { +EGLint egl_window_surface_v2_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_v2_t::getRefreshRate() const { + return (60 * EGL_DISPLAY_SCALING); // FIXME } -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; +EGLint egl_window_surface_v2_t::getSwapBehavior() const +{ + /* + * EGL_BUFFER_PRESERVED means that eglSwapBuffers() completely preserves + * the content of the swapped buffer. + * + * EGL_BUFFER_DESTROYED means that the content of the buffer is lost. + * + * However when ANDROID_swap_retcangle is supported, EGL_BUFFER_DESTROYED + * only applies to the area specified by eglSetSwapRectangleANDROID(), that + * is, everything outside of this area is preserved. + * + * This implementation of EGL assumes the later case. + * + */ + + return EGL_BUFFER_DESTROYED; } // ---------------------------------------------------------------------------- @@ -311,12 +723,11 @@ struct egl_pixmap_surface_t : public egl_surface_t virtual ~egl_pixmap_surface_t() { } - virtual bool isValid() const { return nativePixmap.version == sizeof(egl_native_pixmap_t); } + virtual bool initCheck() const { return !depth.format || depth.data!=0; } 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; }; @@ -334,7 +745,6 @@ egl_pixmap_surface_t::egl_pixmap_surface_t(EGLDisplay dpy, depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2); if (depth.data == 0) { setError(EGL_BAD_ALLOC, EGL_NO_SURFACE); - return; } } } @@ -347,7 +757,7 @@ EGLBoolean egl_pixmap_surface_t::bindDrawSurface(ogles_context_t* gl) 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); @@ -376,12 +786,11 @@ struct egl_pbuffer_surface_t : public egl_surface_t virtual ~egl_pbuffer_surface_t(); - virtual bool isValid() const { return pbuffer.data != 0; } + virtual bool initCheck() 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; }; @@ -396,6 +805,7 @@ egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy, 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; + case GGL_PIXEL_FORMAT_RGBX_8888: size *= 4; break; default: LOGE("incompatible pixel format for pbuffer (format=%d)", f); pbuffer.data = 0; @@ -407,7 +817,7 @@ egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy, pbuffer.stride = w; pbuffer.data = (GGLubyte*)malloc(size); pbuffer.format = f; - + if (depthFormat) { depth.width = pbuffer.width; depth.height = pbuffer.height; @@ -468,7 +878,13 @@ struct config_management_t { 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 = ""; +static char const * const gExtensionsString = + "EGL_KHR_image_base " + // "KHR_image_pixmap " + "EGL_ANDROID_image_native_buffer " + "EGL_ANDROID_swap_rectangle " + "EGL_ANDROID_get_render_buffer " + ; // ---------------------------------------------------------------------------- @@ -496,6 +912,10 @@ static const extention_map_t gExtentionMap[] = { (__eglMustCastToProperFunctionPointerType)&glDrawTexxvOES }, { "glQueryMatrixxOES", (__eglMustCastToProperFunctionPointerType)&glQueryMatrixxOES }, + { "glEGLImageTargetTexture2DOES", + (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetTexture2DOES }, + { "glEGLImageTargetRenderbufferStorageOES", + (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetRenderbufferStorageOES }, { "glClipPlanef", (__eglMustCastToProperFunctionPointerType)&glClipPlanef }, { "glClipPlanex", @@ -510,9 +930,17 @@ static const extention_map_t gExtentionMap[] = { (__eglMustCastToProperFunctionPointerType)&glDeleteBuffers }, { "glGenBuffers", (__eglMustCastToProperFunctionPointerType)&glGenBuffers }, + { "eglCreateImageKHR", + (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR }, + { "eglDestroyImageKHR", + (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR }, + { "eglSetSwapRectangleANDROID", + (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID }, + { "eglGetRenderBufferANDROID", + (__eglMustCastToProperFunctionPointerType)&eglGetRenderBufferANDROID }, }; -/* +/* * In the lists below, attributes names MUST be sorted. * Additionally, all configs must be sorted according to * the EGL specification. @@ -523,7 +951,7 @@ static config_pair_t const config_base_attribute_list[] = { { EGL_CONFIG_CAVEAT, EGL_SLOW_CONFIG }, { EGL_LEVEL, 0 }, { EGL_MAX_PBUFFER_HEIGHT, GGL_MAX_VIEWPORT_DIMS }, - { EGL_MAX_PBUFFER_PIXELS, + { 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 }, @@ -538,12 +966,18 @@ static config_pair_t const config_base_attribute_list[] = { { EGL_BIND_TO_TEXTURE_RGBA, EGL_FALSE }, { EGL_BIND_TO_TEXTURE_RGB, EGL_FALSE }, { EGL_MIN_SWAP_INTERVAL, 1 }, - { EGL_MAX_SWAP_INTERVAL, 4 }, + { EGL_MAX_SWAP_INTERVAL, 1 }, + { EGL_LUMINANCE_SIZE, 0 }, + { EGL_ALPHA_MASK_SIZE, 0 }, + { EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER }, + { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT }, + { EGL_CONFORMANT, 0 } }; // These configs can override the base attribute list // NOTE: when adding a config here, don't forget to update eglCreate*Surface() +// 565 configs static config_pair_t const config_0_attribute_list[] = { { EGL_BUFFER_SIZE, 16 }, { EGL_ALPHA_SIZE, 0 }, @@ -566,8 +1000,32 @@ static config_pair_t const config_1_attribute_list[] = { { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, }; +// RGB 888 configs static config_pair_t const config_2_attribute_list[] = { { EGL_BUFFER_SIZE, 32 }, + { EGL_ALPHA_SIZE, 0 }, + { EGL_BLUE_SIZE, 8 }, + { EGL_GREEN_SIZE, 8 }, + { EGL_RED_SIZE, 8 }, + { EGL_DEPTH_SIZE, 0 }, + { EGL_CONFIG_ID, 6 }, + { 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, 0 }, + { EGL_BLUE_SIZE, 8 }, + { EGL_GREEN_SIZE, 8 }, + { EGL_RED_SIZE, 8 }, + { EGL_DEPTH_SIZE, 16 }, + { EGL_CONFIG_ID, 7 }, + { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, +}; + +// 8888 configs +static config_pair_t const config_4_attribute_list[] = { + { EGL_BUFFER_SIZE, 32 }, { EGL_ALPHA_SIZE, 8 }, { EGL_BLUE_SIZE, 8 }, { EGL_GREEN_SIZE, 8 }, @@ -577,7 +1035,7 @@ static config_pair_t const config_2_attribute_list[] = { { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, }; -static config_pair_t const config_3_attribute_list[] = { +static config_pair_t const config_5_attribute_list[] = { { EGL_BUFFER_SIZE, 32 }, { EGL_ALPHA_SIZE, 8 }, { EGL_BLUE_SIZE, 8 }, @@ -588,7 +1046,8 @@ static config_pair_t const config_3_attribute_list[] = { { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, }; -static config_pair_t const config_4_attribute_list[] = { +// A8 configs +static config_pair_t const config_6_attribute_list[] = { { EGL_BUFFER_SIZE, 8 }, { EGL_ALPHA_SIZE, 8 }, { EGL_BLUE_SIZE, 0 }, @@ -599,7 +1058,7 @@ static config_pair_t const config_4_attribute_list[] = { { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, }; -static config_pair_t const config_5_attribute_list[] = { +static config_pair_t const config_7_attribute_list[] = { { EGL_BUFFER_SIZE, 8 }, { EGL_ALPHA_SIZE, 8 }, { EGL_BLUE_SIZE, 0 }, @@ -617,6 +1076,8 @@ static configs_t const gConfigs[] = { { 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) }, + { config_6_attribute_list, NELEM(config_6_attribute_list) }, + { config_7_attribute_list, NELEM(config_7_attribute_list) }, }; static config_management_t const gConfigManagement[] = { @@ -647,22 +1108,74 @@ static config_management_t const gConfigManagement[] = { { 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 }, + { EGL_LUMINANCE_SIZE, config_management_t::atLeast }, + { EGL_ALPHA_MASK_SIZE, config_management_t::atLeast }, + { EGL_COLOR_BUFFER_TYPE, config_management_t::exact }, + { EGL_RENDERABLE_TYPE, config_management_t::mask }, + { EGL_CONFORMANT, config_management_t::mask } }; + static config_pair_t const config_defaults[] = { - { EGL_SURFACE_TYPE, EGL_WINDOW_BIT }, + // attributes that are not specified are simply ignored, if a particular + // one needs not be ignored, it must be specified here, eg: + // { EGL_SURFACE_TYPE, EGL_WINDOW_BIT }, }; // ---------------------------------------------------------------------------- +static status_t getConfigFormatInfo(EGLint configID, + int32_t& pixelFormat, int32_t& depthFormat) +{ + 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_RGBX_8888; + depthFormat = 0; + break; + case 3: + pixelFormat = GGL_PIXEL_FORMAT_RGBX_8888; + depthFormat = GGL_PIXEL_FORMAT_Z_16; + break; + case 4: + pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888; + depthFormat = 0; + break; + case 5: + pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888; + depthFormat = GGL_PIXEL_FORMAT_Z_16; + break; + case 6: + pixelFormat = GGL_PIXEL_FORMAT_A_8; + depthFormat = 0; + break; + case 7: + pixelFormat = GGL_PIXEL_FORMAT_A_8; + depthFormat = GGL_PIXEL_FORMAT_Z_16; + break; + default: + return NAME_NOT_FOUND; + } + return NO_ERROR; +} + +// ---------------------------------------------------------------------------- + template 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) { + if (key > sortedArray[mid].key) { first = mid + 1; - } else if (key < sortedArray[mid].key) { + } else if (key < sortedArray[mid].key) { last = mid - 1; } else { return mid; @@ -674,13 +1187,13 @@ static int binarySearch(T const sortedArray[], int first, int last, EGLint key) 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; + config_pair_t const* configFound = gConfigs[i].array; int index = binarySearch( gConfigs[i].array, 0, gConfigs[i].size-1, attr); if (index < 0) { - configFound = config_base_attribute_list; + configFound = config_base_attribute_list; index = binarySearch( config_base_attribute_list, 0, NELEM(config_base_attribute_list)-1, @@ -787,38 +1300,18 @@ static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config, if (!(surfaceType & EGL_WINDOW_BIT)) return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); + if (static_cast(window)->common.magic != + ANDROID_NATIVE_WINDOW_MAGIC) { + return setError(EGL_BAD_NATIVE_WINDOW, 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: + if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) { return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); } @@ -828,11 +1321,11 @@ static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config, //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(window)); + egl_surface_t* surface; + surface = new egl_window_surface_v2_t(dpy, config, depthFormat, + static_cast(window)); - if (!surface->isValid()) { + if (!surface->initCheck()) { // there was a problem in the ctor, the error // flag has been set. delete surface; @@ -856,38 +1349,18 @@ static EGLSurface createPixmapSurface(EGLDisplay dpy, EGLConfig config, if (!(surfaceType & EGL_PIXMAP_BIT)) return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); + if (static_cast(pixmap)->version != + sizeof(egl_native_pixmap_t)) { + return setError(EGL_BAD_NATIVE_PIXMAP, 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: + if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) { return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); } @@ -898,7 +1371,7 @@ static EGLSurface createPixmapSurface(EGLDisplay dpy, EGLConfig config, new egl_pixmap_surface_t(dpy, config, depthFormat, static_cast(pixmap)); - if (!surface->isValid()) { + if (!surface->initCheck()) { // there was a problem in the ctor, the error // flag has been set. delete surface; @@ -916,42 +1389,17 @@ static EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config, 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: + if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) { return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); } @@ -966,7 +1414,7 @@ static EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config, egl_surface_t* surface = new egl_pbuffer_surface_t(dpy, config, depthFormat, w, h, pixelFormat); - if (!surface->isValid()) { + if (!surface->initCheck()) { // there was a problem in the ctor, the error // flag has been set. delete surface; @@ -1001,7 +1449,7 @@ EGLDisplay eglGetDisplay(NativeDisplayType display) egl_display_t& d = egl_display_t::get_display(dpy); d.type = display; return dpy; - } + } return EGL_NO_DISPLAY; } @@ -1009,10 +1457,10 @@ 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); @@ -1080,7 +1528,7 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, *num_config = 0; return EGL_TRUE; } - + int numAttributes = 0; int numConfigs = NELEM(gConfigs); uint32_t possibleMatch = (1<( (config_pair_t const*)attrib_list, 0, numAttributes-1, config_defaults[j].key) < 0) { - for (int i=0 ; i(eglSurface) ); - if (surface->magic != egl_surface_t::MAGIC) + if (!surface->isValid()) return setError(EGL_BAD_SURFACE, EGL_FALSE); if (surface->dpy != dpy) return setError(EGL_BAD_DISPLAY, EGL_FALSE); + if (surface->ctx) { + // FIXME: this surface is current check what the spec says + surface->disconnect(); + surface->ctx = 0; + } delete surface; } return EGL_TRUE; @@ -1196,6 +1649,8 @@ EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface eglSurface, if (egl_display_t::is_valid(dpy) == EGL_FALSE) return setError(EGL_BAD_DISPLAY, EGL_FALSE); egl_surface_t* surface = static_cast(eglSurface); + if (!surface->isValid()) + return setError(EGL_BAD_SURFACE, EGL_FALSE); if (surface->dpy != dpy) return setError(EGL_BAD_DISPLAY, EGL_FALSE); @@ -1244,7 +1699,7 @@ EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface eglSurface, *value = (wr * EGL_DISPLAY_SCALING) / hr; } break; case EGL_SWAP_BEHAVIOR: - *value = surface->getSwapBehavior(); + *value = surface->getSwapBehavior(); break; default: ret = setError(EGL_BAD_ATTRIBUTE, EGL_FALSE); @@ -1288,13 +1743,23 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, return setError(EGL_BAD_DISPLAY, EGL_FALSE); if (draw) { egl_surface_t* s = (egl_surface_t*)draw; + if (!s->isValid()) + return setError(EGL_BAD_SURFACE, EGL_FALSE); if (s->dpy != dpy) return setError(EGL_BAD_DISPLAY, EGL_FALSE); - // TODO: check that draw and read are compatible with the context + // TODO: check that draw is compatible with the context + } + if (read && read!=draw) { + egl_surface_t* s = (egl_surface_t*)read; + if (!s->isValid()) + return setError(EGL_BAD_SURFACE, EGL_FALSE); + if (s->dpy != dpy) + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + // TODO: check that read is 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); @@ -1310,21 +1775,29 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface 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 + // one of the surface is bound to a context in another thread return setError(EGL_BAD_ACCESS, EGL_FALSE); } } - // TODO: call connect / disconnect on the surface - 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; + + if (c->draw) { + egl_surface_t* s = reinterpret_cast(c->draw); + s->disconnect(); + } + if (c->read) { + // FIXME: unlock/disconnect the read surface too + } + c->draw = draw; + c->read = read; + if (c->flags & egl_context_t::NEVER_CURRENT) { c->flags &= ~egl_context_t::NEVER_CURRENT; GLint w = 0; @@ -1338,10 +1811,14 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, ogles_scissor(gl, 0, 0, w, h); } if (d) { + if (d->connect() == EGL_FALSE) { + return EGL_FALSE; + } d->ctx = ctx; d->bindDrawSurface(gl); } if (r) { + // FIXME: lock/connect the read surface too r->ctx = ctx; r->bindReadSurface(gl); } @@ -1352,8 +1829,16 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, 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; + if (d) { + c->draw = 0; + d->ctx = EGL_NO_CONTEXT; + d->disconnect(); + } + if (r) { + c->read = 0; + r->ctx = EGL_NO_CONTEXT; + // FIXME: unlock/disconnect the read surface too + } } } return EGL_TRUE; @@ -1425,8 +1910,10 @@ 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(draw); + if (!d->isValid()) + return setError(EGL_BAD_SURFACE, EGL_FALSE); if (d->dpy != dpy) return setError(EGL_BAD_DISPLAY, EGL_FALSE); @@ -1558,7 +2045,7 @@ EGLSurface eglCreatePbufferFromClientBuffer( } // ---------------------------------------------------------------------------- -// Android extensions +// EGL_EGLEXT_VERSION 3 // ---------------------------------------------------------------------------- void (*eglGetProcAddress (const char *procname))() @@ -1571,3 +2058,97 @@ void (*eglGetProcAddress (const char *procname))() } return NULL; } + +EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, + const EGLint *attrib_list) +{ + EGLBoolean result = EGL_FALSE; + return result; +} + +EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface) +{ + EGLBoolean result = EGL_FALSE; + return result; +} + +EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, + EGLClientBuffer buffer, const EGLint *attrib_list) +{ + if (egl_display_t::is_valid(dpy) == EGL_FALSE) { + return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR); + } + if (ctx != EGL_NO_CONTEXT) { + return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR); + } + if (target != EGL_NATIVE_BUFFER_ANDROID) { + return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); + } + + android_native_buffer_t* native_buffer = (android_native_buffer_t*)buffer; + + if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) + return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); + + if (native_buffer->common.version != sizeof(android_native_buffer_t)) + return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); + + native_buffer->common.incRef(&native_buffer->common); + return (EGLImageKHR)native_buffer; +} + +EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) +{ + if (egl_display_t::is_valid(dpy) == EGL_FALSE) { + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + } + + android_native_buffer_t* native_buffer = (android_native_buffer_t*)img; + + if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) + return setError(EGL_BAD_PARAMETER, EGL_FALSE); + + if (native_buffer->common.version != sizeof(android_native_buffer_t)) + return setError(EGL_BAD_PARAMETER, EGL_FALSE); + + native_buffer->common.decRef(&native_buffer->common); + + return EGL_TRUE; +} + +// ---------------------------------------------------------------------------- +// ANDROID extensions +// ---------------------------------------------------------------------------- + +EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw, + EGLint left, EGLint top, EGLint width, EGLint height) +{ + if (egl_display_t::is_valid(dpy) == EGL_FALSE) + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + + egl_surface_t* d = static_cast(draw); + if (!d->isValid()) + return setError(EGL_BAD_SURFACE, EGL_FALSE); + if (d->dpy != dpy) + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + + // post the surface + d->setSwapRectangle(left, top, width, height); + + return EGL_TRUE; +} + +EGLClientBuffer eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw) +{ + if (egl_display_t::is_valid(dpy) == EGL_FALSE) + return setError(EGL_BAD_DISPLAY, (EGLClientBuffer)0); + + egl_surface_t* d = static_cast(draw); + if (!d->isValid()) + return setError(EGL_BAD_SURFACE, (EGLClientBuffer)0); + if (d->dpy != dpy) + return setError(EGL_BAD_DISPLAY, (EGLClientBuffer)0); + + // post the surface + return d->getRenderBuffer(); +} diff --git a/opengl/libagl/light.cpp b/opengl/libagl/light.cpp index 8ae32cc..f211bca 100644 --- a/opengl/libagl/light.cpp +++ b/opengl/libagl/light.cpp @@ -216,6 +216,8 @@ static inline void light_picker(ogles_context_t* c) static inline void validate_light_mvi(ogles_context_t* c) { uint32_t en = c->lighting.enabledLights; + // Vector from object to viewer, in eye coordinates + const vec4_t eyeViewer = { 0, 0, 0x1000, 0 }; while (en) { const int i = 31 - gglClz(en); en &= ~(1<transforms.mvui.point4(&c->transforms.mvui, &l.objPosition, &l.position); vnorm3(l.normalizedObjPosition.v, l.objPosition.v); + c->transforms.mvui.point4(&c->transforms.mvui, + &l.objViewer, &eyeViewer); + vnorm3(l.objViewer.v, l.objViewer.v); } } @@ -379,9 +384,9 @@ void lightVertex(ogles_context_t* c, vertex_t* 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; + h.x = d.x + l.objViewer.x; + h.y = d.y + l.objViewer.y; + h.z = d.z + l.objViewer.z; vnorm3(h.v, h.v); s = dot3(n.v, h.v); s = (s<0) ? (twoSide?(-s):0) : s; diff --git a/opengl/libagl/matrix.cpp b/opengl/libagl/matrix.cpp index 0b68dc0..3c50977 100644 --- a/opengl/libagl/matrix.cpp +++ b/opengl/libagl/matrix.cpp @@ -696,6 +696,8 @@ void ogles_viewport(ogles_context_t* c, 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 (c->transforms.mvp4.flags & transform_t::FLAGS_2D_PROJECTION) + c->transforms.dirty |= transform_state_t::MVP; } // ---------------------------------------------------------------------------- @@ -739,20 +741,19 @@ void point4__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) { void point4__mvui(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) { // this used for transforming light positions back to object space. - // Lights have 3 components positions, so w is always 1. - // however, it is used as a switch for directional lights, so we need + // w is used as a switch for directional lights, so we need // to preserve it. 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 = rhs->w; + 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 = rw; } - void point2__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) { lhs->z = 0; lhs->w = 0x10000; diff --git a/opengl/libagl/primitives.cpp b/opengl/libagl/primitives.cpp index f164c02..769ec40 100644 --- a/opengl/libagl/primitives.cpp +++ b/opengl/libagl/primitives.cpp @@ -369,7 +369,7 @@ 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); + iterators0032(it64, c0, c1, c2); it[0] = it64[0]; it[1] = it64[1]; it[2] = it64[2]; diff --git a/opengl/libagl/state.cpp b/opengl/libagl/state.cpp index 5cbabea..a59b3b0 100644 --- a/opengl/libagl/state.cpp +++ b/opengl/libagl/state.cpp @@ -2,16 +2,16 @@ ** ** 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 +** 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 +** 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 +** 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. */ @@ -28,12 +28,16 @@ #include "BufferObjectManager.h" #include "TextureObjectManager.h" +#ifdef LIBAGL_USE_GRALLOC_COPYBITS +#include +#endif // LIBAGL_USE_GRALLOC_COPYBITS + namespace android { // ---------------------------------------------------------------------------- static char const * const gVendorString = "Android"; -static char const * const gRendererString = "Android PixelFlinger 1.0"; +static char const * const gRendererString = "Android PixelFlinger 1.1"; static char const * const gVersionString = "OpenGL ES-CM 1.0"; static char const * const gExtensionsString = "GL_OES_byte_coordinates " // OK @@ -46,9 +50,9 @@ static char const * const gExtensionsString = "GL_OES_query_matrix " // OK // "GL_OES_point_size_array " // TODO // "GL_OES_point_sprite " // TODO + "GL_OES_EGL_image " // OK "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 @@ -62,13 +66,13 @@ static char const * const gExtensionsString = ogles_context_t *ogles_init(size_t extra) { void* const base = malloc(extra + sizeof(ogles_context_t) + 32); - if (!base) return 0; + 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 smgr(new EGLSurfaceManager()); c->surfaceManager = smgr.get(); @@ -87,13 +91,42 @@ ogles_context_t *ogles_init(size_t extra) 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); + c->copybits.blitEngine = NULL; + c->copybits.minScale = 0; + c->copybits.maxScale = 0; + c->copybits.drawSurfaceBuffer = 0; + +#ifdef LIBAGL_USE_GRALLOC_COPYBITS + hw_module_t const* module; + if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) { + struct copybit_device_t* copyBits; + if (copybit_open(module, ©Bits) == 0) { + c->copybits.blitEngine = copyBits; + { + int minLim = copyBits->get(copyBits, + COPYBIT_MINIFICATION_LIMIT); + if (minLim != -EINVAL && minLim > 0) { + c->copybits.minScale = (1 << 16) / minLim; + } + } + { + int magLim = copyBits->get(copyBits, + COPYBIT_MAGNIFICATION_LIMIT); + if (magLim != -EINVAL && magLim > 0) { + c->copybits.maxScale = min(32*1024-1, magLim) << 16; + } + } + } + } +#endif // LIBAGL_USE_GRALLOC_COPYBITS + return c; } @@ -107,7 +140,12 @@ void ogles_uninit(ogles_context_t* c) c->surfaceManager->decStrong(c); c->bufferObjectManager->decStrong(c); ggl_uninit_context(&(c->rasterizer)); - free(c->rasterizer.base); + free(c->rasterizer.base); +#ifdef LIBAGL_USE_GRALLOC_COPYBITS + if (c->copybits.blitEngine != NULL) { + copybit_close((struct copybit_device_t*) c->copybits.blitEngine); + } +#endif // LIBAGL_USE_GRALLOC_COPYBITS } void _ogles_error(ogles_context_t* c, GLenum error) @@ -188,7 +226,7 @@ static void enable_disable(ogles_context_t* c, GLenum cap, int enabled) // 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: @@ -281,7 +319,7 @@ void glHint(GLenum target, GLenum mode) case GL_LINE_SMOOTH_HINT: break; case GL_POINT_SMOOTH_HINT: - c->rasterizer.procs.enableDisable(c, + c->rasterizer.procs.enableDisable(c, GGL_POINT_SMOOTH_NICE, mode==GL_NICEST); break; case GL_PERSPECTIVE_CORRECTION_HINT: @@ -323,7 +361,7 @@ GLenum glGetError() c->error = 0; return ret; } - + if (c->rasterizer.error) { const GLenum ret(c->rasterizer.error); c->rasterizer.error = 0; @@ -362,25 +400,25 @@ void glGetIntegerv(GLenum pname, GLint *params) int index = c->rasterizer.state.buffers.color.format; GGLFormat const * formats = gglGetPixelFormatTable(); params[0] = formats[index].ah - formats[index].al; - break; + 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; + 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; + 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; + break; } case GL_COMPRESSED_TEXTURE_FORMATS: params[ 0] = GL_PALETTE4_RGB8_OES; diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp index 14a910c..13d078e 100644 --- a/opengl/libagl/texture.cpp +++ b/opengl/libagl/texture.cpp @@ -2,16 +2,16 @@ ** ** 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 +** 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 +** 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 +** 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. */ @@ -23,6 +23,12 @@ #include "texture.h" #include "TextureObjectManager.h" +#include + +#ifdef LIBAGL_USE_GRALLOC_COPYBITS +#include "copybit.h" +#endif // LIBAGL_USE_GRALLOC_COPYBITS + namespace android { // ---------------------------------------------------------------------------- @@ -48,7 +54,7 @@ void ogles_init_texture(ogles_context_t* c) // 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; itextures.defaultTexture); @@ -96,7 +102,7 @@ void validate_tmu(ogles_context_t* c, int i) } } -void ogles_validate_texture_impl(ogles_context_t* c) +void ogles_validate_texture(ogles_context_t* c) { for (int i=0 ; irasterizer.state.texture[i].enable) @@ -110,6 +116,66 @@ void invalidate_texture(ogles_context_t* c, int tmu, uint8_t flags = 0xFF) { c->textures.tmu[tmu].dirty = flags; } +/* + * If the active textures are EGLImage, they need to be locked before + * they can be used. + * + * FIXME: code below is far from being optimal + * + */ + +void ogles_lock_textures(ogles_context_t* c) +{ + for (int i=0 ; irasterizer.state.texture[i].enable) { + texture_unit_t& u(c->textures.tmu[i]); + android_native_buffer_t* native_buffer = u.texture->buffer; + if (native_buffer) { + c->rasterizer.procs.activeTexture(c, i); + hw_module_t const* pModule; + if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule)) + continue; + + gralloc_module_t const* module = + reinterpret_cast(pModule); + + void* vaddr; + int err = module->lock(module, native_buffer->handle, + GRALLOC_USAGE_SW_READ_OFTEN, + 0, 0, native_buffer->width, native_buffer->height, + &vaddr); + + u.texture->setImageBits(vaddr); + c->rasterizer.procs.bindTexture(c, &(u.texture->surface)); + } + } + } +} + +void ogles_unlock_textures(ogles_context_t* c) +{ + for (int i=0 ; irasterizer.state.texture[i].enable) { + texture_unit_t& u(c->textures.tmu[i]); + android_native_buffer_t* native_buffer = u.texture->buffer; + if (native_buffer) { + c->rasterizer.procs.activeTexture(c, i); + hw_module_t const* pModule; + if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule)) + continue; + + gralloc_module_t const* module = + reinterpret_cast(pModule); + + module->unlock(module, native_buffer->handle); + u.texture->setImageBits(NULL); + c->rasterizer.procs.bindTexture(c, &(u.texture->surface)); + } + } + } + c->rasterizer.procs.activeTexture(c, c->textures.active); +} + // ---------------------------------------------------------------------------- #if 0 #pragma mark - @@ -255,7 +321,7 @@ sp getAndBindActiveTextureObject(ogles_context_t* c) u.texture->decStrong(c); if (name == 0) { - // 0 is our local texture object, not shared with anyone. + // 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; @@ -273,7 +339,7 @@ sp getAndBindActiveTextureObject(ogles_context_t* c) u.texture = tex.get(); u.texture->incStrong(c); u.name = name; - invalidate_texture(c, active); + invalidate_texture(c, active); return tex; } @@ -282,7 +348,7 @@ void bindTextureTmu( { 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) @@ -310,7 +376,7 @@ int createTextureSurface(ogles_context_t* c, 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; @@ -343,6 +409,49 @@ int createTextureSurface(ogles_context_t* c, return 0; } +static size_t dataSizePalette4(int numLevels, int width, int height, 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; + } + + size_t size = (1 << indexBits) * entrySize; // palette size + + for (int i=0 ; i< numLevels ; i++) { + int w = (width >> i) ? : 1; + int h = (height >> i) ? : 1; + int levelSize = h * ((w * indexBits) / 8) ? : 1; + size += levelSize; + } + + return size; +} + static void decodePalette4(const GLvoid *data, int level, int width, int height, void *surface, int stride, int format) @@ -377,6 +486,7 @@ static void decodePalette4(const GLvoid *data, int level, int width, int height, } const int paletteSize = (1 << indexBits) * entrySize; + uint8_t const* pixels = (uint8_t *)data + paletteSize; for (int i=0 ; i> i) ? : 1; @@ -530,8 +640,8 @@ static void texParameterx( ogles_error(c, GL_INVALID_ENUM); return; } - - EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture; + + EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture; switch (pname) { case GL_TEXTURE_WRAP_S: if ((param == GL_REPEAT) || @@ -581,12 +691,11 @@ invalid_enum: } -static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h, + +static void drawTexxOESImp(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h, ogles_context_t* c) { - // quickly reject empty rects - if ((w|h) <= 0) - return; + ogles_lock_textures(c); const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s; y = gglIntToFixed(cbSurface.height) - (y + h); @@ -610,7 +719,7 @@ static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h, GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_T, GGL_CLAMP); u.dirty = 0xFF; // XXX: should be more subtle - EGLTextureObject* textureObject = u.texture; + 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; @@ -641,11 +750,30 @@ static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h, 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, + c->rasterizer.procs.recti(c, gglFixedToIntRound(x), gglFixedToIntRound(y), gglFixedToIntRound(x)+w, gglFixedToIntRound(y)+h); + + ogles_unlock_textures(c); +} + +static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h, + ogles_context_t* c) +{ +#ifdef LIBAGL_USE_GRALLOC_COPYBITS + if (drawTexiOESWithCopybit(gglFixedToIntRound(x), + gglFixedToIntRound(y), gglFixedToIntRound(z), + gglFixedToIntRound(w), gglFixedToIntRound(h), c)) { + return; + } +#else + // quickly reject empty rects + if ((w|h) <= 0) + return; +#endif + drawTexxOESImp(x, y, z, w, h, c); } static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_context_t* c) @@ -656,14 +784,21 @@ static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_conte // which is a lot faster. if (ggl_likely(c->rasterizer.state.enabled_tmu == 1)) { +#ifdef LIBAGL_USE_GRALLOC_COPYBITS + if (drawTexiOESWithCopybit(x, y, z, w, h, c)) { + return; + } +#endif const int tmu = 0; texture_unit_t& u(c->textures.tmu[tmu]); - EGLTextureObject* textureObject = u.texture; + EGLTextureObject* textureObject = u.texture; const GLint Wcr = textureObject->crop_rect[2]; const GLint Hcr = textureObject->crop_rect[3]; if ((w == Wcr) && (h == -Hcr)) { +#ifndef LIBAGL_USE_GRALLOC_COPYBITS if ((w|h) <= 0) return; // quickly reject empty rects +#endif if (u.dirty) { c->rasterizer.procs.activeTexture(c, tmu); @@ -679,14 +814,14 @@ static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_conte 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)) { @@ -694,7 +829,9 @@ static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_conte // in this case, so we just use the slow case, which // at least won't crash goto slow_case; - } + } + + ogles_lock_textures(c); c->rasterizer.procs.texCoord2i(c, s0, t0); const uint32_t enables = c->rasterizer.state.enables; @@ -706,12 +843,15 @@ static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_conte 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); + + ogles_unlock_textures(c); + return; } } slow_case: - drawTexxOES( + drawTexxOESImp( gglIntToFixed(x), gglIntToFixed(y), gglIntToFixed(z), gglIntToFixed(w), gglIntToFixed(h), c); @@ -749,7 +889,7 @@ void glBindTexture(GLenum target, GLuint texture) } // Bind or create a texture - sp tex; + sp tex; if (texture == 0) { // 0 is our local texture object tex = c->textures.defaultTexture; @@ -837,7 +977,7 @@ void glPixelStorei(GLenum pname, GLint param) 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; @@ -952,7 +1092,7 @@ void glCompressedTexImage2D( } // "uncompress" the texture since pixelflinger doesn't support - // any compressed texture format natively. + // any compressed texture format natively. GLenum format; GLenum type; switch (internalformat) { @@ -995,6 +1135,12 @@ void glCompressedTexImage2D( GGLSurface* surface; // all mipmap levels are specified at once. const int numLevels = level<0 ? -level : 1; + + if (dataSizePalette4(numLevels, width, height, format) > imageSize) { + ogles_error(c, GL_INVALID_VALUE); + return; + } + for (int i=0 ; i> i) ? : 1; int lod_h = (height >> i) ? : 1; @@ -1016,7 +1162,7 @@ void glTexImage2D( 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) { + if (target != GL_TEXTURE_2D) { ogles_error(c, GL_INVALID_ENUM); return; } @@ -1024,7 +1170,7 @@ void glTexImage2D( ogles_error(c, GL_INVALID_VALUE); return; } - if (format != internalformat) { + if (format != (GLenum)internalformat) { ogles_error(c, GL_INVALID_OPERATION); return; } @@ -1034,16 +1180,10 @@ void glTexImage2D( 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); + int error = createTextureSurface(c, &surface, &size, + level, format, type, width, height); + if (error) { + ogles_error(c, error); return; } @@ -1064,18 +1204,12 @@ void glTexImage2D( 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 tex = getAndBindActiveTextureObject(c); - tex->setSurface(&userSurface); + int err = copyPixels(c, *surface, 0, 0, userSurface, 0, 0, width, height); + if (err) { + ogles_error(c, err); + return; } + generateMipmap(c, level); } } @@ -1118,6 +1252,11 @@ void glTexSubImage2D( ogles_error(c, GL_INVALID_OPERATION); return; } + + if (format != 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); @@ -1150,7 +1289,7 @@ void glTexSubImage2D( int err = copyPixels(c, surface, xoffset, yoffset, - userSurface, 0, 0, width, height); + userSurface, 0, 0, width, height); if (err) { ogles_error(c, err); return; @@ -1203,7 +1342,7 @@ void glCopyTexImage2D( case GL_LUMINANCE_ALPHA: case GL_LUMINANCE: type = GL_UNSIGNED_BYTE; - break; + break; } // figure out the format to use for the new texture @@ -1213,7 +1352,7 @@ void glCopyTexImage2D( case GGL_PIXEL_FORMAT_RGBA_5551: case GGL_PIXEL_FORMAT_RGBA_4444: format = internalformat; - break; + break; case GGL_PIXEL_FORMAT_RGBX_8888: case GGL_PIXEL_FORMAT_RGB_888: case GGL_PIXEL_FORMAT_RGB_565: @@ -1222,7 +1361,7 @@ void glCopyTexImage2D( case GL_LUMINANCE: case GL_RGB: format = internalformat; - break; + break; } break; } @@ -1242,7 +1381,7 @@ void glCopyTexImage2D( ogles_error(c, error); return; } - + // The bottom row is stored first in textures GGLSurface txSurface(*surface); txSurface.stride = -txSurface.stride; @@ -1252,7 +1391,7 @@ void glCopyTexImage2D( int err = copyPixels(c, txSurface, 0, 0, - cbSurface, x, y, cbSurface.width, cbSurface.height); + cbSurface, x, y, cbSurface.width, cbSurface.height); if (err) { ogles_error(c, err); } @@ -1302,7 +1441,7 @@ void glCopyTexSubImage2D( int err = copyPixels(c, surface, xoffset, yoffset, - cbSurface, x, y, width, height); + cbSurface, x, y, width, height); if (err) { ogles_error(c, err); return; @@ -1372,7 +1511,7 @@ void glReadPixels( return; } - ggl->colorBuffer(ggl, &userSurface); // destination is user buffer + 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); @@ -1426,3 +1565,43 @@ 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); } + +// ---------------------------------------------------------------------------- +#if 0 +#pragma mark - +#pragma mark EGL Image Extension +#endif + +void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image) +{ + ogles_context_t* c = ogles_context_t::get(); + if (target != GL_TEXTURE_2D) { + ogles_error(c, GL_INVALID_ENUM); + return; + } + + android_native_buffer_t* native_buffer = (android_native_buffer_t*)image; + if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) { + ogles_error(c, GL_INVALID_VALUE); + return; + } + if (native_buffer->common.version != sizeof(android_native_buffer_t)) { + ogles_error(c, GL_INVALID_VALUE); + return; + } + + // bind it to the texture unit + sp tex = getAndBindActiveTextureObject(c); + tex->setImage(native_buffer); + +#ifdef LIBAGL_USE_GRALLOC_COPYBITS + tex->try_copybit = false; + if (c->copybits.blitEngine != NULL) { + tex->try_copybit = true; + } +#endif // LIBAGL_USE_GRALLOC_COPYBITS +} + +void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image) +{ +} diff --git a/opengl/libagl/texture.h b/opengl/libagl/texture.h index 5c57948..98f7550 100644 --- a/opengl/libagl/texture.h +++ b/opengl/libagl/texture.h @@ -32,13 +32,9 @@ 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); -} - +void ogles_validate_texture(ogles_context_t* c); +void ogles_lock_textures(ogles_context_t* c); +void ogles_unlock_textures(ogles_context_t* c); }; // namespace android -- cgit v1.1