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