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