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