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