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