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