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