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