/* * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_OPENGLES_CONTEXT_H #define ANDROID_OPENGLES_CONTEXT_H #include <stdint.h> #include <stddef.h> #include <sys/types.h> #include <pthread.h> #ifdef HAVE_ANDROID_OS #include <bionic_tls.h> #endif #include <private/pixelflinger/ggl_context.h> #include <hardware/copybit.h> #include <hardware/gralloc.h> #include <GLES/gl.h> #include <GLES/glext.h> namespace android { const unsigned int OGLES_NUM_COMPRESSED_TEXTURE_FORMATS = 10; class EGLTextureObject; class EGLSurfaceManager; class EGLBufferObjectManager; namespace gl { struct ogles_context_t; struct matrixx_t; struct transform_t; struct buffer_t; ogles_context_t* getGlContext(); template<typename T> static inline void swap(T& a, T& b) { T t(a); a = b; b = t; } template<typename T> inline T max(T a, T b) { return a<b ? b : a; } template<typename T> inline T max(T a, T b, T c) { return max(a, max(b, c)); } template<typename T> inline T min(T a, T b) { return a<b ? a : b; } template<typename T> inline T min(T a, T b, T c) { return min(a, min(b, c)); } template<typename T> inline T min(T a, T b, T c, T d) { return min(min(a,b), min(c,d)); } // ---------------------------------------------------------------------------- // vertices // ---------------------------------------------------------------------------- struct vec3_t { union { struct { GLfixed x, y, z; }; struct { GLfixed r, g, b; }; struct { GLfixed S, T, R; }; GLfixed v[3]; }; }; struct vec4_t { union { struct { GLfixed x, y, z, w; }; struct { GLfixed r, g, b, a; }; struct { GLfixed S, T, R, Q; }; GLfixed v[4]; }; }; struct vertex_t { enum { // these constant matter for our clipping CLIP_L = 0x0001, // clipping flags CLIP_R = 0x0002, CLIP_B = 0x0004, CLIP_T = 0x0008, CLIP_N = 0x0010, CLIP_F = 0x0020, EYE = 0x0040, RESERVED = 0x0080, USER_CLIP_0 = 0x0100, // user clipping flags USER_CLIP_1 = 0x0200, USER_CLIP_2 = 0x0400, USER_CLIP_3 = 0x0800, USER_CLIP_4 = 0x1000, USER_CLIP_5 = 0x2000, LIT = 0x4000, // lighting has been applied TT = 0x8000, // texture coords transformed FRUSTUM_CLIP_ALL= 0x003F, USER_CLIP_ALL = 0x3F00, CLIP_ALL = 0x3F3F, }; // the fields below are arranged to minimize d-cache usage // we group together, by cache-line, the fields most likely to be used union { vec4_t obj; vec4_t eye; }; vec4_t clip; uint32_t flags; size_t index; // cache tag, and vertex index GLfixed fog; uint8_t locked; uint8_t mru; uint8_t reserved[2]; vec4_t window; vec4_t color; vec4_t texture[GGL_TEXTURE_UNIT_COUNT]; uint32_t reserved1[4]; inline void clear() { flags = index = locked = mru = 0; } }; struct point_size_t { GGLcoord size; GLboolean smooth; }; struct line_width_t { GGLcoord width; GLboolean smooth; }; struct polygon_offset_t { GLfixed factor; GLfixed units; GLboolean enable; }; // ---------------------------------------------------------------------------- // arrays // ---------------------------------------------------------------------------- struct array_t { typedef void (*fetcher_t)(ogles_context_t*, GLfixed*, const GLvoid*); fetcher_t fetch; GLvoid const* physical_pointer; GLint size; GLsizei stride; GLvoid const* pointer; buffer_t const* bo; uint16_t type; GLboolean enable; GLboolean pad; GLsizei bounds; void init(GLint, GLenum, GLsizei, const GLvoid *, const buffer_t*, GLsizei); inline void resolve(); inline const GLubyte* element(GLint i) const { return (const GLubyte*)physical_pointer + i * stride; } }; struct array_machine_t { array_t vertex; array_t normal; array_t color; array_t texture[GGL_TEXTURE_UNIT_COUNT]; uint8_t activeTexture; uint8_t tmu; uint16_t cull; uint32_t flags; GLenum indicesType; buffer_t const* array_buffer; buffer_t const* element_array_buffer; void (*compileElements)(ogles_context_t*, vertex_t*, GLint, GLsizei); void (*compileElement)(ogles_context_t*, vertex_t*, GLint); void (*mvp_transform)(transform_t const*, vec4_t*, vec4_t const*); void (*mv_transform)(transform_t const*, vec4_t*, vec4_t const*); void (*tex_transform[2])(transform_t const*, vec4_t*, vec4_t const*); void (*perspective)(ogles_context_t*c, vertex_t* v); void (*clipVertex)(ogles_context_t* c, vertex_t* nv, GGLfixed t, const vertex_t* s, const vertex_t* p); void (*clipEye)(ogles_context_t* c, vertex_t* nv, GGLfixed t, const vertex_t* s, const vertex_t* p); }; struct vertex_cache_t { enum { // must be at least 4 // 3 vertice for triangles // or 2 + 2 for indexed triangles w/ cache contention VERTEX_BUFFER_SIZE = 8, // must be a power of two and at least 3 VERTEX_CACHE_SIZE = 64, // 8 KB INDEX_BITS = 16, INDEX_MASK = ((1LU<<INDEX_BITS)-1), INDEX_SEQ = 1LU<<INDEX_BITS, }; vertex_t* vBuffer; vertex_t* vCache; uint32_t sequence; void* base; uint32_t total; uint32_t misses; int64_t startTime; void init(); void uninit(); void clear(); void dump_stats(GLenum mode); }; // ---------------------------------------------------------------------------- // fog // ---------------------------------------------------------------------------- struct fog_t { GLfixed density; GLfixed start; GLfixed end; GLfixed invEndMinusStart; GLenum mode; GLfixed (*fog)(ogles_context_t* c, GLfixed z); }; // ---------------------------------------------------------------------------- // user clip planes // ---------------------------------------------------------------------------- const unsigned int OGLES_MAX_CLIP_PLANES = 6; struct clip_plane_t { vec4_t equation; }; struct user_clip_planes_t { clip_plane_t plane[OGLES_MAX_CLIP_PLANES]; uint32_t enable; }; // ---------------------------------------------------------------------------- // lighting // ---------------------------------------------------------------------------- const unsigned int OGLES_MAX_LIGHTS = 8; struct light_t { vec4_t ambient; vec4_t diffuse; vec4_t specular; vec4_t implicitAmbient; vec4_t implicitDiffuse; vec4_t implicitSpecular; vec4_t position; // position in eye space vec4_t objPosition; vec4_t normalizedObjPosition; vec4_t spotDir; vec4_t normalizedSpotDir; GLfixed spotExp; GLfixed spotCutoff; GLfixed spotCutoffCosine; GLfixed attenuation[3]; GLfixed rConstAttenuation; GLboolean enable; }; struct material_t { vec4_t ambient; vec4_t diffuse; vec4_t specular; vec4_t emission; GLfixed shininess; }; struct light_model_t { vec4_t ambient; GLboolean twoSide; }; struct color_material_t { GLenum face; GLenum mode; GLboolean enable; }; struct lighting_t { light_t lights[OGLES_MAX_LIGHTS]; material_t front; light_model_t lightModel; color_material_t colorMaterial; uint32_t enabledLights; GLboolean enable; vec4_t implicitSceneEmissionAndAmbient; GLenum shadeModel; typedef void (*light_fct_t)(ogles_context_t*, vertex_t*); void (*lightVertex)(ogles_context_t* c, vertex_t* v); void (*lightTriangle)(ogles_context_t* c, vertex_t* v0, vertex_t* v1, vertex_t* v2); }; struct culling_t { GLenum cullFace; GLenum frontFace; GLboolean enable; }; // ---------------------------------------------------------------------------- // textures // ---------------------------------------------------------------------------- struct texture_unit_t { GLuint name; EGLTextureObject* texture; uint8_t dirty; }; struct texture_state_t { texture_unit_t tmu[GGL_TEXTURE_UNIT_COUNT]; int active; // active tmu EGLTextureObject* defaultTexture; GGLContext* ggl; uint8_t packAlignment; uint8_t unpackAlignment; }; // ---------------------------------------------------------------------------- // transformation and matrices // ---------------------------------------------------------------------------- struct matrixf_t; struct matrixx_t { GLfixed m[16]; void load(const matrixf_t& rhs); }; struct matrix_stack_t; struct matrixf_t { void loadIdentity(); void load(const matrixf_t& rhs); inline GLfloat* editElements() { return m; } inline GLfloat const* elements() const { return m; } void set(const GLfixed* rhs); void set(const GLfloat* rhs); static void multiply(matrixf_t& r, const matrixf_t& lhs, const matrixf_t& rhs); void dump(const char* what); private: friend struct matrix_stack_t; GLfloat m[16]; void load(const GLfixed* rhs); void load(const GLfloat* rhs); void multiply(const matrixf_t& rhs); void translate(GLfloat x, GLfloat y, GLfloat z); void scale(GLfloat x, GLfloat y, GLfloat z); void rotate(GLfloat a, GLfloat x, GLfloat y, GLfloat z); }; enum { OP_IDENTITY = 0x00, OP_TRANSLATE = 0x01, OP_UNIFORM_SCALE = 0x02, OP_SCALE = 0x05, OP_ROTATE = 0x08, OP_SKEW = 0x10, OP_ALL = 0x1F }; struct transform_t { enum { FLAGS_2D_PROJECTION = 0x1 }; matrixx_t matrix; uint32_t flags; uint32_t ops; union { struct { void (*point2)(transform_t const* t, vec4_t*, vec4_t const*); void (*point3)(transform_t const* t, vec4_t*, vec4_t const*); void (*point4)(transform_t const* t, vec4_t*, vec4_t const*); }; void (*pointv[3])(transform_t const* t, vec4_t*, vec4_t const*); }; void loadIdentity(); void picker(); void dump(const char* what); }; struct mvui_transform_t : public transform_t { void picker(); }; struct matrix_stack_t { enum { DO_PICKER = 0x1, DO_FLOAT_TO_FIXED = 0x2 }; transform_t transform; uint8_t maxDepth; uint8_t depth; uint8_t dirty; uint8_t reserved; matrixf_t *stack; uint8_t *ops; void init(int depth); void uninit(); void loadIdentity(); void load(const GLfixed* rhs); void load(const GLfloat* rhs); void multiply(const matrixf_t& rhs); void translate(GLfloat x, GLfloat y, GLfloat z); void scale(GLfloat x, GLfloat y, GLfloat z); void rotate(GLfloat a, GLfloat x, GLfloat y, GLfloat z); GLint push(); GLint pop(); void validate(); matrixf_t& top() { return stack[depth]; } const matrixf_t& top() const { return stack[depth]; } uint32_t top_ops() const { return ops[depth]; } inline bool isRigidBody() const { return !(ops[depth] & ~(OP_TRANSLATE|OP_UNIFORM_SCALE|OP_ROTATE)); } }; struct vp_transform_t { transform_t transform; matrixf_t matrix; GLfloat zNear; GLfloat zFar; void loadIdentity(); }; struct transform_state_t { enum { MODELVIEW = 0x01, PROJECTION = 0x02, VIEWPORT = 0x04, TEXTURE = 0x08, MVUI = 0x10, MVIT = 0x20, MVP = 0x40, }; matrix_stack_t *current; matrix_stack_t modelview; matrix_stack_t projection; matrix_stack_t texture[GGL_TEXTURE_UNIT_COUNT]; // modelview * projection transform_t mvp __attribute__((aligned(32))); // viewport transformation vp_transform_t vpt __attribute__((aligned(32))); // same for 4-D vertices transform_t mvp4; // full modelview inverse transpose transform_t mvit4; // upper 3x3 of mv-inverse-transpose (for normals) mvui_transform_t mvui; GLenum matrixMode; GLenum rescaleNormals; uint32_t dirty; void invalidate(); void update_mvp(); void update_mvit(); void update_mvui(); }; struct viewport_t { GLint x; GLint y; GLsizei w; GLsizei h; struct { GLint x; GLint y; } surfaceport; struct { GLint x; GLint y; GLsizei w; GLsizei h; } scissor; }; // ---------------------------------------------------------------------------- // Lerping // ---------------------------------------------------------------------------- struct compute_iterators_t { void initTriangle( vertex_t const* v0, vertex_t const* v1, vertex_t const* v2); void initLine( vertex_t const* v0, vertex_t const* v1); inline void initLerp(vertex_t const* v0, uint32_t enables); int iteratorsScale(int32_t it[3], int32_t c0, int32_t c1, int32_t c2) const; void iterators1616(GGLfixed it[3], GGLfixed c0, GGLfixed c1, GGLfixed c2) const; void iterators0032(int32_t it[3], int32_t c0, int32_t c1, int32_t c2) const; void iterators0032(int64_t it[3], int32_t c0, int32_t c1, int32_t c2) const; GGLcoord area() const { return m_area; } private: // don't change order of members here -- used by iterators.S GGLcoord m_dx01, m_dy10, m_dx20, m_dy02; GGLcoord m_x0, m_y0; GGLcoord m_area; uint8_t m_scale; uint8_t m_area_scale; uint8_t m_reserved[2]; }; // ---------------------------------------------------------------------------- // state // ---------------------------------------------------------------------------- #ifdef HAVE_ANDROID_OS // We have a dedicated TLS slot in bionic inline void setGlThreadSpecific(ogles_context_t *value) { ((uint32_t *)__get_tls())[TLS_SLOT_OPENGL] = (uint32_t)value; } inline ogles_context_t* getGlThreadSpecific() { return (ogles_context_t *)(((unsigned *)__get_tls())[TLS_SLOT_OPENGL]); } #else extern pthread_key_t gGLKey; inline void setGlThreadSpecific(ogles_context_t *value) { pthread_setspecific(gGLKey, value); } inline ogles_context_t* getGlThreadSpecific() { return static_cast<ogles_context_t*>(pthread_getspecific(gGLKey)); } #endif struct prims_t { typedef ogles_context_t* GL; void (*renderPoint)(GL, vertex_t*); void (*renderLine)(GL, vertex_t*, vertex_t*); void (*renderTriangle)(GL, vertex_t*, vertex_t*, vertex_t*); }; struct copybits_context_t { // A handle to the blit engine, if it exists, else NULL. copybit_device_t* blitEngine; int32_t minScale; int32_t maxScale; buffer_handle_t drawSurfaceBuffer; }; struct ogles_context_t { context_t rasterizer; array_machine_t arrays __attribute__((aligned(32))); texture_state_t textures; transform_state_t transforms; vertex_cache_t vc; prims_t prims; culling_t cull; lighting_t lighting; user_clip_planes_t clipPlanes; compute_iterators_t lerp; __attribute__((aligned(32))); vertex_t current; vec4_t currentColorClamped; vec3_t currentNormal; viewport_t viewport; point_size_t point; line_width_t line; polygon_offset_t polygonOffset; fog_t fog; uint32_t perspective : 1; uint32_t transformTextures : 1; EGLSurfaceManager* surfaceManager; EGLBufferObjectManager* bufferObjectManager; // copybits is only used if LIBAGL_USE_GRALLOC_COPYBITS is // defined, but it is always present because ogles_context_t is a public // struct that is used by clients of libagl. We want the size and offsets // to stay the same, whether or not LIBAGL_USE_GRALLOC_COPYBITS is defined. copybits_context_t copybits; GLenum error; static inline ogles_context_t* get() { return getGlThreadSpecific(); } }; }; // namespace gl }; // namespace android #endif // ANDROID_OPENGLES_CONTEXT_H