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