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