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