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