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