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