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