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