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