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