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