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