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