blob: 9bcbfdd24401178ac5eb95d879d1ce5aa7960de7 [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 Agopian076b1cc2009-04-10 14:24:30 -070026#include <EGL/android_natives.h>
27
28#ifdef LIBAGL_USE_GRALLOC_COPYBITS
29#include "copybit.h"
30#include "gralloc_priv.h"
31#endif // LIBAGL_USE_GRALLOC_COPYBITS
32
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080033namespace android {
34
35// ----------------------------------------------------------------------------
36
37static void bindTextureTmu(
38 ogles_context_t* c, int tmu, GLuint texture, const sp<EGLTextureObject>& tex);
39
40static __attribute__((noinline))
41void generateMipmap(ogles_context_t* c, GLint level);
42
43// ----------------------------------------------------------------------------
44
45#if 0
46#pragma mark -
47#pragma mark Init
48#endif
49
50void ogles_init_texture(ogles_context_t* c)
51{
52 c->textures.packAlignment = 4;
53 c->textures.unpackAlignment = 4;
54
55 // each context has a default named (0) texture (not shared)
56 c->textures.defaultTexture = new EGLTextureObject();
57 c->textures.defaultTexture->incStrong(c);
Mathias Agopian076b1cc2009-04-10 14:24:30 -070058
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080059 // bind the default texture to each texture unit
60 for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
61 bindTextureTmu(c, i, 0, c->textures.defaultTexture);
62 memset(c->current.texture[i].v, 0, sizeof(vec4_t));
63 c->current.texture[i].Q = 0x10000;
64 }
65}
66
67void ogles_uninit_texture(ogles_context_t* c)
68{
69 if (c->textures.ggl)
70 gglUninit(c->textures.ggl);
71 c->textures.defaultTexture->decStrong(c);
72 for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
73 if (c->textures.tmu[i].texture)
74 c->textures.tmu[i].texture->decStrong(c);
75 }
76}
77
78static __attribute__((noinline))
79void validate_tmu(ogles_context_t* c, int i)
80{
81 texture_unit_t& u(c->textures.tmu[i]);
82 if (u.dirty) {
83 u.dirty = 0;
84 c->rasterizer.procs.activeTexture(c, i);
85 c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
86 c->rasterizer.procs.texGeni(c, GGL_S,
87 GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC);
88 c->rasterizer.procs.texGeni(c, GGL_T,
89 GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC);
90 c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
91 GGL_TEXTURE_WRAP_S, u.texture->wraps);
92 c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
93 GGL_TEXTURE_WRAP_T, u.texture->wrapt);
94 c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
95 GGL_TEXTURE_MIN_FILTER, u.texture->min_filter);
96 c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
97 GGL_TEXTURE_MAG_FILTER, u.texture->mag_filter);
98
99 // disable this texture unit if it's not complete
100 if (!u.texture->isComplete()) {
101 c->rasterizer.procs.disable(c, GGL_TEXTURE_2D);
102 }
103 }
104}
105
Mathias Agopian0926f502009-05-04 14:17:04 -0700106void ogles_validate_texture(ogles_context_t* c)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800107{
108 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
109 if (c->rasterizer.state.texture[i].enable)
110 validate_tmu(c, i);
111 }
112 c->rasterizer.procs.activeTexture(c, c->textures.active);
113}
114
115static
116void invalidate_texture(ogles_context_t* c, int tmu, uint8_t flags = 0xFF) {
117 c->textures.tmu[tmu].dirty = flags;
118}
119
Mathias Agopian0926f502009-05-04 14:17:04 -0700120/*
121 * If the active textures are EGLImage, they need to be locked before
122 * they can be used.
123 *
124 * FIXME: code below is far from being optimal
125 *
126 */
127
128void ogles_lock_textures(ogles_context_t* c)
129{
130 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
131 if (c->rasterizer.state.texture[i].enable) {
132 texture_unit_t& u(c->textures.tmu[i]);
133 android_native_buffer_t* native_buffer = u.texture->buffer;
134 if (native_buffer) {
135 c->rasterizer.procs.activeTexture(c, i);
136 hw_module_t const* pModule;
137 if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule))
138 continue;
139
140 gralloc_module_t const* module =
141 reinterpret_cast<gralloc_module_t const*>(pModule);
142 buffer_handle_t bufferHandle;
143 native_buffer->getHandle(native_buffer, &bufferHandle);
Mathias Agopiane71212b2009-05-05 00:37:46 -0700144 void* vaddr;
Mathias Agopian0926f502009-05-04 14:17:04 -0700145 int err = module->lock(module, bufferHandle,
146 GRALLOC_USAGE_SW_READ_OFTEN,
147 0, 0, native_buffer->width, native_buffer->height,
Mathias Agopiane71212b2009-05-05 00:37:46 -0700148 &vaddr);
Mathias Agopian0926f502009-05-04 14:17:04 -0700149
Mathias Agopiane71212b2009-05-05 00:37:46 -0700150 u.texture->setImageBits(vaddr);
Mathias Agopian0926f502009-05-04 14:17:04 -0700151 c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
152 }
153 }
154 }
155}
156
157void ogles_unlock_textures(ogles_context_t* c)
158{
159 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
160 if (c->rasterizer.state.texture[i].enable) {
161 texture_unit_t& u(c->textures.tmu[i]);
162 android_native_buffer_t* native_buffer = u.texture->buffer;
163 if (native_buffer) {
164 c->rasterizer.procs.activeTexture(c, i);
165 hw_module_t const* pModule;
166 if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule))
167 continue;
168
169 gralloc_module_t const* module =
170 reinterpret_cast<gralloc_module_t const*>(pModule);
171 buffer_handle_t bufferHandle;
172 native_buffer->getHandle(native_buffer, &bufferHandle);
173 module->unlock(module, bufferHandle);
174 u.texture->setImageBits(NULL);
175 c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
176 }
177 }
178 }
179 c->rasterizer.procs.activeTexture(c, c->textures.active);
180}
181
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800182// ----------------------------------------------------------------------------
183#if 0
184#pragma mark -
185#pragma mark Format conversion
186#endif
187
188static uint32_t gl2format_table[6][4] = {
189 // BYTE, 565, 4444, 5551
190 { GGL_PIXEL_FORMAT_A_8,
191 0, 0, 0 }, // GL_ALPHA
192 { GGL_PIXEL_FORMAT_RGB_888,
193 GGL_PIXEL_FORMAT_RGB_565,
194 0, 0 }, // GL_RGB
195 { GGL_PIXEL_FORMAT_RGBA_8888,
196 0,
197 GGL_PIXEL_FORMAT_RGBA_4444,
198 GGL_PIXEL_FORMAT_RGBA_5551 }, // GL_RGBA
199 { GGL_PIXEL_FORMAT_L_8,
200 0, 0, 0 }, // GL_LUMINANCE
201 { GGL_PIXEL_FORMAT_LA_88,
202 0, 0, 0 }, // GL_LUMINANCE_ALPHA
203};
204
205static int32_t convertGLPixelFormat(GLint format, GLenum type)
206{
207 int32_t fi = -1;
208 int32_t ti = -1;
209 switch (format) {
210 case GL_ALPHA: fi = 0; break;
211 case GL_RGB: fi = 1; break;
212 case GL_RGBA: fi = 2; break;
213 case GL_LUMINANCE: fi = 3; break;
214 case GL_LUMINANCE_ALPHA: fi = 4; break;
215 }
216 switch (type) {
217 case GL_UNSIGNED_BYTE: ti = 0; break;
218 case GL_UNSIGNED_SHORT_5_6_5: ti = 1; break;
219 case GL_UNSIGNED_SHORT_4_4_4_4: ti = 2; break;
220 case GL_UNSIGNED_SHORT_5_5_5_1: ti = 3; break;
221 }
222 if (fi==-1 || ti==-1)
223 return 0;
224 return gl2format_table[fi][ti];
225}
226
227// ----------------------------------------------------------------------------
228
229static GLenum validFormatType(ogles_context_t* c, GLenum format, GLenum type)
230{
231 GLenum error = 0;
232 if (format<GL_ALPHA || format>GL_LUMINANCE_ALPHA) {
233 error = GL_INVALID_ENUM;
234 }
235 if (type != GL_UNSIGNED_BYTE && type != GL_UNSIGNED_SHORT_4_4_4_4 &&
236 type != GL_UNSIGNED_SHORT_5_5_5_1 && type != GL_UNSIGNED_SHORT_5_6_5) {
237 error = GL_INVALID_ENUM;
238 }
239 if (type == GL_UNSIGNED_SHORT_5_6_5 && format != GL_RGB) {
240 error = GL_INVALID_OPERATION;
241 }
242 if ((type == GL_UNSIGNED_SHORT_4_4_4_4 ||
243 type == GL_UNSIGNED_SHORT_5_5_5_1) && format != GL_RGBA) {
244 error = GL_INVALID_OPERATION;
245 }
246 if (error) {
247 ogles_error(c, error);
248 }
249 return error;
250}
251
252// ----------------------------------------------------------------------------
253
254GGLContext* getRasterizer(ogles_context_t* c)
255{
256 GGLContext* ggl = c->textures.ggl;
257 if (ggl_unlikely(!ggl)) {
258 // this is quite heavy the first time...
259 gglInit(&ggl);
260 if (!ggl) {
261 return 0;
262 }
263 GGLfixed colors[4] = { 0, 0, 0, 0x10000 };
264 c->textures.ggl = ggl;
265 ggl->activeTexture(ggl, 0);
266 ggl->enable(ggl, GGL_TEXTURE_2D);
267 ggl->texEnvi(ggl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
268 ggl->disable(ggl, GGL_DITHER);
269 ggl->shadeModel(ggl, GGL_FLAT);
270 ggl->color4xv(ggl, colors);
271 }
272 return ggl;
273}
274
275static __attribute__((noinline))
276int copyPixels(
277 ogles_context_t* c,
278 const GGLSurface& dst,
279 GLint xoffset, GLint yoffset,
280 const GGLSurface& src,
281 GLint x, GLint y, GLsizei w, GLsizei h)
282{
283 if ((dst.format == src.format) &&
284 (dst.stride == src.stride) &&
285 (dst.width == src.width) &&
286 (dst.height == src.height) &&
287 (dst.stride > 0) &&
288 ((x|y) == 0) &&
289 ((xoffset|yoffset) == 0))
290 {
291 // this is a common case...
292 const GGLFormat& pixelFormat(c->rasterizer.formats[src.format]);
293 const size_t size = src.height * src.stride * pixelFormat.size;
294 memcpy(dst.data, src.data, size);
295 return 0;
296 }
297
298 // use pixel-flinger to handle all the conversions
299 GGLContext* ggl = getRasterizer(c);
300 if (!ggl) {
301 // the only reason this would fail is because we ran out of memory
302 return GL_OUT_OF_MEMORY;
303 }
304
305 ggl->colorBuffer(ggl, &dst);
306 ggl->bindTexture(ggl, &src);
307 ggl->texCoord2i(ggl, x-xoffset, y-yoffset);
308 ggl->recti(ggl, xoffset, yoffset, xoffset+w, yoffset+h);
309 return 0;
310}
311
312// ----------------------------------------------------------------------------
313
314static __attribute__((noinline))
315sp<EGLTextureObject> getAndBindActiveTextureObject(ogles_context_t* c)
316{
317 sp<EGLTextureObject> tex;
318 const int active = c->textures.active;
319 const GLuint name = c->textures.tmu[active].name;
320
321 // free the reference to the previously bound object
322 texture_unit_t& u(c->textures.tmu[active]);
323 if (u.texture)
324 u.texture->decStrong(c);
325
326 if (name == 0) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700327 // 0 is our local texture object, not shared with anyone.
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800328 // But it affects all bound TMUs immediately.
329 // (we need to invalidate all units bound to this texture object)
330 tex = c->textures.defaultTexture;
331 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
332 if (c->textures.tmu[i].texture == tex.get())
333 invalidate_texture(c, i);
334 }
335 } else {
336 // get a new texture object for that name
337 tex = c->surfaceManager->replaceTexture(name);
338 }
339
340 // bind this texture to the current active texture unit
341 // and add a reference to this texture object
342 u.texture = tex.get();
343 u.texture->incStrong(c);
344 u.name = name;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700345 invalidate_texture(c, active);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800346 return tex;
347}
348
349void bindTextureTmu(
350 ogles_context_t* c, int tmu, GLuint texture, const sp<EGLTextureObject>& tex)
351{
352 if (tex.get() == c->textures.tmu[tmu].texture)
353 return;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700354
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800355 // free the reference to the previously bound object
356 texture_unit_t& u(c->textures.tmu[tmu]);
357 if (u.texture)
358 u.texture->decStrong(c);
359
360 // bind this texture to the current active texture unit
361 // and add a reference to this texture object
362 u.texture = tex.get();
363 u.texture->incStrong(c);
364 u.name = texture;
365 invalidate_texture(c, tmu);
366}
367
368int createTextureSurface(ogles_context_t* c,
369 GGLSurface** outSurface, int32_t* outSize, GLint level,
370 GLenum format, GLenum type, GLsizei width, GLsizei height,
371 GLenum compressedFormat = 0)
372{
373 // find out which texture is bound to the current unit
374 const int active = c->textures.active;
375 const GLuint name = c->textures.tmu[active].name;
376
377 // convert the pixelformat to one we can handle
378 const int32_t formatIdx = convertGLPixelFormat(format, type);
379 if (formatIdx == 0) { // we don't know what to do with this
380 return GL_INVALID_OPERATION;
381 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700382
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800383 // figure out the size we need as well as the stride
384 const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
385 const int32_t align = c->textures.unpackAlignment-1;
386 const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
387 const size_t size = bpr * height;
388 const int32_t stride = bpr / pixelFormat.size;
389
390 if (level > 0) {
391 const int active = c->textures.active;
392 EGLTextureObject* tex = c->textures.tmu[active].texture;
393 status_t err = tex->reallocate(level,
394 width, height, stride, formatIdx, compressedFormat, bpr);
395 if (err != NO_ERROR)
396 return GL_OUT_OF_MEMORY;
397 GGLSurface& surface = tex->editMip(level);
398 *outSurface = &surface;
399 *outSize = size;
400 return 0;
401 }
402
403 sp<EGLTextureObject> tex = getAndBindActiveTextureObject(c);
404 status_t err = tex->reallocate(level,
405 width, height, stride, formatIdx, compressedFormat, bpr);
406 if (err != NO_ERROR)
407 return GL_OUT_OF_MEMORY;
408
409 tex->internalformat = format;
410 *outSurface = &tex->surface;
411 *outSize = size;
412 return 0;
413}
414
415static void decodePalette4(const GLvoid *data, int level, int width, int height,
416 void *surface, int stride, int format)
417
418{
419 int indexBits = 8;
420 int entrySize = 0;
421 switch (format) {
422 case GL_PALETTE4_RGB8_OES:
423 indexBits = 4;
424 /* FALLTHROUGH */
425 case GL_PALETTE8_RGB8_OES:
426 entrySize = 3;
427 break;
428
429 case GL_PALETTE4_RGBA8_OES:
430 indexBits = 4;
431 /* FALLTHROUGH */
432 case GL_PALETTE8_RGBA8_OES:
433 entrySize = 4;
434 break;
435
436 case GL_PALETTE4_R5_G6_B5_OES:
437 case GL_PALETTE4_RGBA4_OES:
438 case GL_PALETTE4_RGB5_A1_OES:
439 indexBits = 4;
440 /* FALLTHROUGH */
441 case GL_PALETTE8_R5_G6_B5_OES:
442 case GL_PALETTE8_RGBA4_OES:
443 case GL_PALETTE8_RGB5_A1_OES:
444 entrySize = 2;
445 break;
446 }
447
448 const int paletteSize = (1 << indexBits) * entrySize;
449 uint8_t const* pixels = (uint8_t *)data + paletteSize;
450 for (int i=0 ; i<level ; i++) {
451 int w = (width >> i) ? : 1;
452 int h = (height >> i) ? : 1;
453 pixels += h * ((w * indexBits) / 8);
454 }
455 width = (width >> level) ? : 1;
456 height = (height >> level) ? : 1;
457
458 if (entrySize == 2) {
459 uint8_t const* const palette = (uint8_t*)data;
460 for (int y=0 ; y<height ; y++) {
461 uint8_t* p = (uint8_t*)surface + y*stride*2;
462 if (indexBits == 8) {
463 for (int x=0 ; x<width ; x++) {
464 int index = 2 * (*pixels++);
465 *p++ = palette[index + 0];
466 *p++ = palette[index + 1];
467 }
468 } else {
469 for (int x=0 ; x<width ; x+=2) {
470 int v = *pixels++;
471 int index = 2 * (v >> 4);
472 *p++ = palette[index + 0];
473 *p++ = palette[index + 1];
474 if (x+1 < width) {
475 index = 2 * (v & 0xF);
476 *p++ = palette[index + 0];
477 *p++ = palette[index + 1];
478 }
479 }
480 }
481 }
482 } else if (entrySize == 3) {
483 uint8_t const* const palette = (uint8_t*)data;
484 for (int y=0 ; y<height ; y++) {
485 uint8_t* p = (uint8_t*)surface + y*stride*3;
486 if (indexBits == 8) {
487 for (int x=0 ; x<width ; x++) {
488 int index = 3 * (*pixels++);
489 *p++ = palette[index + 0];
490 *p++ = palette[index + 1];
491 *p++ = palette[index + 2];
492 }
493 } else {
494 for (int x=0 ; x<width ; x+=2) {
495 int v = *pixels++;
496 int index = 3 * (v >> 4);
497 *p++ = palette[index + 0];
498 *p++ = palette[index + 1];
499 *p++ = palette[index + 2];
500 if (x+1 < width) {
501 index = 3 * (v & 0xF);
502 *p++ = palette[index + 0];
503 *p++ = palette[index + 1];
504 *p++ = palette[index + 2];
505 }
506 }
507 }
508 }
509 } else if (entrySize == 4) {
510 uint8_t const* const palette = (uint8_t*)data;
511 for (int y=0 ; y<height ; y++) {
512 uint8_t* p = (uint8_t*)surface + y*stride*4;
513 if (indexBits == 8) {
514 for (int x=0 ; x<width ; x++) {
515 int index = 4 * (*pixels++);
516 *p++ = palette[index + 0];
517 *p++ = palette[index + 1];
518 *p++ = palette[index + 2];
519 *p++ = palette[index + 3];
520 }
521 } else {
522 for (int x=0 ; x<width ; x+=2) {
523 int v = *pixels++;
524 int index = 4 * (v >> 4);
525 *p++ = palette[index + 0];
526 *p++ = palette[index + 1];
527 *p++ = palette[index + 2];
528 *p++ = palette[index + 3];
529 if (x+1 < width) {
530 index = 4 * (v & 0xF);
531 *p++ = palette[index + 0];
532 *p++ = palette[index + 1];
533 *p++ = palette[index + 2];
534 *p++ = palette[index + 3];
535 }
536 }
537 }
538 }
539 }
540}
541
542
543
544static __attribute__((noinline))
545void set_depth_and_fog(ogles_context_t* c, GLint z)
546{
547 const uint32_t enables = c->rasterizer.state.enables;
548 // we need to compute Zw
549 int32_t iterators[3];
550 iterators[1] = iterators[2] = 0;
551 GGLfixed Zw;
552 GGLfixed n = gglFloatToFixed(c->transforms.vpt.zNear);
553 GGLfixed f = gglFloatToFixed(c->transforms.vpt.zFar);
554 if (z<=0) Zw = n;
555 else if (z>=1) Zw = f;
556 else Zw = gglMulAddx(z, (f-n), n);
557 if (enables & GGL_ENABLE_FOG) {
558 // set up fog if needed...
559 iterators[0] = c->fog.fog(c, Zw);
560 c->rasterizer.procs.fogGrad3xv(c, iterators);
561 }
562 if (enables & GGL_ENABLE_DEPTH_TEST) {
563 // set up z-test if needed...
564 int32_t z = (Zw & ~(Zw>>31));
565 if (z >= 0x10000)
566 z = 0xFFFF;
567 iterators[0] = (z << 16) | z;
568 c->rasterizer.procs.zGrad3xv(c, iterators);
569 }
570}
571
572// ----------------------------------------------------------------------------
573#if 0
574#pragma mark -
575#pragma mark Generate mimaps
576#endif
577
578extern status_t buildAPyramid(ogles_context_t* c, EGLTextureObject* tex);
579
580void generateMipmap(ogles_context_t* c, GLint level)
581{
582 if (level == 0) {
583 const int active = c->textures.active;
584 EGLTextureObject* tex = c->textures.tmu[active].texture;
585 if (tex->generate_mipmap) {
586 if (buildAPyramid(c, tex) != NO_ERROR) {
587 ogles_error(c, GL_OUT_OF_MEMORY);
588 return;
589 }
590 }
591 }
592}
593
594
595static void texParameterx(
596 GLenum target, GLenum pname, GLfixed param, ogles_context_t* c)
597{
598 if (target != GL_TEXTURE_2D) {
599 ogles_error(c, GL_INVALID_ENUM);
600 return;
601 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700602
603 EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800604 switch (pname) {
605 case GL_TEXTURE_WRAP_S:
606 if ((param == GL_REPEAT) ||
607 (param == GL_CLAMP_TO_EDGE)) {
608 textureObject->wraps = param;
609 } else {
610 goto invalid_enum;
611 }
612 break;
613 case GL_TEXTURE_WRAP_T:
614 if ((param == GL_REPEAT) ||
615 (param == GL_CLAMP_TO_EDGE)) {
616 textureObject->wrapt = param;
617 } else {
618 goto invalid_enum;
619 }
620 break;
621 case GL_TEXTURE_MIN_FILTER:
622 if ((param == GL_NEAREST) ||
623 (param == GL_LINEAR) ||
624 (param == GL_NEAREST_MIPMAP_NEAREST) ||
625 (param == GL_LINEAR_MIPMAP_NEAREST) ||
626 (param == GL_NEAREST_MIPMAP_LINEAR) ||
627 (param == GL_LINEAR_MIPMAP_LINEAR)) {
628 textureObject->min_filter = param;
629 } else {
630 goto invalid_enum;
631 }
632 break;
633 case GL_TEXTURE_MAG_FILTER:
634 if ((param == GL_NEAREST) ||
635 (param == GL_LINEAR)) {
636 textureObject->mag_filter = param;
637 } else {
638 goto invalid_enum;
639 }
640 break;
641 case GL_GENERATE_MIPMAP:
642 textureObject->generate_mipmap = param;
643 break;
644 default:
645invalid_enum:
646 ogles_error(c, GL_INVALID_ENUM);
647 return;
648 }
649 invalidate_texture(c, c->textures.active);
650}
651
652
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700653
654static void drawTexxOESImp(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800655 ogles_context_t* c)
656{
Mathias Agopian0926f502009-05-04 14:17:04 -0700657 ogles_lock_textures(c);
658
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800659 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
660 y = gglIntToFixed(cbSurface.height) - (y + h);
661 w >>= FIXED_BITS;
662 h >>= FIXED_BITS;
663
664 // set up all texture units
665 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
666 if (!c->rasterizer.state.texture[i].enable)
667 continue;
668
669 int32_t texcoords[8];
670 texture_unit_t& u(c->textures.tmu[i]);
671
672 // validate this tmu (bind, wrap, filter)
673 validate_tmu(c, i);
674 // we CLAMP here, which works with premultiplied (s,t)
675 c->rasterizer.procs.texParameteri(c,
676 GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_S, GGL_CLAMP);
677 c->rasterizer.procs.texParameteri(c,
678 GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_T, GGL_CLAMP);
679 u.dirty = 0xFF; // XXX: should be more subtle
680
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700681 EGLTextureObject* textureObject = u.texture;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800682 const GLint Ucr = textureObject->crop_rect[0] << 16;
683 const GLint Vcr = textureObject->crop_rect[1] << 16;
684 const GLint Wcr = textureObject->crop_rect[2] << 16;
685 const GLint Hcr = textureObject->crop_rect[3] << 16;
686
687 // computes texture coordinates (pre-multiplied)
688 int32_t dsdx = Wcr / w; // dsdx = ((Wcr/w)/Wt)*Wt
689 int32_t dtdy =-Hcr / h; // dtdy = -((Hcr/h)/Ht)*Ht
690 int32_t s0 = Ucr - gglMulx(dsdx, x); // s0 = Ucr - x * dsdx
691 int32_t t0 = (Vcr+Hcr) - gglMulx(dtdy, y); // t0 = (Vcr+Hcr) - y*dtdy
692 texcoords[0] = s0;
693 texcoords[1] = dsdx;
694 texcoords[2] = 0;
695 texcoords[3] = t0;
696 texcoords[4] = 0;
697 texcoords[5] = dtdy;
698 texcoords[6] = 0;
699 texcoords[7] = 0;
700 c->rasterizer.procs.texCoordGradScale8xv(c, i, texcoords);
701 }
702
703 const uint32_t enables = c->rasterizer.state.enables;
704 if (ggl_unlikely(enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)))
705 set_depth_and_fog(c, z);
706
707 c->rasterizer.procs.activeTexture(c, c->textures.active);
708 c->rasterizer.procs.color4xv(c, c->currentColorClamped.v);
709 c->rasterizer.procs.disable(c, GGL_W_LERP);
710 c->rasterizer.procs.disable(c, GGL_AA);
711 c->rasterizer.procs.shadeModel(c, GL_FLAT);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700712 c->rasterizer.procs.recti(c,
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800713 gglFixedToIntRound(x),
714 gglFixedToIntRound(y),
715 gglFixedToIntRound(x)+w,
716 gglFixedToIntRound(y)+h);
Mathias Agopian0926f502009-05-04 14:17:04 -0700717
718 ogles_unlock_textures(c);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800719}
720
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700721static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
722 ogles_context_t* c)
723{
724#ifdef LIBAGL_USE_GRALLOC_COPYBITS
725 if (drawTexiOESWithCopybit(gglFixedToIntRound(x),
726 gglFixedToIntRound(y), gglFixedToIntRound(z),
727 gglFixedToIntRound(w), gglFixedToIntRound(h), c)) {
728 return;
729 }
730#else
731 // quickly reject empty rects
732 if ((w|h) <= 0)
733 return;
734#endif
735 drawTexxOESImp(x, y, z, w, h, c);
736}
737
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800738static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_context_t* c)
739{
740 // All coordinates are integer, so if we have only one
741 // texture unit active and no scaling is required
742 // THEN, we can use our special 1:1 mapping
743 // which is a lot faster.
744
745 if (ggl_likely(c->rasterizer.state.enabled_tmu == 1)) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700746#ifdef LIBAGL_USE_GRALLOC_COPYBITS
747 if (drawTexiOESWithCopybit(x, y, z, w, h, c)) {
748 return;
749 }
750#endif
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800751 const int tmu = 0;
752 texture_unit_t& u(c->textures.tmu[tmu]);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700753 EGLTextureObject* textureObject = u.texture;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800754 const GLint Wcr = textureObject->crop_rect[2];
755 const GLint Hcr = textureObject->crop_rect[3];
756
757 if ((w == Wcr) && (h == -Hcr)) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700758#ifndef LIBAGL_USE_GRALLOC_COPYBITS
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800759 if ((w|h) <= 0) return; // quickly reject empty rects
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700760#endif
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800761
762 if (u.dirty) {
763 c->rasterizer.procs.activeTexture(c, tmu);
764 c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
765 c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
766 GGL_TEXTURE_MIN_FILTER, u.texture->min_filter);
767 c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
768 GGL_TEXTURE_MAG_FILTER, u.texture->mag_filter);
769 }
770 c->rasterizer.procs.texGeni(c, GGL_S,
771 GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
772 c->rasterizer.procs.texGeni(c, GGL_T,
773 GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
774 u.dirty = 0xFF; // XXX: should be more subtle
775 c->rasterizer.procs.activeTexture(c, c->textures.active);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700776
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800777 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
778 y = cbSurface.height - (y + h);
779 const GLint Ucr = textureObject->crop_rect[0];
780 const GLint Vcr = textureObject->crop_rect[1];
781 const GLint s0 = Ucr - x;
782 const GLint t0 = (Vcr + Hcr) - y;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700783
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800784 const GLuint tw = textureObject->surface.width;
785 const GLuint th = textureObject->surface.height;
786 if ((uint32_t(s0+x+w) > tw) || (uint32_t(t0+y+h) > th)) {
787 // The GL spec is unclear about what should happen
788 // in this case, so we just use the slow case, which
789 // at least won't crash
790 goto slow_case;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700791 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800792
Mathias Agopian0926f502009-05-04 14:17:04 -0700793 ogles_lock_textures(c);
794
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800795 c->rasterizer.procs.texCoord2i(c, s0, t0);
796 const uint32_t enables = c->rasterizer.state.enables;
797 if (ggl_unlikely(enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)))
798 set_depth_and_fog(c, z);
799
800 c->rasterizer.procs.color4xv(c, c->currentColorClamped.v);
801 c->rasterizer.procs.disable(c, GGL_W_LERP);
802 c->rasterizer.procs.disable(c, GGL_AA);
803 c->rasterizer.procs.shadeModel(c, GL_FLAT);
804 c->rasterizer.procs.recti(c, x, y, x+w, y+h);
Mathias Agopian0926f502009-05-04 14:17:04 -0700805
806 ogles_unlock_textures(c);
807
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800808 return;
809 }
810 }
811
812slow_case:
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700813 drawTexxOESImp(
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800814 gglIntToFixed(x), gglIntToFixed(y), gglIntToFixed(z),
815 gglIntToFixed(w), gglIntToFixed(h),
816 c);
817}
818
819
820}; // namespace android
821// ----------------------------------------------------------------------------
822
823using namespace android;
824
825
826#if 0
827#pragma mark -
828#pragma mark Texture API
829#endif
830
831void glActiveTexture(GLenum texture)
832{
833 ogles_context_t* c = ogles_context_t::get();
834 if (uint32_t(texture-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) {
835 ogles_error(c, GL_INVALID_ENUM);
836 return;
837 }
838 c->textures.active = texture - GL_TEXTURE0;
839 c->rasterizer.procs.activeTexture(c, c->textures.active);
840}
841
842void glBindTexture(GLenum target, GLuint texture)
843{
844 ogles_context_t* c = ogles_context_t::get();
845 if (target != GL_TEXTURE_2D) {
846 ogles_error(c, GL_INVALID_ENUM);
847 return;
848 }
849
850 // Bind or create a texture
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700851 sp<EGLTextureObject> tex;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800852 if (texture == 0) {
853 // 0 is our local texture object
854 tex = c->textures.defaultTexture;
855 } else {
856 tex = c->surfaceManager->texture(texture);
857 if (ggl_unlikely(tex == 0)) {
858 tex = c->surfaceManager->createTexture(texture);
859 if (tex == 0) {
860 ogles_error(c, GL_OUT_OF_MEMORY);
861 return;
862 }
863 }
864 }
865 bindTextureTmu(c, c->textures.active, texture, tex);
866}
867
868void glGenTextures(GLsizei n, GLuint *textures)
869{
870 ogles_context_t* c = ogles_context_t::get();
871 if (n<0) {
872 ogles_error(c, GL_INVALID_VALUE);
873 return;
874 }
875 // generate unique (shared) texture names
876 c->surfaceManager->getToken(n, textures);
877}
878
879void glDeleteTextures(GLsizei n, const GLuint *textures)
880{
881 ogles_context_t* c = ogles_context_t::get();
882 if (n<0) {
883 ogles_error(c, GL_INVALID_VALUE);
884 return;
885 }
886
887 // If deleting a bound texture, bind this unit to 0
888 for (int t=0 ; t<GGL_TEXTURE_UNIT_COUNT ; t++) {
889 if (c->textures.tmu[t].name == 0)
890 continue;
891 for (int i=0 ; i<n ; i++) {
892 if (textures[i] && (textures[i] == c->textures.tmu[t].name)) {
893 // bind this tmu to texture 0
894 sp<EGLTextureObject> tex(c->textures.defaultTexture);
895 bindTextureTmu(c, t, 0, tex);
896 }
897 }
898 }
899 c->surfaceManager->deleteTextures(n, textures);
900 c->surfaceManager->recycleTokens(n, textures);
901}
902
903void glMultiTexCoord4f(
904 GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
905{
906 ogles_context_t* c = ogles_context_t::get();
907 if (uint32_t(target-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) {
908 ogles_error(c, GL_INVALID_ENUM);
909 return;
910 }
911 const int tmu = target-GL_TEXTURE0;
912 c->current.texture[tmu].S = gglFloatToFixed(s);
913 c->current.texture[tmu].T = gglFloatToFixed(t);
914 c->current.texture[tmu].R = gglFloatToFixed(r);
915 c->current.texture[tmu].Q = gglFloatToFixed(q);
916}
917
918void glMultiTexCoord4x(
919 GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q)
920{
921 ogles_context_t* c = ogles_context_t::get();
922 if (uint32_t(target-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) {
923 ogles_error(c, GL_INVALID_ENUM);
924 return;
925 }
926 const int tmu = target-GL_TEXTURE0;
927 c->current.texture[tmu].S = s;
928 c->current.texture[tmu].T = t;
929 c->current.texture[tmu].R = r;
930 c->current.texture[tmu].Q = q;
931}
932
933void glPixelStorei(GLenum pname, GLint param)
934{
935 ogles_context_t* c = ogles_context_t::get();
936 if ((pname != GL_PACK_ALIGNMENT) && (pname != GL_UNPACK_ALIGNMENT)) {
937 ogles_error(c, GL_INVALID_ENUM);
938 return;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700939 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800940 if ((param<=0 || param>8) || (param & (param-1))) {
941 ogles_error(c, GL_INVALID_VALUE);
942 return;
943 }
944 if (pname == GL_PACK_ALIGNMENT)
945 c->textures.packAlignment = param;
946 if (pname == GL_UNPACK_ALIGNMENT)
947 c->textures.unpackAlignment = param;
948}
949
950void glTexEnvf(GLenum target, GLenum pname, GLfloat param)
951{
952 ogles_context_t* c = ogles_context_t::get();
953 c->rasterizer.procs.texEnvi(c, target, pname, GLint(param));
954}
955
956void glTexEnvfv(
957 GLenum target, GLenum pname, const GLfloat *params)
958{
959 ogles_context_t* c = ogles_context_t::get();
960 if (pname == GL_TEXTURE_ENV_MODE) {
961 c->rasterizer.procs.texEnvi(c, target, pname, GLint(*params));
962 return;
963 }
964 if (pname == GL_TEXTURE_ENV_COLOR) {
965 GGLfixed fixed[4];
966 for (int i=0 ; i<4 ; i++)
967 fixed[i] = gglFloatToFixed(params[i]);
968 c->rasterizer.procs.texEnvxv(c, target, pname, fixed);
969 return;
970 }
971 ogles_error(c, GL_INVALID_ENUM);
972}
973
974void glTexEnvx(GLenum target, GLenum pname, GLfixed param)
975{
976 ogles_context_t* c = ogles_context_t::get();
977 c->rasterizer.procs.texEnvi(c, target, pname, param);
978}
979
980void glTexEnvxv(
981 GLenum target, GLenum pname, const GLfixed *params)
982{
983 ogles_context_t* c = ogles_context_t::get();
984 c->rasterizer.procs.texEnvxv(c, target, pname, params);
985}
986
987void glTexParameteriv(
988 GLenum target, GLenum pname, const GLint* params)
989{
990 ogles_context_t* c = ogles_context_t::get();
991 if (target != GGL_TEXTURE_2D) {
992 ogles_error(c, GL_INVALID_ENUM);
993 return;
994 }
995
996 EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture;
997 switch (pname) {
998 case GL_TEXTURE_CROP_RECT_OES:
999 memcpy(textureObject->crop_rect, params, 4*sizeof(GLint));
1000 break;
1001 default:
1002 ogles_error(c, GL_INVALID_ENUM);
1003 return;
1004 }
1005}
1006
1007void glTexParameterf(
1008 GLenum target, GLenum pname, GLfloat param)
1009{
1010 ogles_context_t* c = ogles_context_t::get();
1011 texParameterx(target, pname, GLfixed(param), c);
1012}
1013
1014void glTexParameterx(
1015 GLenum target, GLenum pname, GLfixed param)
1016{
1017 ogles_context_t* c = ogles_context_t::get();
1018 texParameterx(target, pname, param, c);
1019}
1020
1021// ----------------------------------------------------------------------------
1022#if 0
1023#pragma mark -
1024#endif
1025
1026void glCompressedTexImage2D(
1027 GLenum target, GLint level, GLenum internalformat,
1028 GLsizei width, GLsizei height, GLint border,
1029 GLsizei imageSize, const GLvoid *data)
1030{
1031 ogles_context_t* c = ogles_context_t::get();
1032 if (target != GL_TEXTURE_2D) {
1033 ogles_error(c, GL_INVALID_ENUM);
1034 return;
1035 }
1036 if ((internalformat < GL_PALETTE4_RGB8_OES ||
1037 internalformat > GL_PALETTE8_RGB5_A1_OES)) {
1038 ogles_error(c, GL_INVALID_ENUM);
1039 return;
1040 }
1041 if (width<0 || height<0 || border!=0) {
1042 ogles_error(c, GL_INVALID_VALUE);
1043 return;
1044 }
1045
1046 // "uncompress" the texture since pixelflinger doesn't support
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001047 // any compressed texture format natively.
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001048 GLenum format;
1049 GLenum type;
1050 switch (internalformat) {
1051 case GL_PALETTE8_RGB8_OES:
1052 case GL_PALETTE4_RGB8_OES:
1053 format = GL_RGB;
1054 type = GL_UNSIGNED_BYTE;
1055 break;
1056 case GL_PALETTE8_RGBA8_OES:
1057 case GL_PALETTE4_RGBA8_OES:
1058 format = GL_RGBA;
1059 type = GL_UNSIGNED_BYTE;
1060 break;
1061 case GL_PALETTE8_R5_G6_B5_OES:
1062 case GL_PALETTE4_R5_G6_B5_OES:
1063 format = GL_RGB;
1064 type = GL_UNSIGNED_SHORT_5_6_5;
1065 break;
1066 case GL_PALETTE8_RGBA4_OES:
1067 case GL_PALETTE4_RGBA4_OES:
1068 format = GL_RGBA;
1069 type = GL_UNSIGNED_SHORT_4_4_4_4;
1070 break;
1071 case GL_PALETTE8_RGB5_A1_OES:
1072 case GL_PALETTE4_RGB5_A1_OES:
1073 format = GL_RGBA;
1074 type = GL_UNSIGNED_SHORT_5_5_5_1;
1075 break;
1076 default:
1077 ogles_error(c, GL_INVALID_ENUM);
1078 return;
1079 }
1080
1081 if (!data || !width || !height) {
1082 // unclear if this is an error or not...
1083 return;
1084 }
1085
1086 int32_t size;
1087 GGLSurface* surface;
1088 // all mipmap levels are specified at once.
1089 const int numLevels = level<0 ? -level : 1;
1090 for (int i=0 ; i<numLevels ; i++) {
1091 int lod_w = (width >> i) ? : 1;
1092 int lod_h = (height >> i) ? : 1;
1093 int error = createTextureSurface(c, &surface, &size,
1094 i, format, type, lod_w, lod_h);
1095 if (error) {
1096 ogles_error(c, error);
1097 return;
1098 }
1099 decodePalette4(data, i, width, height,
1100 surface->data, surface->stride, internalformat);
1101 }
1102}
1103
1104
1105void glTexImage2D(
1106 GLenum target, GLint level, GLint internalformat,
1107 GLsizei width, GLsizei height, GLint border,
1108 GLenum format, GLenum type, const GLvoid *pixels)
1109{
1110 ogles_context_t* c = ogles_context_t::get();
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001111 if (target != GL_TEXTURE_2D) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001112 ogles_error(c, GL_INVALID_ENUM);
1113 return;
1114 }
1115 if (width<0 || height<0 || border!=0 || level < 0) {
1116 ogles_error(c, GL_INVALID_VALUE);
1117 return;
1118 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001119 if (format != (GLenum)internalformat) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001120 ogles_error(c, GL_INVALID_OPERATION);
1121 return;
1122 }
1123 if (validFormatType(c, format, type)) {
1124 return;
1125 }
1126
1127 int32_t size = 0;
1128 GGLSurface* surface = 0;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001129 int error = createTextureSurface(c, &surface, &size,
1130 level, format, type, width, height);
1131 if (error) {
1132 ogles_error(c, error);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001133 return;
1134 }
1135
1136 if (pixels) {
1137 const int32_t formatIdx = convertGLPixelFormat(format, type);
1138 const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
1139 const int32_t align = c->textures.unpackAlignment-1;
1140 const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
1141 const size_t size = bpr * height;
1142 const int32_t stride = bpr / pixelFormat.size;
1143
1144 GGLSurface userSurface;
1145 userSurface.version = sizeof(userSurface);
1146 userSurface.width = width;
1147 userSurface.height = height;
1148 userSurface.stride = stride;
1149 userSurface.format = formatIdx;
1150 userSurface.compressedFormat = 0;
1151 userSurface.data = (GLubyte*)pixels;
1152
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001153 int err = copyPixels(c, *surface, 0, 0, userSurface, 0, 0, width, height);
1154 if (err) {
1155 ogles_error(c, err);
1156 return;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001157 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001158 generateMipmap(c, level);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001159 }
1160}
1161
1162// ----------------------------------------------------------------------------
1163
1164void glCompressedTexSubImage2D(
1165 GLenum target, GLint level, GLint xoffset,
1166 GLint yoffset, GLsizei width, GLsizei height,
1167 GLenum format, GLsizei imageSize,
1168 const GLvoid *data)
1169{
1170 ogles_context_t* c = ogles_context_t::get();
1171 ogles_error(c, GL_INVALID_ENUM);
1172}
1173
1174void glTexSubImage2D(
1175 GLenum target, GLint level, GLint xoffset,
1176 GLint yoffset, GLsizei width, GLsizei height,
1177 GLenum format, GLenum type, const GLvoid *pixels)
1178{
1179 ogles_context_t* c = ogles_context_t::get();
1180 if (target != GL_TEXTURE_2D) {
1181 ogles_error(c, GL_INVALID_ENUM);
1182 return;
1183 }
1184 if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) {
1185 ogles_error(c, GL_INVALID_VALUE);
1186 return;
1187 }
1188 if (validFormatType(c, format, type)) {
1189 return;
1190 }
1191
1192 // find out which texture is bound to the current unit
1193 const int active = c->textures.active;
1194 EGLTextureObject* tex = c->textures.tmu[active].texture;
1195 const GGLSurface& surface(tex->mip(level));
1196
1197 if (!tex->internalformat || tex->direct) {
1198 ogles_error(c, GL_INVALID_OPERATION);
1199 return;
1200 }
1201 if ((xoffset + width > GLsizei(surface.width)) ||
1202 (yoffset + height > GLsizei(surface.height))) {
1203 ogles_error(c, GL_INVALID_VALUE);
1204 return;
1205 }
1206 if (!width || !height) {
1207 return; // okay, but no-op.
1208 }
1209
1210 // figure out the size we need as well as the stride
1211 const int32_t formatIdx = convertGLPixelFormat(format, type);
1212 if (formatIdx == 0) { // we don't know what to do with this
1213 ogles_error(c, GL_INVALID_OPERATION);
1214 return;
1215 }
1216
1217 const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
1218 const int32_t align = c->textures.unpackAlignment-1;
1219 const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
1220 const size_t size = bpr * height;
1221 const int32_t stride = bpr / pixelFormat.size;
1222 GGLSurface userSurface;
1223 userSurface.version = sizeof(userSurface);
1224 userSurface.width = width;
1225 userSurface.height = height;
1226 userSurface.stride = stride;
1227 userSurface.format = formatIdx;
1228 userSurface.compressedFormat = 0;
1229 userSurface.data = (GLubyte*)pixels;
1230
1231 int err = copyPixels(c,
1232 surface, xoffset, yoffset,
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001233 userSurface, 0, 0, width, height);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001234 if (err) {
1235 ogles_error(c, err);
1236 return;
1237 }
1238
1239 generateMipmap(c, level);
1240
1241 // since we only changed the content of the texture, we don't need
1242 // to call bindTexture on the main rasterizer.
1243}
1244
1245// ----------------------------------------------------------------------------
1246
1247void glCopyTexImage2D(
1248 GLenum target, GLint level, GLenum internalformat,
1249 GLint x, GLint y, GLsizei width, GLsizei height,
1250 GLint border)
1251{
1252 ogles_context_t* c = ogles_context_t::get();
1253 if (target != GL_TEXTURE_2D) {
1254 ogles_error(c, GL_INVALID_ENUM);
1255 return;
1256 }
1257 if (internalformat<GL_ALPHA || internalformat>GL_LUMINANCE_ALPHA) {
1258 ogles_error(c, GL_INVALID_ENUM);
1259 return;
1260 }
1261 if (width<0 || height<0 || border!=0 || level<0) {
1262 ogles_error(c, GL_INVALID_VALUE);
1263 return;
1264 }
1265
1266 GLenum format = 0;
1267 GLenum type = GL_UNSIGNED_BYTE;
1268 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
1269 const int cbFormatIdx = cbSurface.format;
1270 switch (cbFormatIdx) {
1271 case GGL_PIXEL_FORMAT_RGB_565:
1272 type = GL_UNSIGNED_SHORT_5_6_5;
1273 break;
1274 case GGL_PIXEL_FORMAT_RGBA_5551:
1275 type = GL_UNSIGNED_SHORT_5_5_5_1;
1276 break;
1277 case GGL_PIXEL_FORMAT_RGBA_4444:
1278 type = GL_UNSIGNED_SHORT_4_4_4_4;
1279 break;
1280 }
1281 switch (internalformat) {
1282 case GL_ALPHA:
1283 case GL_LUMINANCE_ALPHA:
1284 case GL_LUMINANCE:
1285 type = GL_UNSIGNED_BYTE;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001286 break;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001287 }
1288
1289 // figure out the format to use for the new texture
1290 switch (cbFormatIdx) {
1291 case GGL_PIXEL_FORMAT_RGBA_8888:
1292 case GGL_PIXEL_FORMAT_A_8:
1293 case GGL_PIXEL_FORMAT_RGBA_5551:
1294 case GGL_PIXEL_FORMAT_RGBA_4444:
1295 format = internalformat;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001296 break;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001297 case GGL_PIXEL_FORMAT_RGBX_8888:
1298 case GGL_PIXEL_FORMAT_RGB_888:
1299 case GGL_PIXEL_FORMAT_RGB_565:
1300 case GGL_PIXEL_FORMAT_L_8:
1301 switch (internalformat) {
1302 case GL_LUMINANCE:
1303 case GL_RGB:
1304 format = internalformat;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001305 break;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001306 }
1307 break;
1308 }
1309
1310 if (format == 0) {
1311 // invalid combination
1312 ogles_error(c, GL_INVALID_ENUM);
1313 return;
1314 }
1315
1316 // create the new texture...
1317 int32_t size;
1318 GGLSurface* surface;
1319 int error = createTextureSurface(c, &surface, &size,
1320 level, format, type, width, height);
1321 if (error) {
1322 ogles_error(c, error);
1323 return;
1324 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001325
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001326 // The bottom row is stored first in textures
1327 GGLSurface txSurface(*surface);
1328 txSurface.stride = -txSurface.stride;
1329
1330 // (x,y) is the lower-left corner of colorBuffer
1331 y = cbSurface.height - (y + height);
1332
1333 int err = copyPixels(c,
1334 txSurface, 0, 0,
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001335 cbSurface, x, y, cbSurface.width, cbSurface.height);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001336 if (err) {
1337 ogles_error(c, err);
1338 }
1339
1340 generateMipmap(c, level);
1341}
1342
1343void glCopyTexSubImage2D(
1344 GLenum target, GLint level, GLint xoffset, GLint yoffset,
1345 GLint x, GLint y, GLsizei width, GLsizei height)
1346{
1347 ogles_context_t* c = ogles_context_t::get();
1348 if (target != GL_TEXTURE_2D) {
1349 ogles_error(c, GL_INVALID_ENUM);
1350 return;
1351 }
1352 if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) {
1353 ogles_error(c, GL_INVALID_VALUE);
1354 return;
1355 }
1356 if (!width || !height) {
1357 return; // okay, but no-op.
1358 }
1359
1360 // find out which texture is bound to the current unit
1361 const int active = c->textures.active;
1362 EGLTextureObject* tex = c->textures.tmu[active].texture;
1363 const GGLSurface& surface(tex->mip(level));
1364
1365 if (!tex->internalformat) {
1366 ogles_error(c, GL_INVALID_OPERATION);
1367 return;
1368 }
1369 if ((xoffset + width > GLsizei(surface.width)) ||
1370 (yoffset + height > GLsizei(surface.height))) {
1371 ogles_error(c, GL_INVALID_VALUE);
1372 return;
1373 }
1374
1375 // The bottom row is stored first in textures
1376 GGLSurface txSurface(surface);
1377 txSurface.stride = -txSurface.stride;
1378
1379 // (x,y) is the lower-left corner of colorBuffer
1380 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
1381 y = cbSurface.height - (y + height);
1382
1383 int err = copyPixels(c,
1384 surface, xoffset, yoffset,
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001385 cbSurface, x, y, width, height);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001386 if (err) {
1387 ogles_error(c, err);
1388 return;
1389 }
1390
1391 generateMipmap(c, level);
1392}
1393
1394void glReadPixels(
1395 GLint x, GLint y, GLsizei width, GLsizei height,
1396 GLenum format, GLenum type, GLvoid *pixels)
1397{
1398 ogles_context_t* c = ogles_context_t::get();
1399 if ((format != GL_RGBA) && (format != GL_RGB)) {
1400 ogles_error(c, GL_INVALID_ENUM);
1401 return;
1402 }
1403 if ((type != GL_UNSIGNED_BYTE) && (type != GL_UNSIGNED_SHORT_5_6_5)) {
1404 ogles_error(c, GL_INVALID_ENUM);
1405 return;
1406 }
1407 if (width<0 || height<0) {
1408 ogles_error(c, GL_INVALID_VALUE);
1409 return;
1410 }
1411 if (x<0 || x<0) {
1412 ogles_error(c, GL_INVALID_VALUE);
1413 return;
1414 }
1415
1416 int32_t formatIdx = GGL_PIXEL_FORMAT_NONE;
1417 if ((format == GL_RGBA) && (type == GL_UNSIGNED_BYTE)) {
1418 formatIdx = GGL_PIXEL_FORMAT_RGBA_8888;
1419 } else if ((format == GL_RGB) && (type == GL_UNSIGNED_SHORT_5_6_5)) {
1420 formatIdx = GGL_PIXEL_FORMAT_RGB_565;
1421 } else {
1422 ogles_error(c, GL_INVALID_OPERATION);
1423 return;
1424 }
1425
1426 const GGLSurface& readSurface = c->rasterizer.state.buffers.read.s;
1427 if ((x+width > GLint(readSurface.width)) ||
1428 (y+height > GLint(readSurface.height))) {
1429 ogles_error(c, GL_INVALID_VALUE);
1430 return;
1431 }
1432
1433 const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
1434 const int32_t align = c->textures.packAlignment-1;
1435 const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
1436 const int32_t stride = bpr / pixelFormat.size;
1437
1438 GGLSurface userSurface;
1439 userSurface.version = sizeof(userSurface);
1440 userSurface.width = width;
1441 userSurface.height = height;
1442 userSurface.stride = -stride; // bottom row is transfered first
1443 userSurface.format = formatIdx;
1444 userSurface.compressedFormat = 0;
1445 userSurface.data = (GLubyte*)pixels;
1446
1447 // use pixel-flinger to handle all the conversions
1448 GGLContext* ggl = getRasterizer(c);
1449 if (!ggl) {
1450 // the only reason this would fail is because we ran out of memory
1451 ogles_error(c, GL_OUT_OF_MEMORY);
1452 return;
1453 }
1454
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001455 ggl->colorBuffer(ggl, &userSurface); // destination is user buffer
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001456 ggl->bindTexture(ggl, &readSurface); // source is read-buffer
1457 ggl->texCoord2i(ggl, x, readSurface.height - (y + height));
1458 ggl->recti(ggl, 0, 0, width, height);
1459}
1460
1461// ----------------------------------------------------------------------------
1462#if 0
1463#pragma mark -
1464#pragma mark DrawTexture Extension
1465#endif
1466
1467void glDrawTexsvOES(const GLshort* coords) {
1468 ogles_context_t* c = ogles_context_t::get();
1469 drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
1470}
1471void glDrawTexivOES(const GLint* coords) {
1472 ogles_context_t* c = ogles_context_t::get();
1473 drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
1474}
1475void glDrawTexsOES(GLshort x , GLshort y, GLshort z, GLshort w, GLshort h) {
1476 ogles_context_t* c = ogles_context_t::get();
1477 drawTexiOES(x, y, z, w, h, c);
1478}
1479void glDrawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h) {
1480 ogles_context_t* c = ogles_context_t::get();
1481 drawTexiOES(x, y, z, w, h, c);
1482}
1483
1484void glDrawTexfvOES(const GLfloat* coords) {
1485 ogles_context_t* c = ogles_context_t::get();
1486 drawTexxOES(
1487 gglFloatToFixed(coords[0]),
1488 gglFloatToFixed(coords[1]),
1489 gglFloatToFixed(coords[2]),
1490 gglFloatToFixed(coords[3]),
1491 gglFloatToFixed(coords[4]),
1492 c);
1493}
1494void glDrawTexxvOES(const GLfixed* coords) {
1495 ogles_context_t* c = ogles_context_t::get();
1496 drawTexxOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
1497}
1498void glDrawTexfOES(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h){
1499 ogles_context_t* c = ogles_context_t::get();
1500 drawTexxOES(
1501 gglFloatToFixed(x), gglFloatToFixed(y), gglFloatToFixed(z),
1502 gglFloatToFixed(w), gglFloatToFixed(h),
1503 c);
1504}
1505void glDrawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h) {
1506 ogles_context_t* c = ogles_context_t::get();
1507 drawTexxOES(x, y, z, w, h, c);
1508}
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001509
1510// ----------------------------------------------------------------------------
1511#if 0
1512#pragma mark -
1513#pragma mark EGL Image Extension
1514#endif
1515
1516void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
1517{
1518 ogles_context_t* c = ogles_context_t::get();
1519 if (target != GL_TEXTURE_2D) {
1520 ogles_error(c, GL_INVALID_ENUM);
1521 return;
1522 }
1523
1524 android_native_buffer_t* native_buffer = (android_native_buffer_t*)image;
1525 if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) {
1526 ogles_error(c, GL_INVALID_VALUE);
1527 return;
1528 }
1529 if (native_buffer->common.version != sizeof(android_native_buffer_t)) {
1530 ogles_error(c, GL_INVALID_VALUE);
1531 return;
1532 }
1533
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001534 // bind it to the texture unit
1535 sp<EGLTextureObject> tex = getAndBindActiveTextureObject(c);
Mathias Agopian0926f502009-05-04 14:17:04 -07001536 tex->setImage(native_buffer);
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001537
1538 /*
1539 * Here an implementation can retrieve the buffer_handle_t of this buffer
1540 * which gives it access to an arbitrary-defined kernel resource
1541 * (or anything else for that matter).
1542 * There needs to be an intimate knowledge between GLES and buffer_handle_t,
1543 * so make sure to validate the handle before using it.
1544 * Typically, buffer_handle_t comes from the gralloc HAL which is provided
1545 * by the implementor of GLES.
1546 *
1547 */
1548#ifdef LIBAGL_USE_GRALLOC_COPYBITS
1549 tex->copybits_fd = -1;
1550 buffer_handle_t handle;
1551 if (native_buffer->getHandle(native_buffer, &handle) == 0) {
1552 private_handle_t* hand;
1553 if ((hand = private_handle_t::dynamicCast(handle)) != NULL) {
1554 if (hand->usesPhysicallyContiguousMemory()) {
1555 tex->copybits_fd = hand->fd;
1556 }
1557 }
1558 }
1559#endif // LIBAGL_USE_GRALLOC_COPYBITS
1560}
1561
1562void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
1563{
1564}