Home | History | Annotate | Download | only in libagl
      1 /* libs/opengles/texture.cpp
      2 **
      3 ** Copyright 2006, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 
     18 #include <stdio.h>
     19 #include <stdlib.h>
     20 #include "context.h"
     21 #include "fp.h"
     22 #include "state.h"
     23 #include "texture.h"
     24 #include "TextureObjectManager.h"
     25 
     26 #include <ETC1/etc1.h>
     27 
     28 #include <ui/GraphicBufferMapper.h>
     29 #include <ui/Rect.h>
     30 
     31 namespace android {
     32 
     33 // ----------------------------------------------------------------------------
     34 
     35 static void bindTextureTmu(
     36     ogles_context_t* c, int tmu, GLuint texture, const sp<EGLTextureObject>& tex);
     37 
     38 static __attribute__((noinline))
     39 void generateMipmap(ogles_context_t* c, GLint level);
     40 
     41 // ----------------------------------------------------------------------------
     42 
     43 #if 0
     44 #pragma mark -
     45 #pragma mark Init
     46 #endif
     47 
     48 void ogles_init_texture(ogles_context_t* c)
     49 {
     50     c->textures.packAlignment   = 4;
     51     c->textures.unpackAlignment = 4;
     52 
     53     // each context has a default named (0) texture (not shared)
     54     c->textures.defaultTexture = new EGLTextureObject();
     55     c->textures.defaultTexture->incStrong(c);
     56 
     57     // bind the default texture to each texture unit
     58     for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
     59         bindTextureTmu(c, i, 0, c->textures.defaultTexture);
     60         memset(c->current.texture[i].v, 0, sizeof(vec4_t));
     61         c->current.texture[i].Q = 0x10000;
     62     }
     63 }
     64 
     65 void ogles_uninit_texture(ogles_context_t* c)
     66 {
     67     if (c->textures.ggl)
     68         gglUninit(c->textures.ggl);
     69     c->textures.defaultTexture->decStrong(c);
     70     for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
     71         if (c->textures.tmu[i].texture)
     72             c->textures.tmu[i].texture->decStrong(c);
     73     }
     74 }
     75 
     76 static __attribute__((noinline))
     77 void validate_tmu(ogles_context_t* c, int i)
     78 {
     79     texture_unit_t& u(c->textures.tmu[i]);
     80     if (u.dirty) {
     81         u.dirty = 0;
     82         c->rasterizer.procs.activeTexture(c, i);
     83         c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
     84         c->rasterizer.procs.texGeni(c, GGL_S,
     85                 GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC);
     86         c->rasterizer.procs.texGeni(c, GGL_T,
     87                 GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC);
     88         c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
     89                 GGL_TEXTURE_WRAP_S, u.texture->wraps);
     90         c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
     91                 GGL_TEXTURE_WRAP_T, u.texture->wrapt);
     92         c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
     93                 GGL_TEXTURE_MIN_FILTER, u.texture->min_filter);
     94         c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
     95                 GGL_TEXTURE_MAG_FILTER, u.texture->mag_filter);
     96 
     97         // disable this texture unit if it's not complete
     98         if (!u.texture->isComplete()) {
     99             c->rasterizer.procs.disable(c, GGL_TEXTURE_2D);
    100         }
    101     }
    102 }
    103 
    104 void ogles_validate_texture(ogles_context_t* c)
    105 {
    106     for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
    107         if (c->rasterizer.state.texture[i].enable)
    108             validate_tmu(c, i);
    109     }
    110     c->rasterizer.procs.activeTexture(c, c->textures.active);
    111 }
    112 
    113 static
    114 void invalidate_texture(ogles_context_t* c, int tmu, uint8_t flags = 0xFF) {
    115     c->textures.tmu[tmu].dirty = flags;
    116 }
    117 
    118 /*
    119  * If the active textures are EGLImage, they need to be locked before
    120  * they can be used.
    121  *
    122  * FIXME: code below is far from being optimal
    123  *
    124  */
    125 
    126 void ogles_lock_textures(ogles_context_t* c)
    127 {
    128     for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
    129         if (c->rasterizer.state.texture[i].enable) {
    130             texture_unit_t& u(c->textures.tmu[i]);
    131             ANativeWindowBuffer* native_buffer = u.texture->buffer;
    132             if (native_buffer) {
    133                 c->rasterizer.procs.activeTexture(c, i);
    134 
    135                 auto& mapper = GraphicBufferMapper::get();
    136                 void* vaddr;
    137                 mapper.lock(native_buffer->handle, GRALLOC_USAGE_SW_READ_OFTEN,
    138                         Rect(native_buffer->width, native_buffer->height),
    139                         &vaddr);
    140 
    141                 u.texture->setImageBits(vaddr);
    142                 c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
    143             }
    144         }
    145     }
    146 }
    147 
    148 void ogles_unlock_textures(ogles_context_t* c)
    149 {
    150     for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
    151         if (c->rasterizer.state.texture[i].enable) {
    152             texture_unit_t& u(c->textures.tmu[i]);
    153             ANativeWindowBuffer* native_buffer = u.texture->buffer;
    154             if (native_buffer) {
    155                 c->rasterizer.procs.activeTexture(c, i);
    156 
    157                 auto& mapper = GraphicBufferMapper::get();
    158                 mapper.unlock(native_buffer->handle);
    159 
    160                 u.texture->setImageBits(NULL);
    161                 c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
    162             }
    163         }
    164     }
    165     c->rasterizer.procs.activeTexture(c, c->textures.active);
    166 }
    167 
    168 // ----------------------------------------------------------------------------
    169 #if 0
    170 #pragma mark -
    171 #pragma mark Format conversion
    172 #endif
    173 
    174 static uint32_t gl2format_table[6][4] = {
    175     // BYTE, 565, 4444, 5551
    176     { GGL_PIXEL_FORMAT_A_8,
    177       0, 0, 0 },                        // GL_ALPHA
    178     { GGL_PIXEL_FORMAT_RGB_888,
    179       GGL_PIXEL_FORMAT_RGB_565,
    180       0, 0 },                           // GL_RGB
    181     { GGL_PIXEL_FORMAT_RGBA_8888,
    182       0,
    183       GGL_PIXEL_FORMAT_RGBA_4444,
    184       GGL_PIXEL_FORMAT_RGBA_5551 },     // GL_RGBA
    185     { GGL_PIXEL_FORMAT_L_8,
    186       0, 0, 0 },                        // GL_LUMINANCE
    187     { GGL_PIXEL_FORMAT_LA_88,
    188       0, 0, 0 },                        // GL_LUMINANCE_ALPHA
    189 };
    190 
    191 static int32_t convertGLPixelFormat(GLint format, GLenum type)
    192 {
    193     int32_t fi = -1;
    194     int32_t ti = -1;
    195     switch (format) {
    196     case GL_ALPHA:              fi = 0;     break;
    197     case GL_RGB:                fi = 1;     break;
    198     case GL_RGBA:               fi = 2;     break;
    199     case GL_LUMINANCE:          fi = 3;     break;
    200     case GL_LUMINANCE_ALPHA:    fi = 4;     break;
    201     }
    202     switch (type) {
    203     case GL_UNSIGNED_BYTE:          ti = 0; break;
    204     case GL_UNSIGNED_SHORT_5_6_5:   ti = 1; break;
    205     case GL_UNSIGNED_SHORT_4_4_4_4: ti = 2; break;
    206     case GL_UNSIGNED_SHORT_5_5_5_1: ti = 3; break;
    207     }
    208     if (fi==-1 || ti==-1)
    209         return 0;
    210     return gl2format_table[fi][ti];
    211 }
    212 
    213 // ----------------------------------------------------------------------------
    214 
    215 static GLenum validFormatType(ogles_context_t* c, GLenum format, GLenum type)
    216 {
    217     GLenum error = 0;
    218     if (format<GL_ALPHA || format>GL_LUMINANCE_ALPHA) {
    219         error = GL_INVALID_ENUM;
    220     }
    221     if (type != GL_UNSIGNED_BYTE && type != GL_UNSIGNED_SHORT_4_4_4_4 &&
    222         type != GL_UNSIGNED_SHORT_5_5_5_1 && type != GL_UNSIGNED_SHORT_5_6_5) {
    223         error = GL_INVALID_ENUM;
    224     }
    225     if (type == GL_UNSIGNED_SHORT_5_6_5 && format != GL_RGB) {
    226         error = GL_INVALID_OPERATION;
    227     }
    228     if ((type == GL_UNSIGNED_SHORT_4_4_4_4 ||
    229          type == GL_UNSIGNED_SHORT_5_5_5_1)  && format != GL_RGBA) {
    230         error = GL_INVALID_OPERATION;
    231     }
    232     if (error) {
    233         ogles_error(c, error);
    234     }
    235     return error;
    236 }
    237 
    238 // ----------------------------------------------------------------------------
    239 
    240 GGLContext* getRasterizer(ogles_context_t* c)
    241 {
    242     GGLContext* ggl = c->textures.ggl;
    243     if (ggl_unlikely(!ggl)) {
    244         // this is quite heavy the first time...
    245         gglInit(&ggl);
    246         if (!ggl) {
    247             return 0;
    248         }
    249         GGLfixed colors[4] = { 0, 0, 0, 0x10000 };
    250         c->textures.ggl = ggl;
    251         ggl->activeTexture(ggl, 0);
    252         ggl->enable(ggl, GGL_TEXTURE_2D);
    253         ggl->texEnvi(ggl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
    254         ggl->disable(ggl, GGL_DITHER);
    255         ggl->shadeModel(ggl, GGL_FLAT);
    256         ggl->color4xv(ggl, colors);
    257     }
    258     return ggl;
    259 }
    260 
    261 static __attribute__((noinline))
    262 int copyPixels(
    263         ogles_context_t* c,
    264         const GGLSurface& dst,
    265         GLint xoffset, GLint yoffset,
    266         const GGLSurface& src,
    267         GLint x, GLint y, GLsizei w, GLsizei h)
    268 {
    269     if ((dst.format == src.format) &&
    270         (dst.stride == src.stride) &&
    271         (dst.width == src.width) &&
    272         (dst.height == src.height) &&
    273         (dst.stride > 0) &&
    274         ((x|y) == 0) &&
    275         ((xoffset|yoffset) == 0))
    276     {
    277         // this is a common case...
    278         const GGLFormat& pixelFormat(c->rasterizer.formats[src.format]);
    279         const size_t size = src.height * src.stride * pixelFormat.size;
    280         memcpy(dst.data, src.data, size);
    281         return 0;
    282     }
    283 
    284     // use pixel-flinger to handle all the conversions
    285     GGLContext* ggl = getRasterizer(c);
    286     if (!ggl) {
    287         // the only reason this would fail is because we ran out of memory
    288         return GL_OUT_OF_MEMORY;
    289     }
    290 
    291     ggl->colorBuffer(ggl, &dst);
    292     ggl->bindTexture(ggl, &src);
    293     ggl->texCoord2i(ggl, x-xoffset, y-yoffset);
    294     ggl->recti(ggl, xoffset, yoffset, xoffset+w, yoffset+h);
    295     return 0;
    296 }
    297 
    298 // ----------------------------------------------------------------------------
    299 
    300 static __attribute__((noinline))
    301 sp<EGLTextureObject> getAndBindActiveTextureObject(ogles_context_t* c)
    302 {
    303     sp<EGLTextureObject> tex;
    304     const int active = c->textures.active;
    305     const GLuint name = c->textures.tmu[active].name;
    306 
    307     // free the reference to the previously bound object
    308     texture_unit_t& u(c->textures.tmu[active]);
    309     if (u.texture)
    310         u.texture->decStrong(c);
    311 
    312     if (name == 0) {
    313         // 0 is our local texture object, not shared with anyone.
    314         // But it affects all bound TMUs immediately.
    315         // (we need to invalidate all units bound to this texture object)
    316         tex = c->textures.defaultTexture;
    317         for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
    318             if (c->textures.tmu[i].texture == tex.get())
    319                 invalidate_texture(c, i);
    320         }
    321     } else {
    322         // get a new texture object for that name
    323         tex = c->surfaceManager->replaceTexture(name);
    324     }
    325 
    326     // bind this texture to the current active texture unit
    327     // and add a reference to this texture object
    328     u.texture = tex.get();
    329     u.texture->incStrong(c);
    330     u.name = name;
    331     invalidate_texture(c, active);
    332     return tex;
    333 }
    334 
    335 void bindTextureTmu(
    336     ogles_context_t* c, int tmu, GLuint texture, const sp<EGLTextureObject>& tex)
    337 {
    338     if (tex.get() == c->textures.tmu[tmu].texture)
    339         return;
    340 
    341     // free the reference to the previously bound object
    342     texture_unit_t& u(c->textures.tmu[tmu]);
    343     if (u.texture)
    344         u.texture->decStrong(c);
    345 
    346     // bind this texture to the current active texture unit
    347     // and add a reference to this texture object
    348     u.texture = tex.get();
    349     u.texture->incStrong(c);
    350     u.name = texture;
    351     invalidate_texture(c, tmu);
    352 }
    353 
    354 int createTextureSurface(ogles_context_t* c,
    355         GGLSurface** outSurface, int32_t* outSize, GLint level,
    356         GLenum format, GLenum type, GLsizei width, GLsizei height,
    357         GLenum compressedFormat = 0)
    358 {
    359     // convert the pixelformat to one we can handle
    360     const int32_t formatIdx = convertGLPixelFormat(format, type);
    361     if (formatIdx == 0) { // we don't know what to do with this
    362         return GL_INVALID_OPERATION;
    363     }
    364 
    365     // figure out the size we need as well as the stride
    366     const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
    367     const int32_t align = c->textures.unpackAlignment-1;
    368     const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
    369     const size_t size = bpr * height;
    370     const int32_t stride = bpr / pixelFormat.size;
    371 
    372     if (level > 0) {
    373         const int active = c->textures.active;
    374         EGLTextureObject* tex = c->textures.tmu[active].texture;
    375         status_t err = tex->reallocate(level,
    376                 width, height, stride, formatIdx, compressedFormat, bpr);
    377         if (err != NO_ERROR)
    378             return GL_OUT_OF_MEMORY;
    379         GGLSurface& surface = tex->editMip(level);
    380         *outSurface = &surface;
    381         *outSize = size;
    382         return 0;
    383     }
    384 
    385     sp<EGLTextureObject> tex = getAndBindActiveTextureObject(c);
    386     status_t err = tex->reallocate(level,
    387             width, height, stride, formatIdx, compressedFormat, bpr);
    388     if (err != NO_ERROR)
    389         return GL_OUT_OF_MEMORY;
    390 
    391     tex->internalformat = format;
    392     *outSurface = &tex->surface;
    393     *outSize = size;
    394     return 0;
    395 }
    396 
    397 static GLsizei dataSizePalette4(int numLevels, int width, int height, int format)
    398 {
    399     int indexBits = 8;
    400     int entrySize = 0;
    401     switch (format) {
    402     case GL_PALETTE4_RGB8_OES:
    403         indexBits = 4;
    404         /* FALLTHROUGH */
    405     case GL_PALETTE8_RGB8_OES:
    406         entrySize = 3;
    407         break;
    408 
    409     case GL_PALETTE4_RGBA8_OES:
    410         indexBits = 4;
    411         /* FALLTHROUGH */
    412     case GL_PALETTE8_RGBA8_OES:
    413         entrySize = 4;
    414         break;
    415 
    416     case GL_PALETTE4_R5_G6_B5_OES:
    417     case GL_PALETTE4_RGBA4_OES:
    418     case GL_PALETTE4_RGB5_A1_OES:
    419         indexBits = 4;
    420         /* FALLTHROUGH */
    421     case GL_PALETTE8_R5_G6_B5_OES:
    422     case GL_PALETTE8_RGBA4_OES:
    423     case GL_PALETTE8_RGB5_A1_OES:
    424         entrySize = 2;
    425         break;
    426     }
    427 
    428     size_t size = (1 << indexBits) * entrySize; // palette size
    429 
    430     for (int i=0 ; i< numLevels ; i++) {
    431         int w = (width  >> i) ? : 1;
    432         int h = (height >> i) ? : 1;
    433         int levelSize = h * ((w * indexBits) / 8) ? : 1;
    434         size += levelSize;
    435     }
    436 
    437     return size;
    438 }
    439 
    440 static void decodePalette4(const GLvoid *data, int level, int width, int height,
    441                            void *surface, int stride, int format)
    442 
    443 {
    444     int indexBits = 8;
    445     int entrySize = 0;
    446     switch (format) {
    447     case GL_PALETTE4_RGB8_OES:
    448         indexBits = 4;
    449         /* FALLTHROUGH */
    450     case GL_PALETTE8_RGB8_OES:
    451         entrySize = 3;
    452         break;
    453 
    454     case GL_PALETTE4_RGBA8_OES:
    455         indexBits = 4;
    456         /* FALLTHROUGH */
    457     case GL_PALETTE8_RGBA8_OES:
    458         entrySize = 4;
    459         break;
    460 
    461     case GL_PALETTE4_R5_G6_B5_OES:
    462     case GL_PALETTE4_RGBA4_OES:
    463     case GL_PALETTE4_RGB5_A1_OES:
    464         indexBits = 4;
    465         /* FALLTHROUGH */
    466     case GL_PALETTE8_R5_G6_B5_OES:
    467     case GL_PALETTE8_RGBA4_OES:
    468     case GL_PALETTE8_RGB5_A1_OES:
    469         entrySize = 2;
    470         break;
    471     }
    472 
    473     const int paletteSize = (1 << indexBits) * entrySize;
    474 
    475     uint8_t const* pixels = (uint8_t *)data + paletteSize;
    476     for (int i=0 ; i<level ; i++) {
    477         int w = (width  >> i) ? : 1;
    478         int h = (height >> i) ? : 1;
    479         pixels += h * ((w * indexBits) / 8);
    480     }
    481     width  = (width  >> level) ? : 1;
    482     height = (height >> level) ? : 1;
    483 
    484     if (entrySize == 2) {
    485         uint8_t const* const palette = (uint8_t*)data;
    486         for (int y=0 ; y<height ; y++) {
    487             uint8_t* p = (uint8_t*)surface + y*stride*2;
    488             if (indexBits == 8) {
    489                 for (int x=0 ; x<width ; x++) {
    490                     int index = 2 * (*pixels++);
    491                     *p++ = palette[index + 0];
    492                     *p++ = palette[index + 1];
    493                 }
    494             } else {
    495                 for (int x=0 ; x<width ; x+=2) {
    496                     int v = *pixels++;
    497                     int index = 2 * (v >> 4);
    498                     *p++ = palette[index + 0];
    499                     *p++ = palette[index + 1];
    500                     if (x+1 < width) {
    501                         index = 2 * (v & 0xF);
    502                         *p++ = palette[index + 0];
    503                         *p++ = palette[index + 1];
    504                     }
    505                 }
    506             }
    507         }
    508     } else if (entrySize == 3) {
    509         uint8_t const* const palette = (uint8_t*)data;
    510         for (int y=0 ; y<height ; y++) {
    511             uint8_t* p = (uint8_t*)surface + y*stride*3;
    512             if (indexBits == 8) {
    513                 for (int x=0 ; x<width ; x++) {
    514                     int index = 3 * (*pixels++);
    515                     *p++ = palette[index + 0];
    516                     *p++ = palette[index + 1];
    517                     *p++ = palette[index + 2];
    518                 }
    519             } else {
    520                 for (int x=0 ; x<width ; x+=2) {
    521                     int v = *pixels++;
    522                     int index = 3 * (v >> 4);
    523                     *p++ = palette[index + 0];
    524                     *p++ = palette[index + 1];
    525                     *p++ = palette[index + 2];
    526                     if (x+1 < width) {
    527                         index = 3 * (v & 0xF);
    528                         *p++ = palette[index + 0];
    529                         *p++ = palette[index + 1];
    530                         *p++ = palette[index + 2];
    531                     }
    532                 }
    533             }
    534         }
    535     } else if (entrySize == 4) {
    536         uint8_t const* const palette = (uint8_t*)data;
    537         for (int y=0 ; y<height ; y++) {
    538             uint8_t* p = (uint8_t*)surface + y*stride*4;
    539             if (indexBits == 8) {
    540                 for (int x=0 ; x<width ; x++) {
    541                     int index = 4 * (*pixels++);
    542                     *p++ = palette[index + 0];
    543                     *p++ = palette[index + 1];
    544                     *p++ = palette[index + 2];
    545                     *p++ = palette[index + 3];
    546                 }
    547             } else {
    548                 for (int x=0 ; x<width ; x+=2) {
    549                     int v = *pixels++;
    550                     int index = 4 * (v >> 4);
    551                     *p++ = palette[index + 0];
    552                     *p++ = palette[index + 1];
    553                     *p++ = palette[index + 2];
    554                     *p++ = palette[index + 3];
    555                     if (x+1 < width) {
    556                         index = 4 * (v & 0xF);
    557                         *p++ = palette[index + 0];
    558                         *p++ = palette[index + 1];
    559                         *p++ = palette[index + 2];
    560                         *p++ = palette[index + 3];
    561                     }
    562                 }
    563             }
    564         }
    565     }
    566 }
    567 
    568 
    569 
    570 static __attribute__((noinline))
    571 void set_depth_and_fog(ogles_context_t* c, GGLfixed z)
    572 {
    573     const uint32_t enables = c->rasterizer.state.enables;
    574     // we need to compute Zw
    575     int32_t iterators[3];
    576     iterators[1] = iterators[2] = 0;
    577     GGLfixed Zw;
    578     GGLfixed n = gglFloatToFixed(c->transforms.vpt.zNear);
    579     GGLfixed f = gglFloatToFixed(c->transforms.vpt.zFar);
    580     if (z<=0)               Zw = n;
    581     else if (z>=0x10000)    Zw = f;
    582     else            Zw = gglMulAddx(z, (f-n), n);
    583     if (enables & GGL_ENABLE_FOG) {
    584         // set up fog if needed...
    585         iterators[0] = c->fog.fog(c, Zw);
    586         c->rasterizer.procs.fogGrad3xv(c, iterators);
    587     }
    588     if (enables & GGL_ENABLE_DEPTH_TEST) {
    589         // set up z-test if needed...
    590         int32_t z = (Zw & ~(Zw>>31));
    591         if (z >= 0x10000)
    592             z = 0xFFFF;
    593         iterators[0] = (z << 16) | z;
    594         c->rasterizer.procs.zGrad3xv(c, iterators);
    595     }
    596 }
    597 
    598 // ----------------------------------------------------------------------------
    599 #if 0
    600 #pragma mark -
    601 #pragma mark Generate mimaps
    602 #endif
    603 
    604 extern status_t buildAPyramid(ogles_context_t* c, EGLTextureObject* tex);
    605 
    606 void generateMipmap(ogles_context_t* c, GLint level)
    607 {
    608     if (level == 0) {
    609         const int active = c->textures.active;
    610         EGLTextureObject* tex = c->textures.tmu[active].texture;
    611         if (tex->generate_mipmap) {
    612             if (buildAPyramid(c, tex) != NO_ERROR) {
    613                 ogles_error(c, GL_OUT_OF_MEMORY);
    614                 return;
    615             }
    616         }
    617     }
    618 }
    619 
    620 
    621 static void texParameterx(
    622         GLenum target, GLenum pname, GLfixed param, ogles_context_t* c)
    623 {
    624     if (target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES) {
    625         ogles_error(c, GL_INVALID_ENUM);
    626         return;
    627     }
    628 
    629     EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture;
    630     switch (pname) {
    631     case GL_TEXTURE_WRAP_S:
    632         if ((param == GL_REPEAT) ||
    633             (param == GL_CLAMP_TO_EDGE)) {
    634             textureObject->wraps = param;
    635         } else {
    636             goto invalid_enum;
    637         }
    638         break;
    639     case GL_TEXTURE_WRAP_T:
    640         if ((param == GL_REPEAT) ||
    641             (param == GL_CLAMP_TO_EDGE)) {
    642             textureObject->wrapt = param;
    643         } else {
    644             goto invalid_enum;
    645         }
    646         break;
    647     case GL_TEXTURE_MIN_FILTER:
    648         if ((param == GL_NEAREST) ||
    649             (param == GL_LINEAR) ||
    650             (param == GL_NEAREST_MIPMAP_NEAREST) ||
    651             (param == GL_LINEAR_MIPMAP_NEAREST) ||
    652             (param == GL_NEAREST_MIPMAP_LINEAR) ||
    653             (param == GL_LINEAR_MIPMAP_LINEAR)) {
    654             textureObject->min_filter = param;
    655         } else {
    656             goto invalid_enum;
    657         }
    658         break;
    659     case GL_TEXTURE_MAG_FILTER:
    660         if ((param == GL_NEAREST) ||
    661             (param == GL_LINEAR)) {
    662             textureObject->mag_filter = param;
    663         } else {
    664             goto invalid_enum;
    665         }
    666         break;
    667     case GL_GENERATE_MIPMAP:
    668         textureObject->generate_mipmap = param;
    669         break;
    670     default:
    671 invalid_enum:
    672         ogles_error(c, GL_INVALID_ENUM);
    673         return;
    674     }
    675     invalidate_texture(c, c->textures.active);
    676 }
    677 
    678 
    679 
    680 static void drawTexxOESImp(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
    681         ogles_context_t* c)
    682 {
    683     ogles_lock_textures(c);
    684 
    685     const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
    686     y = gglIntToFixed(cbSurface.height) - (y + h);
    687     w >>= FIXED_BITS;
    688     h >>= FIXED_BITS;
    689 
    690     // set up all texture units
    691     for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
    692         if (!c->rasterizer.state.texture[i].enable)
    693             continue;
    694 
    695         int32_t texcoords[8];
    696         texture_unit_t& u(c->textures.tmu[i]);
    697 
    698         // validate this tmu (bind, wrap, filter)
    699         validate_tmu(c, i);
    700         // we CLAMP here, which works with premultiplied (s,t)
    701         c->rasterizer.procs.texParameteri(c,
    702                 GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_S, GGL_CLAMP);
    703         c->rasterizer.procs.texParameteri(c,
    704                 GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_T, GGL_CLAMP);
    705         u.dirty = 0xFF; // XXX: should be more subtle
    706 
    707         EGLTextureObject* textureObject = u.texture;
    708         const GLint Ucr = textureObject->crop_rect[0] << 16;
    709         const GLint Vcr = textureObject->crop_rect[1] << 16;
    710         const GLint Wcr = textureObject->crop_rect[2] << 16;
    711         const GLint Hcr = textureObject->crop_rect[3] << 16;
    712 
    713         // computes texture coordinates (pre-multiplied)
    714         int32_t dsdx = Wcr / w;   // dsdx =  ((Wcr/w)/Wt)*Wt
    715         int32_t dtdy =-Hcr / h;   // dtdy = -((Hcr/h)/Ht)*Ht
    716         int32_t s0   = Ucr       - gglMulx(dsdx, x); // s0 = Ucr - x * dsdx
    717         int32_t t0   = (Vcr+Hcr) - gglMulx(dtdy, y); // t0 = (Vcr+Hcr) - y*dtdy
    718         texcoords[0] = s0;
    719         texcoords[1] = dsdx;
    720         texcoords[2] = 0;
    721         texcoords[3] = t0;
    722         texcoords[4] = 0;
    723         texcoords[5] = dtdy;
    724         texcoords[6] = 0;
    725         texcoords[7] = 0;
    726         c->rasterizer.procs.texCoordGradScale8xv(c, i, texcoords);
    727     }
    728 
    729     const uint32_t enables = c->rasterizer.state.enables;
    730     if (ggl_unlikely(enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)))
    731         set_depth_and_fog(c, z);
    732 
    733     c->rasterizer.procs.activeTexture(c, c->textures.active);
    734     c->rasterizer.procs.color4xv(c, c->currentColorClamped.v);
    735     c->rasterizer.procs.disable(c, GGL_W_LERP);
    736     c->rasterizer.procs.disable(c, GGL_AA);
    737     c->rasterizer.procs.shadeModel(c, GL_FLAT);
    738     c->rasterizer.procs.recti(c,
    739             gglFixedToIntRound(x),
    740             gglFixedToIntRound(y),
    741             gglFixedToIntRound(x)+w,
    742             gglFixedToIntRound(y)+h);
    743 
    744     ogles_unlock_textures(c);
    745 }
    746 
    747 static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
    748         ogles_context_t* c)
    749 {
    750     // quickly reject empty rects
    751     if ((w|h) <= 0)
    752         return;
    753 
    754     drawTexxOESImp(x, y, z, w, h, c);
    755 }
    756 
    757 static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_context_t* c)
    758 {
    759     // All coordinates are integer, so if we have only one
    760     // texture unit active and no scaling is required
    761     // THEN, we can use our special 1:1 mapping
    762     // which is a lot faster.
    763 
    764     if (ggl_likely(c->rasterizer.state.enabled_tmu == 1)) {
    765         const int tmu = 0;
    766         texture_unit_t& u(c->textures.tmu[tmu]);
    767         EGLTextureObject* textureObject = u.texture;
    768         const GLint Wcr = textureObject->crop_rect[2];
    769         const GLint Hcr = textureObject->crop_rect[3];
    770 
    771         if ((w == Wcr) && (h == -Hcr)) {
    772             if ((w|h) <= 0) return; // quickly reject empty rects
    773 
    774             if (u.dirty) {
    775                 c->rasterizer.procs.activeTexture(c, tmu);
    776                 c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
    777                 c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
    778                         GGL_TEXTURE_MIN_FILTER, u.texture->min_filter);
    779                 c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
    780                         GGL_TEXTURE_MAG_FILTER, u.texture->mag_filter);
    781             }
    782             c->rasterizer.procs.texGeni(c, GGL_S,
    783                     GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
    784             c->rasterizer.procs.texGeni(c, GGL_T,
    785                     GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
    786             u.dirty = 0xFF; // XXX: should be more subtle
    787             c->rasterizer.procs.activeTexture(c, c->textures.active);
    788 
    789             const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
    790             y = cbSurface.height - (y + h);
    791             const GLint Ucr = textureObject->crop_rect[0];
    792             const GLint Vcr = textureObject->crop_rect[1];
    793             const GLint s0  = Ucr - x;
    794             const GLint t0  = (Vcr + Hcr) - y;
    795 
    796             const GLuint tw = textureObject->surface.width;
    797             const GLuint th = textureObject->surface.height;
    798             if ((uint32_t(s0+x+w) > tw) || (uint32_t(t0+y+h) > th)) {
    799                 // The GL spec is unclear about what should happen
    800                 // in this case, so we just use the slow case, which
    801                 // at least won't crash
    802                 goto slow_case;
    803             }
    804 
    805             ogles_lock_textures(c);
    806 
    807             c->rasterizer.procs.texCoord2i(c, s0, t0);
    808             const uint32_t enables = c->rasterizer.state.enables;
    809             if (ggl_unlikely(enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)))
    810                 set_depth_and_fog(c, gglIntToFixed(z));
    811 
    812             c->rasterizer.procs.color4xv(c, c->currentColorClamped.v);
    813             c->rasterizer.procs.disable(c, GGL_W_LERP);
    814             c->rasterizer.procs.disable(c, GGL_AA);
    815             c->rasterizer.procs.shadeModel(c, GL_FLAT);
    816             c->rasterizer.procs.recti(c, x, y, x+w, y+h);
    817 
    818             ogles_unlock_textures(c);
    819 
    820             return;
    821         }
    822     }
    823 
    824 slow_case:
    825     drawTexxOESImp(
    826             gglIntToFixed(x), gglIntToFixed(y), gglIntToFixed(z),
    827             gglIntToFixed(w), gglIntToFixed(h),
    828             c);
    829 }
    830 
    831 
    832 }; // namespace android
    833 // ----------------------------------------------------------------------------
    834 
    835 using namespace android;
    836 
    837 
    838 #if 0
    839 #pragma mark -
    840 #pragma mark Texture API
    841 #endif
    842 
    843 void glActiveTexture(GLenum texture)
    844 {
    845     ogles_context_t* c = ogles_context_t::get();
    846     if (uint32_t(texture-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) {
    847         ogles_error(c, GL_INVALID_ENUM);
    848         return;
    849     }
    850     c->textures.active = texture - GL_TEXTURE0;
    851     c->rasterizer.procs.activeTexture(c, c->textures.active);
    852 }
    853 
    854 void glBindTexture(GLenum target, GLuint texture)
    855 {
    856     ogles_context_t* c = ogles_context_t::get();
    857     if (target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES) {
    858         ogles_error(c, GL_INVALID_ENUM);
    859         return;
    860     }
    861 
    862     // Bind or create a texture
    863     sp<EGLTextureObject> tex;
    864     if (texture == 0) {
    865         // 0 is our local texture object
    866         tex = c->textures.defaultTexture;
    867     } else {
    868         tex = c->surfaceManager->texture(texture);
    869         if (ggl_unlikely(tex == 0)) {
    870             tex = c->surfaceManager->createTexture(texture);
    871             if (tex == 0) {
    872                 ogles_error(c, GL_OUT_OF_MEMORY);
    873                 return;
    874             }
    875         }
    876     }
    877     bindTextureTmu(c, c->textures.active, texture, tex);
    878 }
    879 
    880 void glGenTextures(GLsizei n, GLuint *textures)
    881 {
    882     ogles_context_t* c = ogles_context_t::get();
    883     if (n<0) {
    884         ogles_error(c, GL_INVALID_VALUE);
    885         return;
    886     }
    887     // generate unique (shared) texture names
    888     c->surfaceManager->getToken(n, textures);
    889 }
    890 
    891 void glDeleteTextures(GLsizei n, const GLuint *textures)
    892 {
    893     ogles_context_t* c = ogles_context_t::get();
    894     if (n<0) {
    895         ogles_error(c, GL_INVALID_VALUE);
    896         return;
    897     }
    898 
    899     // If deleting a bound texture, bind this unit to 0
    900     for (int t=0 ; t<GGL_TEXTURE_UNIT_COUNT ; t++) {
    901         if (c->textures.tmu[t].name == 0)
    902             continue;
    903         for (int i=0 ; i<n ; i++) {
    904             if (textures[i] && (textures[i] == c->textures.tmu[t].name)) {
    905                 // bind this tmu to texture 0
    906                 sp<EGLTextureObject> tex(c->textures.defaultTexture);
    907                 bindTextureTmu(c, t, 0, tex);
    908             }
    909         }
    910     }
    911     c->surfaceManager->deleteTextures(n, textures);
    912     c->surfaceManager->recycleTokens(n, textures);
    913 }
    914 
    915 void glMultiTexCoord4f(
    916         GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
    917 {
    918     ogles_context_t* c = ogles_context_t::get();
    919     if (uint32_t(target-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) {
    920         ogles_error(c, GL_INVALID_ENUM);
    921         return;
    922     }
    923     const int tmu = target-GL_TEXTURE0;
    924     c->current.texture[tmu].S = gglFloatToFixed(s);
    925     c->current.texture[tmu].T = gglFloatToFixed(t);
    926     c->current.texture[tmu].R = gglFloatToFixed(r);
    927     c->current.texture[tmu].Q = gglFloatToFixed(q);
    928 }
    929 
    930 void glMultiTexCoord4x(
    931         GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q)
    932 {
    933     ogles_context_t* c = ogles_context_t::get();
    934     if (uint32_t(target-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) {
    935         ogles_error(c, GL_INVALID_ENUM);
    936         return;
    937     }
    938     const int tmu = target-GL_TEXTURE0;
    939     c->current.texture[tmu].S = s;
    940     c->current.texture[tmu].T = t;
    941     c->current.texture[tmu].R = r;
    942     c->current.texture[tmu].Q = q;
    943 }
    944 
    945 void glPixelStorei(GLenum pname, GLint param)
    946 {
    947     ogles_context_t* c = ogles_context_t::get();
    948     if ((pname != GL_PACK_ALIGNMENT) && (pname != GL_UNPACK_ALIGNMENT)) {
    949         ogles_error(c, GL_INVALID_ENUM);
    950         return;
    951     }
    952     if ((param<=0 || param>8) || (param & (param-1))) {
    953         ogles_error(c, GL_INVALID_VALUE);
    954         return;
    955     }
    956     if (pname == GL_PACK_ALIGNMENT)
    957         c->textures.packAlignment = param;
    958     if (pname == GL_UNPACK_ALIGNMENT)
    959         c->textures.unpackAlignment = param;
    960 }
    961 
    962 void glTexEnvf(GLenum target, GLenum pname, GLfloat param)
    963 {
    964     ogles_context_t* c = ogles_context_t::get();
    965     c->rasterizer.procs.texEnvi(c, target, pname, GLint(param));
    966 }
    967 
    968 void glTexEnvfv(
    969         GLenum target, GLenum pname, const GLfloat *params)
    970 {
    971     ogles_context_t* c = ogles_context_t::get();
    972     if (pname == GL_TEXTURE_ENV_MODE) {
    973         c->rasterizer.procs.texEnvi(c, target, pname, GLint(*params));
    974         return;
    975     }
    976     if (pname == GL_TEXTURE_ENV_COLOR) {
    977         GGLfixed fixed[4];
    978         for (int i=0 ; i<4 ; i++)
    979             fixed[i] = gglFloatToFixed(params[i]);
    980         c->rasterizer.procs.texEnvxv(c, target, pname, fixed);
    981         return;
    982     }
    983     ogles_error(c, GL_INVALID_ENUM);
    984 }
    985 
    986 void glTexEnvx(GLenum target, GLenum pname, GLfixed param)
    987 {
    988     ogles_context_t* c = ogles_context_t::get();
    989     c->rasterizer.procs.texEnvi(c, target, pname, param);
    990 }
    991 
    992 void glTexEnvxv(
    993         GLenum target, GLenum pname, const GLfixed *params)
    994 {
    995     ogles_context_t* c = ogles_context_t::get();
    996     c->rasterizer.procs.texEnvxv(c, target, pname, params);
    997 }
    998 
    999 void glTexParameteriv(
   1000         GLenum target, GLenum pname, const GLint* params)
   1001 {
   1002     ogles_context_t* c = ogles_context_t::get();
   1003     if (target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES) {
   1004         ogles_error(c, GL_INVALID_ENUM);
   1005         return;
   1006     }
   1007 
   1008     EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture;
   1009     switch (pname) {
   1010     case GL_TEXTURE_CROP_RECT_OES:
   1011         memcpy(textureObject->crop_rect, params, 4*sizeof(GLint));
   1012         break;
   1013     default:
   1014         texParameterx(target, pname, GLfixed(params[0]), c);
   1015         return;
   1016     }
   1017 }
   1018 
   1019 void glTexParameterf(
   1020         GLenum target, GLenum pname, GLfloat param)
   1021 {
   1022     ogles_context_t* c = ogles_context_t::get();
   1023     texParameterx(target, pname, GLfixed(param), c);
   1024 }
   1025 
   1026 void glTexParameterx(
   1027         GLenum target, GLenum pname, GLfixed param)
   1028 {
   1029     ogles_context_t* c = ogles_context_t::get();
   1030     texParameterx(target, pname, param, c);
   1031 }
   1032 
   1033 void glTexParameteri(
   1034         GLenum target, GLenum pname, GLint param)
   1035 {
   1036     ogles_context_t* c = ogles_context_t::get();
   1037     texParameterx(target, pname, GLfixed(param), c);
   1038 }
   1039 
   1040 // ----------------------------------------------------------------------------
   1041 #if 0
   1042 #pragma mark -
   1043 #endif
   1044 
   1045 void glCompressedTexImage2D(
   1046         GLenum target, GLint level, GLenum internalformat,
   1047         GLsizei width, GLsizei height, GLint border,
   1048         GLsizei imageSize, const GLvoid *data)
   1049 {
   1050     ogles_context_t* c = ogles_context_t::get();
   1051     if (target != GL_TEXTURE_2D) {
   1052         ogles_error(c, GL_INVALID_ENUM);
   1053         return;
   1054     }
   1055     if (width<0 || height<0 || border!=0) {
   1056         ogles_error(c, GL_INVALID_VALUE);
   1057         return;
   1058     }
   1059 
   1060     // "uncompress" the texture since pixelflinger doesn't support
   1061     // any compressed texture format natively.
   1062     GLenum format;
   1063     GLenum type;
   1064     switch (internalformat) {
   1065     case GL_PALETTE8_RGB8_OES:
   1066     case GL_PALETTE4_RGB8_OES:
   1067         format      = GL_RGB;
   1068         type        = GL_UNSIGNED_BYTE;
   1069         break;
   1070     case GL_PALETTE8_RGBA8_OES:
   1071     case GL_PALETTE4_RGBA8_OES:
   1072         format      = GL_RGBA;
   1073         type        = GL_UNSIGNED_BYTE;
   1074         break;
   1075     case GL_PALETTE8_R5_G6_B5_OES:
   1076     case GL_PALETTE4_R5_G6_B5_OES:
   1077         format      = GL_RGB;
   1078         type        = GL_UNSIGNED_SHORT_5_6_5;
   1079         break;
   1080     case GL_PALETTE8_RGBA4_OES:
   1081     case GL_PALETTE4_RGBA4_OES:
   1082         format      = GL_RGBA;
   1083         type        = GL_UNSIGNED_SHORT_4_4_4_4;
   1084         break;
   1085     case GL_PALETTE8_RGB5_A1_OES:
   1086     case GL_PALETTE4_RGB5_A1_OES:
   1087         format      = GL_RGBA;
   1088         type        = GL_UNSIGNED_SHORT_5_5_5_1;
   1089         break;
   1090 #ifdef GL_OES_compressed_ETC1_RGB8_texture
   1091     case GL_ETC1_RGB8_OES:
   1092         format      = GL_RGB;
   1093         type        = GL_UNSIGNED_BYTE;
   1094         break;
   1095 #endif
   1096     default:
   1097         ogles_error(c, GL_INVALID_ENUM);
   1098         return;
   1099     }
   1100 
   1101     if (!data || !width || !height) {
   1102         // unclear if this is an error or not...
   1103         return;
   1104     }
   1105 
   1106     int32_t size;
   1107     GGLSurface* surface;
   1108 
   1109 #ifdef GL_OES_compressed_ETC1_RGB8_texture
   1110     if (internalformat == GL_ETC1_RGB8_OES) {
   1111         GLsizei compressedSize = etc1_get_encoded_data_size(width, height);
   1112         if (compressedSize > imageSize) {
   1113             ogles_error(c, GL_INVALID_VALUE);
   1114             return;
   1115         }
   1116         int error = createTextureSurface(c, &surface, &size,
   1117                 level, format, type, width, height);
   1118         if (error) {
   1119             ogles_error(c, error);
   1120             return;
   1121         }
   1122         if (etc1_decode_image(
   1123                 (const etc1_byte*)data,
   1124                 (etc1_byte*)surface->data,
   1125                 width, height, 3, surface->stride*3) != 0) {
   1126             ogles_error(c, GL_INVALID_OPERATION);
   1127         }
   1128         return;
   1129     }
   1130 #endif
   1131 
   1132     // all mipmap levels are specified at once.
   1133     const int numLevels = level<0 ? -level : 1;
   1134 
   1135     if (dataSizePalette4(numLevels, width, height, format) > imageSize) {
   1136         ogles_error(c, GL_INVALID_VALUE);
   1137         return;
   1138     }
   1139 
   1140     for (int i=0 ; i<numLevels ; i++) {
   1141         int lod_w = (width  >> i) ? : 1;
   1142         int lod_h = (height >> i) ? : 1;
   1143         int error = createTextureSurface(c, &surface, &size,
   1144                 i, format, type, lod_w, lod_h);
   1145         if (error) {
   1146             ogles_error(c, error);
   1147             return;
   1148         }
   1149         decodePalette4(data, i, width, height,
   1150                 surface->data, surface->stride, internalformat);
   1151     }
   1152 }
   1153 
   1154 
   1155 void glTexImage2D(
   1156         GLenum target, GLint level, GLint internalformat,
   1157         GLsizei width, GLsizei height, GLint border,
   1158         GLenum format, GLenum type, const GLvoid *pixels)
   1159 {
   1160     ogles_context_t* c = ogles_context_t::get();
   1161     if (target != GL_TEXTURE_2D) {
   1162         ogles_error(c, GL_INVALID_ENUM);
   1163         return;
   1164     }
   1165     if (width<0 || height<0 || border!=0 || level < 0) {
   1166         ogles_error(c, GL_INVALID_VALUE);
   1167         return;
   1168     }
   1169     if (format != (GLenum)internalformat) {
   1170         ogles_error(c, GL_INVALID_OPERATION);
   1171         return;
   1172     }
   1173     if (validFormatType(c, format, type)) {
   1174         return;
   1175     }
   1176 
   1177     int32_t size = 0;
   1178     GGLSurface* surface = 0;
   1179     int error = createTextureSurface(c, &surface, &size,
   1180             level, format, type, width, height);
   1181     if (error) {
   1182         ogles_error(c, error);
   1183         return;
   1184     }
   1185 
   1186     if (pixels) {
   1187         const int32_t formatIdx = convertGLPixelFormat(format, type);
   1188         const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
   1189         const int32_t align = c->textures.unpackAlignment-1;
   1190         const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
   1191         const int32_t stride = bpr / pixelFormat.size;
   1192 
   1193         GGLSurface userSurface;
   1194         userSurface.version = sizeof(userSurface);
   1195         userSurface.width  = width;
   1196         userSurface.height = height;
   1197         userSurface.stride = stride;
   1198         userSurface.format = formatIdx;
   1199         userSurface.compressedFormat = 0;
   1200         userSurface.data = (GLubyte*)pixels;
   1201 
   1202         int err = copyPixels(c, *surface, 0, 0, userSurface, 0, 0, width, height);
   1203         if (err) {
   1204             ogles_error(c, err);
   1205             return;
   1206         }
   1207         generateMipmap(c, level);
   1208     }
   1209 }
   1210 
   1211 // ----------------------------------------------------------------------------
   1212 
   1213 void glCompressedTexSubImage2D(
   1214         GLenum /*target*/, GLint /*level*/, GLint /*xoffset*/,
   1215         GLint /*yoffset*/, GLsizei /*width*/, GLsizei /*height*/,
   1216         GLenum /*format*/, GLsizei /*imageSize*/,
   1217         const GLvoid* /*data*/)
   1218 {
   1219     ogles_context_t* c = ogles_context_t::get();
   1220     ogles_error(c, GL_INVALID_ENUM);
   1221 }
   1222 
   1223 void glTexSubImage2D(
   1224         GLenum target, GLint level, GLint xoffset,
   1225         GLint yoffset, GLsizei width, GLsizei height,
   1226         GLenum format, GLenum type, const GLvoid *pixels)
   1227 {
   1228     ogles_context_t* c = ogles_context_t::get();
   1229     if (target != GL_TEXTURE_2D) {
   1230         ogles_error(c, GL_INVALID_ENUM);
   1231         return;
   1232     }
   1233     if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) {
   1234         ogles_error(c, GL_INVALID_VALUE);
   1235         return;
   1236     }
   1237     if (validFormatType(c, format, type)) {
   1238         return;
   1239     }
   1240 
   1241     // find out which texture is bound to the current unit
   1242     const int active = c->textures.active;
   1243     EGLTextureObject* tex = c->textures.tmu[active].texture;
   1244     const GGLSurface& surface(tex->mip(level));
   1245 
   1246     if (!tex->internalformat || tex->direct) {
   1247         ogles_error(c, GL_INVALID_OPERATION);
   1248         return;
   1249     }
   1250 
   1251     if (format != tex->internalformat) {
   1252         ogles_error(c, GL_INVALID_OPERATION);
   1253         return;
   1254     }
   1255     if ((xoffset + width  > GLsizei(surface.width)) ||
   1256         (yoffset + height > GLsizei(surface.height))) {
   1257         ogles_error(c, GL_INVALID_VALUE);
   1258         return;
   1259     }
   1260     if (!width || !height) {
   1261         return; // okay, but no-op.
   1262     }
   1263 
   1264     // figure out the size we need as well as the stride
   1265     const int32_t formatIdx = convertGLPixelFormat(format, type);
   1266     if (formatIdx == 0) { // we don't know what to do with this
   1267         ogles_error(c, GL_INVALID_OPERATION);
   1268         return;
   1269     }
   1270 
   1271     const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
   1272     const int32_t align = c->textures.unpackAlignment-1;
   1273     const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
   1274     const int32_t stride = bpr / pixelFormat.size;
   1275     GGLSurface userSurface;
   1276     userSurface.version = sizeof(userSurface);
   1277     userSurface.width  = width;
   1278     userSurface.height = height;
   1279     userSurface.stride = stride;
   1280     userSurface.format = formatIdx;
   1281     userSurface.compressedFormat = 0;
   1282     userSurface.data = (GLubyte*)pixels;
   1283 
   1284     int err = copyPixels(c,
   1285             surface, xoffset, yoffset,
   1286             userSurface, 0, 0, width, height);
   1287     if (err) {
   1288         ogles_error(c, err);
   1289         return;
   1290     }
   1291 
   1292     generateMipmap(c, level);
   1293 
   1294     // since we only changed the content of the texture, we don't need
   1295     // to call bindTexture on the main rasterizer.
   1296 }
   1297 
   1298 // ----------------------------------------------------------------------------
   1299 
   1300 void glCopyTexImage2D(
   1301         GLenum target, GLint level, GLenum internalformat,
   1302         GLint x, GLint y, GLsizei width, GLsizei height,
   1303         GLint border)
   1304 {
   1305     ogles_context_t* c = ogles_context_t::get();
   1306     if (target != GL_TEXTURE_2D) {
   1307         ogles_error(c, GL_INVALID_ENUM);
   1308         return;
   1309     }
   1310     if (internalformat<GL_ALPHA || internalformat>GL_LUMINANCE_ALPHA) {
   1311         ogles_error(c, GL_INVALID_ENUM);
   1312         return;
   1313     }
   1314     if (width<0 || height<0 || border!=0 || level<0) {
   1315         ogles_error(c, GL_INVALID_VALUE);
   1316         return;
   1317     }
   1318 
   1319     GLenum format = 0;
   1320     GLenum type = GL_UNSIGNED_BYTE;
   1321     const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
   1322     const int cbFormatIdx = cbSurface.format;
   1323     switch (cbFormatIdx) {
   1324     case GGL_PIXEL_FORMAT_RGB_565:
   1325         type = GL_UNSIGNED_SHORT_5_6_5;
   1326         break;
   1327     case GGL_PIXEL_FORMAT_RGBA_5551:
   1328         type = GL_UNSIGNED_SHORT_5_5_5_1;
   1329         break;
   1330     case GGL_PIXEL_FORMAT_RGBA_4444:
   1331         type = GL_UNSIGNED_SHORT_4_4_4_4;
   1332         break;
   1333     }
   1334     switch (internalformat) {
   1335     case GL_ALPHA:
   1336     case GL_LUMINANCE_ALPHA:
   1337     case GL_LUMINANCE:
   1338         type = GL_UNSIGNED_BYTE;
   1339         break;
   1340     }
   1341 
   1342     // figure out the format to use for the new texture
   1343     switch (cbFormatIdx) {
   1344     case GGL_PIXEL_FORMAT_RGBA_8888:
   1345     case GGL_PIXEL_FORMAT_A_8:
   1346     case GGL_PIXEL_FORMAT_RGBA_5551:
   1347     case GGL_PIXEL_FORMAT_RGBA_4444:
   1348         format = internalformat;
   1349         break;
   1350     case GGL_PIXEL_FORMAT_RGBX_8888:
   1351     case GGL_PIXEL_FORMAT_RGB_888:
   1352     case GGL_PIXEL_FORMAT_RGB_565:
   1353     case GGL_PIXEL_FORMAT_L_8:
   1354         switch (internalformat) {
   1355         case GL_LUMINANCE:
   1356         case GL_RGB:
   1357             format = internalformat;
   1358             break;
   1359         }
   1360         break;
   1361     }
   1362 
   1363     if (format == 0) {
   1364         // invalid combination
   1365         ogles_error(c, GL_INVALID_ENUM);
   1366         return;
   1367     }
   1368 
   1369     // create the new texture...
   1370     int32_t size;
   1371     GGLSurface* surface;
   1372     int error = createTextureSurface(c, &surface, &size,
   1373             level, format, type, width, height);
   1374     if (error) {
   1375         ogles_error(c, error);
   1376         return;
   1377     }
   1378 
   1379     // The bottom row is stored first in textures
   1380     GGLSurface txSurface(*surface);
   1381     txSurface.stride = -txSurface.stride;
   1382 
   1383     // (x,y) is the lower-left corner of colorBuffer
   1384     y = cbSurface.height - (y + height);
   1385 
   1386     /* The GLES spec says:
   1387      * If any of the pixels within the specified rectangle are outside
   1388      * the framebuffer associated with the current rendering context,
   1389      * then the values obtained for those pixels are undefined.
   1390      */
   1391     if (x+width > GLint(cbSurface.width))
   1392         width = cbSurface.width - x;
   1393 
   1394     if (y+height > GLint(cbSurface.height))
   1395         height = cbSurface.height - y;
   1396 
   1397     int err = copyPixels(c,
   1398             txSurface, 0, 0,
   1399             cbSurface, x, y, width, height);
   1400     if (err) {
   1401         ogles_error(c, err);
   1402     }
   1403 
   1404     generateMipmap(c, level);
   1405 }
   1406 
   1407 void glCopyTexSubImage2D(
   1408         GLenum target, GLint level, GLint xoffset, GLint yoffset,
   1409         GLint x, GLint y, GLsizei width, GLsizei height)
   1410 {
   1411     ogles_context_t* c = ogles_context_t::get();
   1412     if (target != GL_TEXTURE_2D) {
   1413         ogles_error(c, GL_INVALID_ENUM);
   1414         return;
   1415     }
   1416     if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) {
   1417         ogles_error(c, GL_INVALID_VALUE);
   1418         return;
   1419     }
   1420     if (!width || !height) {
   1421         return; // okay, but no-op.
   1422     }
   1423 
   1424     // find out which texture is bound to the current unit
   1425     const int active = c->textures.active;
   1426     EGLTextureObject* tex = c->textures.tmu[active].texture;
   1427     const GGLSurface& surface(tex->mip(level));
   1428 
   1429     if (!tex->internalformat) {
   1430         ogles_error(c, GL_INVALID_OPERATION);
   1431         return;
   1432     }
   1433     if ((xoffset + width  > GLsizei(surface.width)) ||
   1434         (yoffset + height > GLsizei(surface.height))) {
   1435         ogles_error(c, GL_INVALID_VALUE);
   1436         return;
   1437     }
   1438 
   1439     // The bottom row is stored first in textures
   1440     GGLSurface txSurface(surface);
   1441     txSurface.stride = -txSurface.stride;
   1442 
   1443     // (x,y) is the lower-left corner of colorBuffer
   1444     const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
   1445     y = cbSurface.height - (y + height);
   1446 
   1447     /* The GLES spec says:
   1448      * If any of the pixels within the specified rectangle are outside
   1449      * the framebuffer associated with the current rendering context,
   1450      * then the values obtained for those pixels are undefined.
   1451      */
   1452     if (x+width > GLint(cbSurface.width))
   1453         width = cbSurface.width - x;
   1454 
   1455     if (y+height > GLint(cbSurface.height))
   1456         height = cbSurface.height - y;
   1457 
   1458     int err = copyPixels(c,
   1459             txSurface, xoffset, yoffset,
   1460             cbSurface, x, y, width, height);
   1461     if (err) {
   1462         ogles_error(c, err);
   1463         return;
   1464     }
   1465 
   1466     generateMipmap(c, level);
   1467 }
   1468 
   1469 void glReadPixels(
   1470         GLint x, GLint y, GLsizei width, GLsizei height,
   1471         GLenum format, GLenum type, GLvoid *pixels)
   1472 {
   1473     ogles_context_t* c = ogles_context_t::get();
   1474     if ((format != GL_RGBA) && (format != GL_RGB)) {
   1475         ogles_error(c, GL_INVALID_ENUM);
   1476         return;
   1477     }
   1478     if ((type != GL_UNSIGNED_BYTE) && (type != GL_UNSIGNED_SHORT_5_6_5)) {
   1479         ogles_error(c, GL_INVALID_ENUM);
   1480         return;
   1481     }
   1482     if (width<0 || height<0) {
   1483         ogles_error(c, GL_INVALID_VALUE);
   1484         return;
   1485     }
   1486     if (x<0 || y<0) {
   1487         ogles_error(c, GL_INVALID_VALUE);
   1488         return;
   1489     }
   1490 
   1491     int32_t formatIdx = GGL_PIXEL_FORMAT_NONE;
   1492     if ((format == GL_RGBA) && (type == GL_UNSIGNED_BYTE)) {
   1493         formatIdx = GGL_PIXEL_FORMAT_RGBA_8888;
   1494     } else if ((format == GL_RGB) && (type == GL_UNSIGNED_SHORT_5_6_5)) {
   1495         formatIdx = GGL_PIXEL_FORMAT_RGB_565;
   1496     } else {
   1497         ogles_error(c, GL_INVALID_OPERATION);
   1498         return;
   1499     }
   1500 
   1501     const GGLSurface& readSurface = c->rasterizer.state.buffers.read.s;
   1502     if ((x+width > GLint(readSurface.width)) ||
   1503             (y+height > GLint(readSurface.height))) {
   1504         ogles_error(c, GL_INVALID_VALUE);
   1505         return;
   1506     }
   1507 
   1508     const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
   1509     const int32_t align = c->textures.packAlignment-1;
   1510     const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
   1511     const int32_t stride = bpr / pixelFormat.size;
   1512 
   1513     GGLSurface userSurface;
   1514     userSurface.version = sizeof(userSurface);
   1515     userSurface.width  = width;
   1516     userSurface.height = height;
   1517     userSurface.stride = -stride; // bottom row is transfered first
   1518     userSurface.format = formatIdx;
   1519     userSurface.compressedFormat = 0;
   1520     userSurface.data = (GLubyte*)pixels;
   1521 
   1522     // use pixel-flinger to handle all the conversions
   1523     GGLContext* ggl = getRasterizer(c);
   1524     if (!ggl) {
   1525         // the only reason this would fail is because we ran out of memory
   1526         ogles_error(c, GL_OUT_OF_MEMORY);
   1527         return;
   1528     }
   1529 
   1530     ggl->colorBuffer(ggl, &userSurface);  // destination is user buffer
   1531     ggl->bindTexture(ggl, &readSurface);  // source is read-buffer
   1532     ggl->texCoord2i(ggl, x, readSurface.height - (y + height));
   1533     ggl->recti(ggl, 0, 0, width, height);
   1534 }
   1535 
   1536 // ----------------------------------------------------------------------------
   1537 #if 0
   1538 #pragma mark -
   1539 #pragma mark DrawTexture Extension
   1540 #endif
   1541 
   1542 void glDrawTexsvOES(const GLshort* coords) {
   1543     ogles_context_t* c = ogles_context_t::get();
   1544     drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
   1545 }
   1546 void glDrawTexivOES(const GLint* coords) {
   1547     ogles_context_t* c = ogles_context_t::get();
   1548     drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
   1549 }
   1550 void glDrawTexsOES(GLshort x , GLshort y, GLshort z, GLshort w, GLshort h) {
   1551     ogles_context_t* c = ogles_context_t::get();
   1552     drawTexiOES(x, y, z, w, h, c);
   1553 }
   1554 void glDrawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h) {
   1555     ogles_context_t* c = ogles_context_t::get();
   1556     drawTexiOES(x, y, z, w, h, c);
   1557 }
   1558 
   1559 void glDrawTexfvOES(const GLfloat* coords) {
   1560     ogles_context_t* c = ogles_context_t::get();
   1561     drawTexxOES(
   1562             gglFloatToFixed(coords[0]),
   1563             gglFloatToFixed(coords[1]),
   1564             gglFloatToFixed(coords[2]),
   1565             gglFloatToFixed(coords[3]),
   1566             gglFloatToFixed(coords[4]),
   1567             c);
   1568 }
   1569 void glDrawTexxvOES(const GLfixed* coords) {
   1570     ogles_context_t* c = ogles_context_t::get();
   1571     drawTexxOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
   1572 }
   1573 void glDrawTexfOES(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h){
   1574     ogles_context_t* c = ogles_context_t::get();
   1575     drawTexxOES(
   1576             gglFloatToFixed(x), gglFloatToFixed(y), gglFloatToFixed(z),
   1577             gglFloatToFixed(w), gglFloatToFixed(h),
   1578             c);
   1579 }
   1580 void glDrawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h) {
   1581     ogles_context_t* c = ogles_context_t::get();
   1582     drawTexxOES(x, y, z, w, h, c);
   1583 }
   1584 
   1585 // ----------------------------------------------------------------------------
   1586 #if 0
   1587 #pragma mark -
   1588 #pragma mark EGL Image Extension
   1589 #endif
   1590 
   1591 void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
   1592 {
   1593     ogles_context_t* c = ogles_context_t::get();
   1594     if (target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES) {
   1595         ogles_error(c, GL_INVALID_ENUM);
   1596         return;
   1597     }
   1598 
   1599     if (image == EGL_NO_IMAGE_KHR) {
   1600         ogles_error(c, GL_INVALID_VALUE);
   1601         return;
   1602     }
   1603 
   1604     ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)image;
   1605     if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) {
   1606         ogles_error(c, GL_INVALID_VALUE);
   1607         return;
   1608     }
   1609     if (native_buffer->common.version != sizeof(ANativeWindowBuffer)) {
   1610         ogles_error(c, GL_INVALID_VALUE);
   1611         return;
   1612     }
   1613 
   1614     // bind it to the texture unit
   1615     sp<EGLTextureObject> tex = getAndBindActiveTextureObject(c);
   1616     tex->setImage(native_buffer);
   1617 }
   1618 
   1619 void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
   1620 {
   1621     ogles_context_t* c = ogles_context_t::get();
   1622     if (target != GL_RENDERBUFFER_OES) {
   1623         ogles_error(c, GL_INVALID_ENUM);
   1624         return;
   1625     }
   1626 
   1627     if (image == EGL_NO_IMAGE_KHR) {
   1628         ogles_error(c, GL_INVALID_VALUE);
   1629         return;
   1630     }
   1631 
   1632     ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)image;
   1633     if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) {
   1634         ogles_error(c, GL_INVALID_VALUE);
   1635         return;
   1636     }
   1637     if (native_buffer->common.version != sizeof(ANativeWindowBuffer)) {
   1638         ogles_error(c, GL_INVALID_VALUE);
   1639         return;
   1640     }
   1641 
   1642     // well, we're not supporting this extension anyways
   1643 }
   1644