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