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