blob: 0211208e2f4a2da48e6f91c284e4d2bea9afcafb [file] [log] [blame]
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001/* libs/opengles/texture.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
Mathias Agopian076b1cc2009-04-10 14:24:30 -07005** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08008**
Mathias Agopian076b1cc2009-04-10 14:24:30 -07009** http://www.apache.org/licenses/LICENSE-2.0
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080010**
Mathias Agopian076b1cc2009-04-10 14:24:30 -070011** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080015** limitations under the License.
16*/
17
18#include <stdio.h>
19#include <stdlib.h>
20#include "context.h"
21#include "fp.h"
22#include "state.h"
23#include "texture.h"
24#include "TextureObjectManager.h"
25
Mathias Agopian7189c002009-05-05 18:11:11 -070026#include <ui/egl/android_natives.h>
Mathias Agopian076b1cc2009-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 Projectedbf3b62009-03-03 19:31:44 -080033namespace android {
34
35// ----------------------------------------------------------------------------
36
37static void bindTextureTmu(
38 ogles_context_t* c, int tmu, GLuint texture, const sp<EGLTextureObject>& tex);
39
40static __attribute__((noinline))
41void generateMipmap(ogles_context_t* c, GLint level);
42
43// ----------------------------------------------------------------------------
44
45#if 0
46#pragma mark -
47#pragma mark Init
48#endif
49
50void ogles_init_texture(ogles_context_t* c)
51{
52 c->textures.packAlignment = 4;
53 c->textures.unpackAlignment = 4;
54
55 // each context has a default named (0) texture (not shared)
56 c->textures.defaultTexture = new EGLTextureObject();
57 c->textures.defaultTexture->incStrong(c);
Mathias Agopian076b1cc2009-04-10 14:24:30 -070058
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080059 // bind the default texture to each texture unit
60 for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
61 bindTextureTmu(c, i, 0, c->textures.defaultTexture);
62 memset(c->current.texture[i].v, 0, sizeof(vec4_t));
63 c->current.texture[i].Q = 0x10000;
64 }
65}
66
67void ogles_uninit_texture(ogles_context_t* c)
68{
69 if (c->textures.ggl)
70 gglUninit(c->textures.ggl);
71 c->textures.defaultTexture->decStrong(c);
72 for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
73 if (c->textures.tmu[i].texture)
74 c->textures.tmu[i].texture->decStrong(c);
75 }
76}
77
78static __attribute__((noinline))
79void validate_tmu(ogles_context_t* c, int i)
80{
81 texture_unit_t& u(c->textures.tmu[i]);
82 if (u.dirty) {
83 u.dirty = 0;
84 c->rasterizer.procs.activeTexture(c, i);
85 c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
86 c->rasterizer.procs.texGeni(c, GGL_S,
87 GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC);
88 c->rasterizer.procs.texGeni(c, GGL_T,
89 GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC);
90 c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
91 GGL_TEXTURE_WRAP_S, u.texture->wraps);
92 c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
93 GGL_TEXTURE_WRAP_T, u.texture->wrapt);
94 c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
95 GGL_TEXTURE_MIN_FILTER, u.texture->min_filter);
96 c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
97 GGL_TEXTURE_MAG_FILTER, u.texture->mag_filter);
98
99 // disable this texture unit if it's not complete
100 if (!u.texture->isComplete()) {
101 c->rasterizer.procs.disable(c, GGL_TEXTURE_2D);
102 }
103 }
104}
105
Mathias Agopian0926f502009-05-04 14:17:04 -0700106void ogles_validate_texture(ogles_context_t* c)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800107{
108 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
109 if (c->rasterizer.state.texture[i].enable)
110 validate_tmu(c, i);
111 }
112 c->rasterizer.procs.activeTexture(c, c->textures.active);
113}
114
115static
116void invalidate_texture(ogles_context_t* c, int tmu, uint8_t flags = 0xFF) {
117 c->textures.tmu[tmu].dirty = flags;
118}
119
Mathias Agopian0926f502009-05-04 14:17:04 -0700120/*
121 * If the active textures are EGLImage, they need to be locked before
122 * they can be used.
123 *
124 * FIXME: code below is far from being optimal
125 *
126 */
127
128void ogles_lock_textures(ogles_context_t* c)
129{
130 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
131 if (c->rasterizer.state.texture[i].enable) {
132 texture_unit_t& u(c->textures.tmu[i]);
133 android_native_buffer_t* native_buffer = u.texture->buffer;
134 if (native_buffer) {
135 c->rasterizer.procs.activeTexture(c, i);
136 hw_module_t const* pModule;
137 if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule))
138 continue;
139
140 gralloc_module_t const* module =
141 reinterpret_cast<gralloc_module_t const*>(pModule);
Mathias Agopian21c59d02009-05-05 00:59:23 -0700142
Mathias Agopiane71212b2009-05-05 00:37:46 -0700143 void* vaddr;
Mathias Agopian21c59d02009-05-05 00:59:23 -0700144 int err = module->lock(module, native_buffer->handle,
Mathias Agopian0926f502009-05-04 14:17:04 -0700145 GRALLOC_USAGE_SW_READ_OFTEN,
146 0, 0, native_buffer->width, native_buffer->height,
Mathias Agopiane71212b2009-05-05 00:37:46 -0700147 &vaddr);
Mathias Agopian0926f502009-05-04 14:17:04 -0700148
Mathias Agopiane71212b2009-05-05 00:37:46 -0700149 u.texture->setImageBits(vaddr);
Mathias Agopian0926f502009-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 Agopian21c59d02009-05-05 00:59:23 -0700170
171 module->unlock(module, native_buffer->handle);
Mathias Agopian0926f502009-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 Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700325 // 0 is our local texture object, not shared with anyone.
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700343 invalidate_texture(c, active);
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700352
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700380
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700600
601 EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture;
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700651
652static void drawTexxOESImp(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800653 ogles_context_t* c)
654{
Mathias Agopian0926f502009-05-04 14:17:04 -0700655 ogles_lock_textures(c);
656
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700679 EGLTextureObject* textureObject = u.texture;
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700710 c->rasterizer.procs.recti(c,
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800711 gglFixedToIntRound(x),
712 gglFixedToIntRound(y),
713 gglFixedToIntRound(x)+w,
714 gglFixedToIntRound(y)+h);
Mathias Agopian0926f502009-05-04 14:17:04 -0700715
716 ogles_unlock_textures(c);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800717}
718
Mathias Agopian076b1cc2009-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 Projectedbf3b62009-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 Agopian076b1cc2009-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 Projectedbf3b62009-03-03 19:31:44 -0800749 const int tmu = 0;
750 texture_unit_t& u(c->textures.tmu[tmu]);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700751 EGLTextureObject* textureObject = u.texture;
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700756#ifndef LIBAGL_USE_GRALLOC_COPYBITS
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800757 if ((w|h) <= 0) return; // quickly reject empty rects
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700758#endif
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700774
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700781
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700789 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800790
Mathias Agopian0926f502009-05-04 14:17:04 -0700791 ogles_lock_textures(c);
792
The Android Open Source Projectedbf3b62009-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 Agopian0926f502009-05-04 14:17:04 -0700803
804 ogles_unlock_textures(c);
805
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800806 return;
807 }
808 }
809
810slow_case:
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700811 drawTexxOESImp(
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700849 sp<EGLTextureObject> tex;
The Android Open Source Projectedbf3b62009-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 Agopian076b1cc2009-04-10 14:24:30 -0700937 }
The Android Open Source Projectedbf3b62009-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:
1000 ogles_error(c, GL_INVALID_ENUM);
1001 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
1019// ----------------------------------------------------------------------------
1020#if 0
1021#pragma mark -
1022#endif
1023
1024void glCompressedTexImage2D(
1025 GLenum target, GLint level, GLenum internalformat,
1026 GLsizei width, GLsizei height, GLint border,
1027 GLsizei imageSize, const GLvoid *data)
1028{
1029 ogles_context_t* c = ogles_context_t::get();
1030 if (target != GL_TEXTURE_2D) {
1031 ogles_error(c, GL_INVALID_ENUM);
1032 return;
1033 }
1034 if ((internalformat < GL_PALETTE4_RGB8_OES ||
1035 internalformat > GL_PALETTE8_RGB5_A1_OES)) {
1036 ogles_error(c, GL_INVALID_ENUM);
1037 return;
1038 }
1039 if (width<0 || height<0 || border!=0) {
1040 ogles_error(c, GL_INVALID_VALUE);
1041 return;
1042 }
1043
1044 // "uncompress" the texture since pixelflinger doesn't support
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001045 // any compressed texture format natively.
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001046 GLenum format;
1047 GLenum type;
1048 switch (internalformat) {
1049 case GL_PALETTE8_RGB8_OES:
1050 case GL_PALETTE4_RGB8_OES:
1051 format = GL_RGB;
1052 type = GL_UNSIGNED_BYTE;
1053 break;
1054 case GL_PALETTE8_RGBA8_OES:
1055 case GL_PALETTE4_RGBA8_OES:
1056 format = GL_RGBA;
1057 type = GL_UNSIGNED_BYTE;
1058 break;
1059 case GL_PALETTE8_R5_G6_B5_OES:
1060 case GL_PALETTE4_R5_G6_B5_OES:
1061 format = GL_RGB;
1062 type = GL_UNSIGNED_SHORT_5_6_5;
1063 break;
1064 case GL_PALETTE8_RGBA4_OES:
1065 case GL_PALETTE4_RGBA4_OES:
1066 format = GL_RGBA;
1067 type = GL_UNSIGNED_SHORT_4_4_4_4;
1068 break;
1069 case GL_PALETTE8_RGB5_A1_OES:
1070 case GL_PALETTE4_RGB5_A1_OES:
1071 format = GL_RGBA;
1072 type = GL_UNSIGNED_SHORT_5_5_5_1;
1073 break;
1074 default:
1075 ogles_error(c, GL_INVALID_ENUM);
1076 return;
1077 }
1078
1079 if (!data || !width || !height) {
1080 // unclear if this is an error or not...
1081 return;
1082 }
1083
1084 int32_t size;
1085 GGLSurface* surface;
1086 // all mipmap levels are specified at once.
1087 const int numLevels = level<0 ? -level : 1;
1088 for (int i=0 ; i<numLevels ; i++) {
1089 int lod_w = (width >> i) ? : 1;
1090 int lod_h = (height >> i) ? : 1;
1091 int error = createTextureSurface(c, &surface, &size,
1092 i, format, type, lod_w, lod_h);
1093 if (error) {
1094 ogles_error(c, error);
1095 return;
1096 }
1097 decodePalette4(data, i, width, height,
1098 surface->data, surface->stride, internalformat);
1099 }
1100}
1101
1102
1103void glTexImage2D(
1104 GLenum target, GLint level, GLint internalformat,
1105 GLsizei width, GLsizei height, GLint border,
1106 GLenum format, GLenum type, const GLvoid *pixels)
1107{
1108 ogles_context_t* c = ogles_context_t::get();
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001109 if (target != GL_TEXTURE_2D) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001110 ogles_error(c, GL_INVALID_ENUM);
1111 return;
1112 }
1113 if (width<0 || height<0 || border!=0 || level < 0) {
1114 ogles_error(c, GL_INVALID_VALUE);
1115 return;
1116 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001117 if (format != (GLenum)internalformat) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001118 ogles_error(c, GL_INVALID_OPERATION);
1119 return;
1120 }
1121 if (validFormatType(c, format, type)) {
1122 return;
1123 }
1124
1125 int32_t size = 0;
1126 GGLSurface* surface = 0;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001127 int error = createTextureSurface(c, &surface, &size,
1128 level, format, type, width, height);
1129 if (error) {
1130 ogles_error(c, error);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001131 return;
1132 }
1133
1134 if (pixels) {
1135 const int32_t formatIdx = convertGLPixelFormat(format, type);
1136 const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
1137 const int32_t align = c->textures.unpackAlignment-1;
1138 const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
1139 const size_t size = bpr * height;
1140 const int32_t stride = bpr / pixelFormat.size;
1141
1142 GGLSurface userSurface;
1143 userSurface.version = sizeof(userSurface);
1144 userSurface.width = width;
1145 userSurface.height = height;
1146 userSurface.stride = stride;
1147 userSurface.format = formatIdx;
1148 userSurface.compressedFormat = 0;
1149 userSurface.data = (GLubyte*)pixels;
1150
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001151 int err = copyPixels(c, *surface, 0, 0, userSurface, 0, 0, width, height);
1152 if (err) {
1153 ogles_error(c, err);
1154 return;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001155 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001156 generateMipmap(c, level);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001157 }
1158}
1159
1160// ----------------------------------------------------------------------------
1161
1162void glCompressedTexSubImage2D(
1163 GLenum target, GLint level, GLint xoffset,
1164 GLint yoffset, GLsizei width, GLsizei height,
1165 GLenum format, GLsizei imageSize,
1166 const GLvoid *data)
1167{
1168 ogles_context_t* c = ogles_context_t::get();
1169 ogles_error(c, GL_INVALID_ENUM);
1170}
1171
1172void glTexSubImage2D(
1173 GLenum target, GLint level, GLint xoffset,
1174 GLint yoffset, GLsizei width, GLsizei height,
1175 GLenum format, GLenum type, const GLvoid *pixels)
1176{
1177 ogles_context_t* c = ogles_context_t::get();
1178 if (target != GL_TEXTURE_2D) {
1179 ogles_error(c, GL_INVALID_ENUM);
1180 return;
1181 }
1182 if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) {
1183 ogles_error(c, GL_INVALID_VALUE);
1184 return;
1185 }
1186 if (validFormatType(c, format, type)) {
1187 return;
1188 }
1189
1190 // find out which texture is bound to the current unit
1191 const int active = c->textures.active;
1192 EGLTextureObject* tex = c->textures.tmu[active].texture;
1193 const GGLSurface& surface(tex->mip(level));
1194
1195 if (!tex->internalformat || tex->direct) {
1196 ogles_error(c, GL_INVALID_OPERATION);
1197 return;
1198 }
1199 if ((xoffset + width > GLsizei(surface.width)) ||
1200 (yoffset + height > GLsizei(surface.height))) {
1201 ogles_error(c, GL_INVALID_VALUE);
1202 return;
1203 }
1204 if (!width || !height) {
1205 return; // okay, but no-op.
1206 }
1207
1208 // figure out the size we need as well as the stride
1209 const int32_t formatIdx = convertGLPixelFormat(format, type);
1210 if (formatIdx == 0) { // we don't know what to do with this
1211 ogles_error(c, GL_INVALID_OPERATION);
1212 return;
1213 }
1214
1215 const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
1216 const int32_t align = c->textures.unpackAlignment-1;
1217 const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
1218 const size_t size = bpr * height;
1219 const int32_t stride = bpr / pixelFormat.size;
1220 GGLSurface userSurface;
1221 userSurface.version = sizeof(userSurface);
1222 userSurface.width = width;
1223 userSurface.height = height;
1224 userSurface.stride = stride;
1225 userSurface.format = formatIdx;
1226 userSurface.compressedFormat = 0;
1227 userSurface.data = (GLubyte*)pixels;
1228
1229 int err = copyPixels(c,
1230 surface, xoffset, yoffset,
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001231 userSurface, 0, 0, width, height);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001232 if (err) {
1233 ogles_error(c, err);
1234 return;
1235 }
1236
1237 generateMipmap(c, level);
1238
1239 // since we only changed the content of the texture, we don't need
1240 // to call bindTexture on the main rasterizer.
1241}
1242
1243// ----------------------------------------------------------------------------
1244
1245void glCopyTexImage2D(
1246 GLenum target, GLint level, GLenum internalformat,
1247 GLint x, GLint y, GLsizei width, GLsizei height,
1248 GLint border)
1249{
1250 ogles_context_t* c = ogles_context_t::get();
1251 if (target != GL_TEXTURE_2D) {
1252 ogles_error(c, GL_INVALID_ENUM);
1253 return;
1254 }
1255 if (internalformat<GL_ALPHA || internalformat>GL_LUMINANCE_ALPHA) {
1256 ogles_error(c, GL_INVALID_ENUM);
1257 return;
1258 }
1259 if (width<0 || height<0 || border!=0 || level<0) {
1260 ogles_error(c, GL_INVALID_VALUE);
1261 return;
1262 }
1263
1264 GLenum format = 0;
1265 GLenum type = GL_UNSIGNED_BYTE;
1266 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
1267 const int cbFormatIdx = cbSurface.format;
1268 switch (cbFormatIdx) {
1269 case GGL_PIXEL_FORMAT_RGB_565:
1270 type = GL_UNSIGNED_SHORT_5_6_5;
1271 break;
1272 case GGL_PIXEL_FORMAT_RGBA_5551:
1273 type = GL_UNSIGNED_SHORT_5_5_5_1;
1274 break;
1275 case GGL_PIXEL_FORMAT_RGBA_4444:
1276 type = GL_UNSIGNED_SHORT_4_4_4_4;
1277 break;
1278 }
1279 switch (internalformat) {
1280 case GL_ALPHA:
1281 case GL_LUMINANCE_ALPHA:
1282 case GL_LUMINANCE:
1283 type = GL_UNSIGNED_BYTE;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001284 break;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001285 }
1286
1287 // figure out the format to use for the new texture
1288 switch (cbFormatIdx) {
1289 case GGL_PIXEL_FORMAT_RGBA_8888:
1290 case GGL_PIXEL_FORMAT_A_8:
1291 case GGL_PIXEL_FORMAT_RGBA_5551:
1292 case GGL_PIXEL_FORMAT_RGBA_4444:
1293 format = internalformat;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001294 break;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001295 case GGL_PIXEL_FORMAT_RGBX_8888:
1296 case GGL_PIXEL_FORMAT_RGB_888:
1297 case GGL_PIXEL_FORMAT_RGB_565:
1298 case GGL_PIXEL_FORMAT_L_8:
1299 switch (internalformat) {
1300 case GL_LUMINANCE:
1301 case GL_RGB:
1302 format = internalformat;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001303 break;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001304 }
1305 break;
1306 }
1307
1308 if (format == 0) {
1309 // invalid combination
1310 ogles_error(c, GL_INVALID_ENUM);
1311 return;
1312 }
1313
1314 // create the new texture...
1315 int32_t size;
1316 GGLSurface* surface;
1317 int error = createTextureSurface(c, &surface, &size,
1318 level, format, type, width, height);
1319 if (error) {
1320 ogles_error(c, error);
1321 return;
1322 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001323
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001324 // The bottom row is stored first in textures
1325 GGLSurface txSurface(*surface);
1326 txSurface.stride = -txSurface.stride;
1327
1328 // (x,y) is the lower-left corner of colorBuffer
1329 y = cbSurface.height - (y + height);
1330
1331 int err = copyPixels(c,
1332 txSurface, 0, 0,
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001333 cbSurface, x, y, cbSurface.width, cbSurface.height);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001334 if (err) {
1335 ogles_error(c, err);
1336 }
1337
1338 generateMipmap(c, level);
1339}
1340
1341void glCopyTexSubImage2D(
1342 GLenum target, GLint level, GLint xoffset, GLint yoffset,
1343 GLint x, GLint y, GLsizei width, GLsizei height)
1344{
1345 ogles_context_t* c = ogles_context_t::get();
1346 if (target != GL_TEXTURE_2D) {
1347 ogles_error(c, GL_INVALID_ENUM);
1348 return;
1349 }
1350 if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) {
1351 ogles_error(c, GL_INVALID_VALUE);
1352 return;
1353 }
1354 if (!width || !height) {
1355 return; // okay, but no-op.
1356 }
1357
1358 // find out which texture is bound to the current unit
1359 const int active = c->textures.active;
1360 EGLTextureObject* tex = c->textures.tmu[active].texture;
1361 const GGLSurface& surface(tex->mip(level));
1362
1363 if (!tex->internalformat) {
1364 ogles_error(c, GL_INVALID_OPERATION);
1365 return;
1366 }
1367 if ((xoffset + width > GLsizei(surface.width)) ||
1368 (yoffset + height > GLsizei(surface.height))) {
1369 ogles_error(c, GL_INVALID_VALUE);
1370 return;
1371 }
1372
1373 // The bottom row is stored first in textures
1374 GGLSurface txSurface(surface);
1375 txSurface.stride = -txSurface.stride;
1376
1377 // (x,y) is the lower-left corner of colorBuffer
1378 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
1379 y = cbSurface.height - (y + height);
1380
1381 int err = copyPixels(c,
1382 surface, xoffset, yoffset,
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001383 cbSurface, x, y, width, height);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001384 if (err) {
1385 ogles_error(c, err);
1386 return;
1387 }
1388
1389 generateMipmap(c, level);
1390}
1391
1392void glReadPixels(
1393 GLint x, GLint y, GLsizei width, GLsizei height,
1394 GLenum format, GLenum type, GLvoid *pixels)
1395{
1396 ogles_context_t* c = ogles_context_t::get();
1397 if ((format != GL_RGBA) && (format != GL_RGB)) {
1398 ogles_error(c, GL_INVALID_ENUM);
1399 return;
1400 }
1401 if ((type != GL_UNSIGNED_BYTE) && (type != GL_UNSIGNED_SHORT_5_6_5)) {
1402 ogles_error(c, GL_INVALID_ENUM);
1403 return;
1404 }
1405 if (width<0 || height<0) {
1406 ogles_error(c, GL_INVALID_VALUE);
1407 return;
1408 }
1409 if (x<0 || x<0) {
1410 ogles_error(c, GL_INVALID_VALUE);
1411 return;
1412 }
1413
1414 int32_t formatIdx = GGL_PIXEL_FORMAT_NONE;
1415 if ((format == GL_RGBA) && (type == GL_UNSIGNED_BYTE)) {
1416 formatIdx = GGL_PIXEL_FORMAT_RGBA_8888;
1417 } else if ((format == GL_RGB) && (type == GL_UNSIGNED_SHORT_5_6_5)) {
1418 formatIdx = GGL_PIXEL_FORMAT_RGB_565;
1419 } else {
1420 ogles_error(c, GL_INVALID_OPERATION);
1421 return;
1422 }
1423
1424 const GGLSurface& readSurface = c->rasterizer.state.buffers.read.s;
1425 if ((x+width > GLint(readSurface.width)) ||
1426 (y+height > GLint(readSurface.height))) {
1427 ogles_error(c, GL_INVALID_VALUE);
1428 return;
1429 }
1430
1431 const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
1432 const int32_t align = c->textures.packAlignment-1;
1433 const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
1434 const int32_t stride = bpr / pixelFormat.size;
1435
1436 GGLSurface userSurface;
1437 userSurface.version = sizeof(userSurface);
1438 userSurface.width = width;
1439 userSurface.height = height;
1440 userSurface.stride = -stride; // bottom row is transfered first
1441 userSurface.format = formatIdx;
1442 userSurface.compressedFormat = 0;
1443 userSurface.data = (GLubyte*)pixels;
1444
1445 // use pixel-flinger to handle all the conversions
1446 GGLContext* ggl = getRasterizer(c);
1447 if (!ggl) {
1448 // the only reason this would fail is because we ran out of memory
1449 ogles_error(c, GL_OUT_OF_MEMORY);
1450 return;
1451 }
1452
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001453 ggl->colorBuffer(ggl, &userSurface); // destination is user buffer
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001454 ggl->bindTexture(ggl, &readSurface); // source is read-buffer
1455 ggl->texCoord2i(ggl, x, readSurface.height - (y + height));
1456 ggl->recti(ggl, 0, 0, width, height);
1457}
1458
1459// ----------------------------------------------------------------------------
1460#if 0
1461#pragma mark -
1462#pragma mark DrawTexture Extension
1463#endif
1464
1465void glDrawTexsvOES(const GLshort* coords) {
1466 ogles_context_t* c = ogles_context_t::get();
1467 drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
1468}
1469void glDrawTexivOES(const GLint* coords) {
1470 ogles_context_t* c = ogles_context_t::get();
1471 drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
1472}
1473void glDrawTexsOES(GLshort x , GLshort y, GLshort z, GLshort w, GLshort h) {
1474 ogles_context_t* c = ogles_context_t::get();
1475 drawTexiOES(x, y, z, w, h, c);
1476}
1477void glDrawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h) {
1478 ogles_context_t* c = ogles_context_t::get();
1479 drawTexiOES(x, y, z, w, h, c);
1480}
1481
1482void glDrawTexfvOES(const GLfloat* coords) {
1483 ogles_context_t* c = ogles_context_t::get();
1484 drawTexxOES(
1485 gglFloatToFixed(coords[0]),
1486 gglFloatToFixed(coords[1]),
1487 gglFloatToFixed(coords[2]),
1488 gglFloatToFixed(coords[3]),
1489 gglFloatToFixed(coords[4]),
1490 c);
1491}
1492void glDrawTexxvOES(const GLfixed* coords) {
1493 ogles_context_t* c = ogles_context_t::get();
1494 drawTexxOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
1495}
1496void glDrawTexfOES(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h){
1497 ogles_context_t* c = ogles_context_t::get();
1498 drawTexxOES(
1499 gglFloatToFixed(x), gglFloatToFixed(y), gglFloatToFixed(z),
1500 gglFloatToFixed(w), gglFloatToFixed(h),
1501 c);
1502}
1503void glDrawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h) {
1504 ogles_context_t* c = ogles_context_t::get();
1505 drawTexxOES(x, y, z, w, h, c);
1506}
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001507
1508// ----------------------------------------------------------------------------
1509#if 0
1510#pragma mark -
1511#pragma mark EGL Image Extension
1512#endif
1513
1514void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
1515{
1516 ogles_context_t* c = ogles_context_t::get();
1517 if (target != GL_TEXTURE_2D) {
1518 ogles_error(c, GL_INVALID_ENUM);
1519 return;
1520 }
1521
1522 android_native_buffer_t* native_buffer = (android_native_buffer_t*)image;
1523 if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) {
1524 ogles_error(c, GL_INVALID_VALUE);
1525 return;
1526 }
1527 if (native_buffer->common.version != sizeof(android_native_buffer_t)) {
1528 ogles_error(c, GL_INVALID_VALUE);
1529 return;
1530 }
1531
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001532 // bind it to the texture unit
1533 sp<EGLTextureObject> tex = getAndBindActiveTextureObject(c);
Mathias Agopian0926f502009-05-04 14:17:04 -07001534 tex->setImage(native_buffer);
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001535
1536 /*
1537 * Here an implementation can retrieve the buffer_handle_t of this buffer
1538 * which gives it access to an arbitrary-defined kernel resource
1539 * (or anything else for that matter).
1540 * There needs to be an intimate knowledge between GLES and buffer_handle_t,
1541 * so make sure to validate the handle before using it.
1542 * Typically, buffer_handle_t comes from the gralloc HAL which is provided
1543 * by the implementor of GLES.
1544 *
1545 */
1546#ifdef LIBAGL_USE_GRALLOC_COPYBITS
1547 tex->copybits_fd = -1;
Mathias Agopian21c59d02009-05-05 00:59:23 -07001548 private_handle_t* hand;
1549 if ((hand = private_handle_t::dynamicCast(native_buffer->handle)) != NULL) {
1550 if (hand->usesPhysicallyContiguousMemory()) {
1551 tex->copybits_fd = hand->fd;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001552 }
1553 }
1554#endif // LIBAGL_USE_GRALLOC_COPYBITS
1555}
1556
1557void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
1558{
1559}