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