1 /* libs/opengles/texture.cpp
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
5 ** 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
8 **
9 ** http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** 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
15 ** 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
26 #include <private/ui/android_natives_priv.h>
27
28 #ifdef LIBAGL_USE_GRALLOC_COPYBITS
29 #include "copybit.h"
30 #endif // LIBAGL_USE_GRALLOC_COPYBITS
31
32 namespace android {
33
34 // ----------------------------------------------------------------------------
35
36 static void bindTextureTmu(
37 ogles_context_t* c, int tmu, GLuint texture, const sp<EGLTextureObject>& tex);
38
39 static __attribute__((noinline))
40 void generateMipmap(ogles_context_t* c, GLint level);
41
42 // ----------------------------------------------------------------------------
43
44 #if 0
45 #pragma mark -
46 #pragma mark Init
47 #endif
48
ogles_init_texture(ogles_context_t * c)49 void 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);
57
58 // 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
ogles_uninit_texture(ogles_context_t * c)66 void 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
77 static __attribute__((noinline))
validate_tmu(ogles_context_t * c,int i)78 void 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
ogles_validate_texture(ogles_context_t * c)105 void ogles_validate_texture(ogles_context_t* c)
106 {
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
114 static
invalidate_texture(ogles_context_t * c,int tmu,uint8_t flags=0xFF)115 void invalidate_texture(ogles_context_t* c, int tmu, uint8_t flags = 0xFF) {
116 c->textures.tmu[tmu].dirty = flags;
117 }
118
119 /*
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
ogles_lock_textures(ogles_context_t * c)127 void 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);
141
142 void* vaddr;
143 int err = module->lock(module, native_buffer->handle,
144 GRALLOC_USAGE_SW_READ_OFTEN,
145 0, 0, native_buffer->width, native_buffer->height,
146 &vaddr);
147
148 u.texture->setImageBits(vaddr);
149 c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
150 }
151 }
152 }
153 }
154
ogles_unlock_textures(ogles_context_t * c)155 void 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);
169
170 module->unlock(module, native_buffer->handle);
171 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
179 // ----------------------------------------------------------------------------
180 #if 0
181 #pragma mark -
182 #pragma mark Format conversion
183 #endif
184
185 static 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
convertGLPixelFormat(GLint format,GLenum type)202 static 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
validFormatType(ogles_context_t * c,GLenum format,GLenum type)226 static 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
getRasterizer(ogles_context_t * c)251 GGLContext* 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
272 static __attribute__((noinline))
copyPixels(ogles_context_t * c,const GGLSurface & dst,GLint xoffset,GLint yoffset,const GGLSurface & src,GLint x,GLint y,GLsizei w,GLsizei h)273 int 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
311 static __attribute__((noinline))
getAndBindActiveTextureObject(ogles_context_t * c)312 sp<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) {
324 // 0 is our local texture object, not shared with anyone.
325 // 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;
342 invalidate_texture(c, active);
343 return tex;
344 }
345
bindTextureTmu(ogles_context_t * c,int tmu,GLuint texture,const sp<EGLTextureObject> & tex)346 void 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;
351
352 // 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
createTextureSurface(ogles_context_t * c,GGLSurface ** outSurface,int32_t * outSize,GLint level,GLenum format,GLenum type,GLsizei width,GLsizei height,GLenum compressedFormat=0)365 int 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 }
379
380 // 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
dataSizePalette4(int numLevels,int width,int height,int format)412 static size_t dataSizePalette4(int numLevels, int width, int height, int format)
413 {
414 int indexBits = 8;
415 int entrySize = 0;
416 switch (format) {
417 case GL_PALETTE4_RGB8_OES:
418 indexBits = 4;
419 /* FALLTHROUGH */
420 case GL_PALETTE8_RGB8_OES:
421 entrySize = 3;
422 break;
423
424 case GL_PALETTE4_RGBA8_OES:
425 indexBits = 4;
426 /* FALLTHROUGH */
427 case GL_PALETTE8_RGBA8_OES:
428 entrySize = 4;
429 break;
430
431 case GL_PALETTE4_R5_G6_B5_OES:
432 case GL_PALETTE4_RGBA4_OES:
433 case GL_PALETTE4_RGB5_A1_OES:
434 indexBits = 4;
435 /* FALLTHROUGH */
436 case GL_PALETTE8_R5_G6_B5_OES:
437 case GL_PALETTE8_RGBA4_OES:
438 case GL_PALETTE8_RGB5_A1_OES:
439 entrySize = 2;
440 break;
441 }
442
443 size_t size = (1 << indexBits) * entrySize; // palette size
444
445 for (int i=0 ; i< numLevels ; i++) {
446 int w = (width >> i) ? : 1;
447 int h = (height >> i) ? : 1;
448 int levelSize = h * ((w * indexBits) / 8) ? : 1;
449 size += levelSize;
450 }
451
452 return size;
453 }
454
decodePalette4(const GLvoid * data,int level,int width,int height,void * surface,int stride,int format)455 static void decodePalette4(const GLvoid *data, int level, int width, int height,
456 void *surface, int stride, int format)
457
458 {
459 int indexBits = 8;
460 int entrySize = 0;
461 switch (format) {
462 case GL_PALETTE4_RGB8_OES:
463 indexBits = 4;
464 /* FALLTHROUGH */
465 case GL_PALETTE8_RGB8_OES:
466 entrySize = 3;
467 break;
468
469 case GL_PALETTE4_RGBA8_OES:
470 indexBits = 4;
471 /* FALLTHROUGH */
472 case GL_PALETTE8_RGBA8_OES:
473 entrySize = 4;
474 break;
475
476 case GL_PALETTE4_R5_G6_B5_OES:
477 case GL_PALETTE4_RGBA4_OES:
478 case GL_PALETTE4_RGB5_A1_OES:
479 indexBits = 4;
480 /* FALLTHROUGH */
481 case GL_PALETTE8_R5_G6_B5_OES:
482 case GL_PALETTE8_RGBA4_OES:
483 case GL_PALETTE8_RGB5_A1_OES:
484 entrySize = 2;
485 break;
486 }
487
488 const int paletteSize = (1 << indexBits) * entrySize;
489
490 uint8_t const* pixels = (uint8_t *)data + paletteSize;
491 for (int i=0 ; i<level ; i++) {
492 int w = (width >> i) ? : 1;
493 int h = (height >> i) ? : 1;
494 pixels += h * ((w * indexBits) / 8);
495 }
496 width = (width >> level) ? : 1;
497 height = (height >> level) ? : 1;
498
499 if (entrySize == 2) {
500 uint8_t const* const palette = (uint8_t*)data;
501 for (int y=0 ; y<height ; y++) {
502 uint8_t* p = (uint8_t*)surface + y*stride*2;
503 if (indexBits == 8) {
504 for (int x=0 ; x<width ; x++) {
505 int index = 2 * (*pixels++);
506 *p++ = palette[index + 0];
507 *p++ = palette[index + 1];
508 }
509 } else {
510 for (int x=0 ; x<width ; x+=2) {
511 int v = *pixels++;
512 int index = 2 * (v >> 4);
513 *p++ = palette[index + 0];
514 *p++ = palette[index + 1];
515 if (x+1 < width) {
516 index = 2 * (v & 0xF);
517 *p++ = palette[index + 0];
518 *p++ = palette[index + 1];
519 }
520 }
521 }
522 }
523 } else if (entrySize == 3) {
524 uint8_t const* const palette = (uint8_t*)data;
525 for (int y=0 ; y<height ; y++) {
526 uint8_t* p = (uint8_t*)surface + y*stride*3;
527 if (indexBits == 8) {
528 for (int x=0 ; x<width ; x++) {
529 int index = 3 * (*pixels++);
530 *p++ = palette[index + 0];
531 *p++ = palette[index + 1];
532 *p++ = palette[index + 2];
533 }
534 } else {
535 for (int x=0 ; x<width ; x+=2) {
536 int v = *pixels++;
537 int index = 3 * (v >> 4);
538 *p++ = palette[index + 0];
539 *p++ = palette[index + 1];
540 *p++ = palette[index + 2];
541 if (x+1 < width) {
542 index = 3 * (v & 0xF);
543 *p++ = palette[index + 0];
544 *p++ = palette[index + 1];
545 *p++ = palette[index + 2];
546 }
547 }
548 }
549 }
550 } else if (entrySize == 4) {
551 uint8_t const* const palette = (uint8_t*)data;
552 for (int y=0 ; y<height ; y++) {
553 uint8_t* p = (uint8_t*)surface + y*stride*4;
554 if (indexBits == 8) {
555 for (int x=0 ; x<width ; x++) {
556 int index = 4 * (*pixels++);
557 *p++ = palette[index + 0];
558 *p++ = palette[index + 1];
559 *p++ = palette[index + 2];
560 *p++ = palette[index + 3];
561 }
562 } else {
563 for (int x=0 ; x<width ; x+=2) {
564 int v = *pixels++;
565 int index = 4 * (v >> 4);
566 *p++ = palette[index + 0];
567 *p++ = palette[index + 1];
568 *p++ = palette[index + 2];
569 *p++ = palette[index + 3];
570 if (x+1 < width) {
571 index = 4 * (v & 0xF);
572 *p++ = palette[index + 0];
573 *p++ = palette[index + 1];
574 *p++ = palette[index + 2];
575 *p++ = palette[index + 3];
576 }
577 }
578 }
579 }
580 }
581 }
582
583
584
585 static __attribute__((noinline))
set_depth_and_fog(ogles_context_t * c,GLint z)586 void set_depth_and_fog(ogles_context_t* c, GLint z)
587 {
588 const uint32_t enables = c->rasterizer.state.enables;
589 // we need to compute Zw
590 int32_t iterators[3];
591 iterators[1] = iterators[2] = 0;
592 GGLfixed Zw;
593 GGLfixed n = gglFloatToFixed(c->transforms.vpt.zNear);
594 GGLfixed f = gglFloatToFixed(c->transforms.vpt.zFar);
595 if (z<=0) Zw = n;
596 else if (z>=1) Zw = f;
597 else Zw = gglMulAddx(z, (f-n), n);
598 if (enables & GGL_ENABLE_FOG) {
599 // set up fog if needed...
600 iterators[0] = c->fog.fog(c, Zw);
601 c->rasterizer.procs.fogGrad3xv(c, iterators);
602 }
603 if (enables & GGL_ENABLE_DEPTH_TEST) {
604 // set up z-test if needed...
605 int32_t z = (Zw & ~(Zw>>31));
606 if (z >= 0x10000)
607 z = 0xFFFF;
608 iterators[0] = (z << 16) | z;
609 c->rasterizer.procs.zGrad3xv(c, iterators);
610 }
611 }
612
613 // ----------------------------------------------------------------------------
614 #if 0
615 #pragma mark -
616 #pragma mark Generate mimaps
617 #endif
618
619 extern status_t buildAPyramid(ogles_context_t* c, EGLTextureObject* tex);
620
generateMipmap(ogles_context_t * c,GLint level)621 void generateMipmap(ogles_context_t* c, GLint level)
622 {
623 if (level == 0) {
624 const int active = c->textures.active;
625 EGLTextureObject* tex = c->textures.tmu[active].texture;
626 if (tex->generate_mipmap) {
627 if (buildAPyramid(c, tex) != NO_ERROR) {
628 ogles_error(c, GL_OUT_OF_MEMORY);
629 return;
630 }
631 }
632 }
633 }
634
635
texParameterx(GLenum target,GLenum pname,GLfixed param,ogles_context_t * c)636 static void texParameterx(
637 GLenum target, GLenum pname, GLfixed param, ogles_context_t* c)
638 {
639 if (target != GL_TEXTURE_2D) {
640 ogles_error(c, GL_INVALID_ENUM);
641 return;
642 }
643
644 EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture;
645 switch (pname) {
646 case GL_TEXTURE_WRAP_S:
647 if ((param == GL_REPEAT) ||
648 (param == GL_CLAMP_TO_EDGE)) {
649 textureObject->wraps = param;
650 } else {
651 goto invalid_enum;
652 }
653 break;
654 case GL_TEXTURE_WRAP_T:
655 if ((param == GL_REPEAT) ||
656 (param == GL_CLAMP_TO_EDGE)) {
657 textureObject->wrapt = param;
658 } else {
659 goto invalid_enum;
660 }
661 break;
662 case GL_TEXTURE_MIN_FILTER:
663 if ((param == GL_NEAREST) ||
664 (param == GL_LINEAR) ||
665 (param == GL_NEAREST_MIPMAP_NEAREST) ||
666 (param == GL_LINEAR_MIPMAP_NEAREST) ||
667 (param == GL_NEAREST_MIPMAP_LINEAR) ||
668 (param == GL_LINEAR_MIPMAP_LINEAR)) {
669 textureObject->min_filter = param;
670 } else {
671 goto invalid_enum;
672 }
673 break;
674 case GL_TEXTURE_MAG_FILTER:
675 if ((param == GL_NEAREST) ||
676 (param == GL_LINEAR)) {
677 textureObject->mag_filter = param;
678 } else {
679 goto invalid_enum;
680 }
681 break;
682 case GL_GENERATE_MIPMAP:
683 textureObject->generate_mipmap = param;
684 break;
685 default:
686 invalid_enum:
687 ogles_error(c, GL_INVALID_ENUM);
688 return;
689 }
690 invalidate_texture(c, c->textures.active);
691 }
692
693
694
drawTexxOESImp(GLfixed x,GLfixed y,GLfixed z,GLfixed w,GLfixed h,ogles_context_t * c)695 static void drawTexxOESImp(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
696 ogles_context_t* c)
697 {
698 ogles_lock_textures(c);
699
700 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
701 y = gglIntToFixed(cbSurface.height) - (y + h);
702 w >>= FIXED_BITS;
703 h >>= FIXED_BITS;
704
705 // set up all texture units
706 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
707 if (!c->rasterizer.state.texture[i].enable)
708 continue;
709
710 int32_t texcoords[8];
711 texture_unit_t& u(c->textures.tmu[i]);
712
713 // validate this tmu (bind, wrap, filter)
714 validate_tmu(c, i);
715 // we CLAMP here, which works with premultiplied (s,t)
716 c->rasterizer.procs.texParameteri(c,
717 GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_S, GGL_CLAMP);
718 c->rasterizer.procs.texParameteri(c,
719 GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_T, GGL_CLAMP);
720 u.dirty = 0xFF; // XXX: should be more subtle
721
722 EGLTextureObject* textureObject = u.texture;
723 const GLint Ucr = textureObject->crop_rect[0] << 16;
724 const GLint Vcr = textureObject->crop_rect[1] << 16;
725 const GLint Wcr = textureObject->crop_rect[2] << 16;
726 const GLint Hcr = textureObject->crop_rect[3] << 16;
727
728 // computes texture coordinates (pre-multiplied)
729 int32_t dsdx = Wcr / w; // dsdx = ((Wcr/w)/Wt)*Wt
730 int32_t dtdy =-Hcr / h; // dtdy = -((Hcr/h)/Ht)*Ht
731 int32_t s0 = Ucr - gglMulx(dsdx, x); // s0 = Ucr - x * dsdx
732 int32_t t0 = (Vcr+Hcr) - gglMulx(dtdy, y); // t0 = (Vcr+Hcr) - y*dtdy
733 texcoords[0] = s0;
734 texcoords[1] = dsdx;
735 texcoords[2] = 0;
736 texcoords[3] = t0;
737 texcoords[4] = 0;
738 texcoords[5] = dtdy;
739 texcoords[6] = 0;
740 texcoords[7] = 0;
741 c->rasterizer.procs.texCoordGradScale8xv(c, i, texcoords);
742 }
743
744 const uint32_t enables = c->rasterizer.state.enables;
745 if (ggl_unlikely(enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)))
746 set_depth_and_fog(c, z);
747
748 c->rasterizer.procs.activeTexture(c, c->textures.active);
749 c->rasterizer.procs.color4xv(c, c->currentColorClamped.v);
750 c->rasterizer.procs.disable(c, GGL_W_LERP);
751 c->rasterizer.procs.disable(c, GGL_AA);
752 c->rasterizer.procs.shadeModel(c, GL_FLAT);
753 c->rasterizer.procs.recti(c,
754 gglFixedToIntRound(x),
755 gglFixedToIntRound(y),
756 gglFixedToIntRound(x)+w,
757 gglFixedToIntRound(y)+h);
758
759 ogles_unlock_textures(c);
760 }
761
drawTexxOES(GLfixed x,GLfixed y,GLfixed z,GLfixed w,GLfixed h,ogles_context_t * c)762 static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
763 ogles_context_t* c)
764 {
765 #ifdef LIBAGL_USE_GRALLOC_COPYBITS
766 if (drawTexiOESWithCopybit(gglFixedToIntRound(x),
767 gglFixedToIntRound(y), gglFixedToIntRound(z),
768 gglFixedToIntRound(w), gglFixedToIntRound(h), c)) {
769 return;
770 }
771 #else
772 // quickly reject empty rects
773 if ((w|h) <= 0)
774 return;
775 #endif
776 drawTexxOESImp(x, y, z, w, h, c);
777 }
778
drawTexiOES(GLint x,GLint y,GLint z,GLint w,GLint h,ogles_context_t * c)779 static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_context_t* c)
780 {
781 // All coordinates are integer, so if we have only one
782 // texture unit active and no scaling is required
783 // THEN, we can use our special 1:1 mapping
784 // which is a lot faster.
785
786 if (ggl_likely(c->rasterizer.state.enabled_tmu == 1)) {
787 #ifdef LIBAGL_USE_GRALLOC_COPYBITS
788 if (drawTexiOESWithCopybit(x, y, z, w, h, c)) {
789 return;
790 }
791 #endif
792 const int tmu = 0;
793 texture_unit_t& u(c->textures.tmu[tmu]);
794 EGLTextureObject* textureObject = u.texture;
795 const GLint Wcr = textureObject->crop_rect[2];
796 const GLint Hcr = textureObject->crop_rect[3];
797
798 if ((w == Wcr) && (h == -Hcr)) {
799 #ifndef LIBAGL_USE_GRALLOC_COPYBITS
800 if ((w|h) <= 0) return; // quickly reject empty rects
801 #endif
802
803 if (u.dirty) {
804 c->rasterizer.procs.activeTexture(c, tmu);
805 c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
806 c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
807 GGL_TEXTURE_MIN_FILTER, u.texture->min_filter);
808 c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
809 GGL_TEXTURE_MAG_FILTER, u.texture->mag_filter);
810 }
811 c->rasterizer.procs.texGeni(c, GGL_S,
812 GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
813 c->rasterizer.procs.texGeni(c, GGL_T,
814 GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
815 u.dirty = 0xFF; // XXX: should be more subtle
816 c->rasterizer.procs.activeTexture(c, c->textures.active);
817
818 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
819 y = cbSurface.height - (y + h);
820 const GLint Ucr = textureObject->crop_rect[0];
821 const GLint Vcr = textureObject->crop_rect[1];
822 const GLint s0 = Ucr - x;
823 const GLint t0 = (Vcr + Hcr) - y;
824
825 const GLuint tw = textureObject->surface.width;
826 const GLuint th = textureObject->surface.height;
827 if ((uint32_t(s0+x+w) > tw) || (uint32_t(t0+y+h) > th)) {
828 // The GL spec is unclear about what should happen
829 // in this case, so we just use the slow case, which
830 // at least won't crash
831 goto slow_case;
832 }
833
834 ogles_lock_textures(c);
835
836 c->rasterizer.procs.texCoord2i(c, s0, t0);
837 const uint32_t enables = c->rasterizer.state.enables;
838 if (ggl_unlikely(enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)))
839 set_depth_and_fog(c, z);
840
841 c->rasterizer.procs.color4xv(c, c->currentColorClamped.v);
842 c->rasterizer.procs.disable(c, GGL_W_LERP);
843 c->rasterizer.procs.disable(c, GGL_AA);
844 c->rasterizer.procs.shadeModel(c, GL_FLAT);
845 c->rasterizer.procs.recti(c, x, y, x+w, y+h);
846
847 ogles_unlock_textures(c);
848
849 return;
850 }
851 }
852
853 slow_case:
854 drawTexxOESImp(
855 gglIntToFixed(x), gglIntToFixed(y), gglIntToFixed(z),
856 gglIntToFixed(w), gglIntToFixed(h),
857 c);
858 }
859
860
861 }; // namespace android
862 // ----------------------------------------------------------------------------
863
864 using namespace android;
865
866
867 #if 0
868 #pragma mark -
869 #pragma mark Texture API
870 #endif
871
glActiveTexture(GLenum texture)872 void glActiveTexture(GLenum texture)
873 {
874 ogles_context_t* c = ogles_context_t::get();
875 if (uint32_t(texture-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) {
876 ogles_error(c, GL_INVALID_ENUM);
877 return;
878 }
879 c->textures.active = texture - GL_TEXTURE0;
880 c->rasterizer.procs.activeTexture(c, c->textures.active);
881 }
882
glBindTexture(GLenum target,GLuint texture)883 void glBindTexture(GLenum target, GLuint texture)
884 {
885 ogles_context_t* c = ogles_context_t::get();
886 if (target != GL_TEXTURE_2D) {
887 ogles_error(c, GL_INVALID_ENUM);
888 return;
889 }
890
891 // Bind or create a texture
892 sp<EGLTextureObject> tex;
893 if (texture == 0) {
894 // 0 is our local texture object
895 tex = c->textures.defaultTexture;
896 } else {
897 tex = c->surfaceManager->texture(texture);
898 if (ggl_unlikely(tex == 0)) {
899 tex = c->surfaceManager->createTexture(texture);
900 if (tex == 0) {
901 ogles_error(c, GL_OUT_OF_MEMORY);
902 return;
903 }
904 }
905 }
906 bindTextureTmu(c, c->textures.active, texture, tex);
907 }
908
glGenTextures(GLsizei n,GLuint * textures)909 void glGenTextures(GLsizei n, GLuint *textures)
910 {
911 ogles_context_t* c = ogles_context_t::get();
912 if (n<0) {
913 ogles_error(c, GL_INVALID_VALUE);
914 return;
915 }
916 // generate unique (shared) texture names
917 c->surfaceManager->getToken(n, textures);
918 }
919
glDeleteTextures(GLsizei n,const GLuint * textures)920 void glDeleteTextures(GLsizei n, const GLuint *textures)
921 {
922 ogles_context_t* c = ogles_context_t::get();
923 if (n<0) {
924 ogles_error(c, GL_INVALID_VALUE);
925 return;
926 }
927
928 // If deleting a bound texture, bind this unit to 0
929 for (int t=0 ; t<GGL_TEXTURE_UNIT_COUNT ; t++) {
930 if (c->textures.tmu[t].name == 0)
931 continue;
932 for (int i=0 ; i<n ; i++) {
933 if (textures[i] && (textures[i] == c->textures.tmu[t].name)) {
934 // bind this tmu to texture 0
935 sp<EGLTextureObject> tex(c->textures.defaultTexture);
936 bindTextureTmu(c, t, 0, tex);
937 }
938 }
939 }
940 c->surfaceManager->deleteTextures(n, textures);
941 c->surfaceManager->recycleTokens(n, textures);
942 }
943
glMultiTexCoord4f(GLenum target,GLfloat s,GLfloat t,GLfloat r,GLfloat q)944 void glMultiTexCoord4f(
945 GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
946 {
947 ogles_context_t* c = ogles_context_t::get();
948 if (uint32_t(target-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) {
949 ogles_error(c, GL_INVALID_ENUM);
950 return;
951 }
952 const int tmu = target-GL_TEXTURE0;
953 c->current.texture[tmu].S = gglFloatToFixed(s);
954 c->current.texture[tmu].T = gglFloatToFixed(t);
955 c->current.texture[tmu].R = gglFloatToFixed(r);
956 c->current.texture[tmu].Q = gglFloatToFixed(q);
957 }
958
glMultiTexCoord4x(GLenum target,GLfixed s,GLfixed t,GLfixed r,GLfixed q)959 void glMultiTexCoord4x(
960 GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q)
961 {
962 ogles_context_t* c = ogles_context_t::get();
963 if (uint32_t(target-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) {
964 ogles_error(c, GL_INVALID_ENUM);
965 return;
966 }
967 const int tmu = target-GL_TEXTURE0;
968 c->current.texture[tmu].S = s;
969 c->current.texture[tmu].T = t;
970 c->current.texture[tmu].R = r;
971 c->current.texture[tmu].Q = q;
972 }
973
glPixelStorei(GLenum pname,GLint param)974 void glPixelStorei(GLenum pname, GLint param)
975 {
976 ogles_context_t* c = ogles_context_t::get();
977 if ((pname != GL_PACK_ALIGNMENT) && (pname != GL_UNPACK_ALIGNMENT)) {
978 ogles_error(c, GL_INVALID_ENUM);
979 return;
980 }
981 if ((param<=0 || param>8) || (param & (param-1))) {
982 ogles_error(c, GL_INVALID_VALUE);
983 return;
984 }
985 if (pname == GL_PACK_ALIGNMENT)
986 c->textures.packAlignment = param;
987 if (pname == GL_UNPACK_ALIGNMENT)
988 c->textures.unpackAlignment = param;
989 }
990
glTexEnvf(GLenum target,GLenum pname,GLfloat param)991 void glTexEnvf(GLenum target, GLenum pname, GLfloat param)
992 {
993 ogles_context_t* c = ogles_context_t::get();
994 c->rasterizer.procs.texEnvi(c, target, pname, GLint(param));
995 }
996
glTexEnvfv(GLenum target,GLenum pname,const GLfloat * params)997 void glTexEnvfv(
998 GLenum target, GLenum pname, const GLfloat *params)
999 {
1000 ogles_context_t* c = ogles_context_t::get();
1001 if (pname == GL_TEXTURE_ENV_MODE) {
1002 c->rasterizer.procs.texEnvi(c, target, pname, GLint(*params));
1003 return;
1004 }
1005 if (pname == GL_TEXTURE_ENV_COLOR) {
1006 GGLfixed fixed[4];
1007 for (int i=0 ; i<4 ; i++)
1008 fixed[i] = gglFloatToFixed(params[i]);
1009 c->rasterizer.procs.texEnvxv(c, target, pname, fixed);
1010 return;
1011 }
1012 ogles_error(c, GL_INVALID_ENUM);
1013 }
1014
glTexEnvx(GLenum target,GLenum pname,GLfixed param)1015 void glTexEnvx(GLenum target, GLenum pname, GLfixed param)
1016 {
1017 ogles_context_t* c = ogles_context_t::get();
1018 c->rasterizer.procs.texEnvi(c, target, pname, param);
1019 }
1020
glTexEnvxv(GLenum target,GLenum pname,const GLfixed * params)1021 void glTexEnvxv(
1022 GLenum target, GLenum pname, const GLfixed *params)
1023 {
1024 ogles_context_t* c = ogles_context_t::get();
1025 c->rasterizer.procs.texEnvxv(c, target, pname, params);
1026 }
1027
glTexParameteriv(GLenum target,GLenum pname,const GLint * params)1028 void glTexParameteriv(
1029 GLenum target, GLenum pname, const GLint* params)
1030 {
1031 ogles_context_t* c = ogles_context_t::get();
1032 if (target != GGL_TEXTURE_2D) {
1033 ogles_error(c, GL_INVALID_ENUM);
1034 return;
1035 }
1036
1037 EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture;
1038 switch (pname) {
1039 case GL_TEXTURE_CROP_RECT_OES:
1040 memcpy(textureObject->crop_rect, params, 4*sizeof(GLint));
1041 break;
1042 default:
1043 texParameterx(target, pname, GLfixed(params[0]), c);
1044 return;
1045 }
1046 }
1047
glTexParameterf(GLenum target,GLenum pname,GLfloat param)1048 void glTexParameterf(
1049 GLenum target, GLenum pname, GLfloat param)
1050 {
1051 ogles_context_t* c = ogles_context_t::get();
1052 texParameterx(target, pname, GLfixed(param), c);
1053 }
1054
glTexParameterx(GLenum target,GLenum pname,GLfixed param)1055 void glTexParameterx(
1056 GLenum target, GLenum pname, GLfixed param)
1057 {
1058 ogles_context_t* c = ogles_context_t::get();
1059 texParameterx(target, pname, param, c);
1060 }
1061
glTexParameteri(GLenum target,GLenum pname,GLint param)1062 void glTexParameteri(
1063 GLenum target, GLenum pname, GLint param)
1064 {
1065 ogles_context_t* c = ogles_context_t::get();
1066 texParameterx(target, pname, GLfixed(param), c);
1067 }
1068
1069 // ----------------------------------------------------------------------------
1070 #if 0
1071 #pragma mark -
1072 #endif
1073
glCompressedTexImage2D(GLenum target,GLint level,GLenum internalformat,GLsizei width,GLsizei height,GLint border,GLsizei imageSize,const GLvoid * data)1074 void glCompressedTexImage2D(
1075 GLenum target, GLint level, GLenum internalformat,
1076 GLsizei width, GLsizei height, GLint border,
1077 GLsizei imageSize, const GLvoid *data)
1078 {
1079 ogles_context_t* c = ogles_context_t::get();
1080 if (target != GL_TEXTURE_2D) {
1081 ogles_error(c, GL_INVALID_ENUM);
1082 return;
1083 }
1084 if ((internalformat < GL_PALETTE4_RGB8_OES ||
1085 internalformat > GL_PALETTE8_RGB5_A1_OES)) {
1086 ogles_error(c, GL_INVALID_ENUM);
1087 return;
1088 }
1089 if (width<0 || height<0 || border!=0) {
1090 ogles_error(c, GL_INVALID_VALUE);
1091 return;
1092 }
1093
1094 // "uncompress" the texture since pixelflinger doesn't support
1095 // any compressed texture format natively.
1096 GLenum format;
1097 GLenum type;
1098 switch (internalformat) {
1099 case GL_PALETTE8_RGB8_OES:
1100 case GL_PALETTE4_RGB8_OES:
1101 format = GL_RGB;
1102 type = GL_UNSIGNED_BYTE;
1103 break;
1104 case GL_PALETTE8_RGBA8_OES:
1105 case GL_PALETTE4_RGBA8_OES:
1106 format = GL_RGBA;
1107 type = GL_UNSIGNED_BYTE;
1108 break;
1109 case GL_PALETTE8_R5_G6_B5_OES:
1110 case GL_PALETTE4_R5_G6_B5_OES:
1111 format = GL_RGB;
1112 type = GL_UNSIGNED_SHORT_5_6_5;
1113 break;
1114 case GL_PALETTE8_RGBA4_OES:
1115 case GL_PALETTE4_RGBA4_OES:
1116 format = GL_RGBA;
1117 type = GL_UNSIGNED_SHORT_4_4_4_4;
1118 break;
1119 case GL_PALETTE8_RGB5_A1_OES:
1120 case GL_PALETTE4_RGB5_A1_OES:
1121 format = GL_RGBA;
1122 type = GL_UNSIGNED_SHORT_5_5_5_1;
1123 break;
1124 default:
1125 ogles_error(c, GL_INVALID_ENUM);
1126 return;
1127 }
1128
1129 if (!data || !width || !height) {
1130 // unclear if this is an error or not...
1131 return;
1132 }
1133
1134 int32_t size;
1135 GGLSurface* surface;
1136 // all mipmap levels are specified at once.
1137 const int numLevels = level<0 ? -level : 1;
1138
1139 if (dataSizePalette4(numLevels, width, height, format) > imageSize) {
1140 ogles_error(c, GL_INVALID_VALUE);
1141 return;
1142 }
1143
1144 for (int i=0 ; i<numLevels ; i++) {
1145 int lod_w = (width >> i) ? : 1;
1146 int lod_h = (height >> i) ? : 1;
1147 int error = createTextureSurface(c, &surface, &size,
1148 i, format, type, lod_w, lod_h);
1149 if (error) {
1150 ogles_error(c, error);
1151 return;
1152 }
1153 decodePalette4(data, i, width, height,
1154 surface->data, surface->stride, internalformat);
1155 }
1156 }
1157
1158
glTexImage2D(GLenum target,GLint level,GLint internalformat,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type,const GLvoid * pixels)1159 void glTexImage2D(
1160 GLenum target, GLint level, GLint internalformat,
1161 GLsizei width, GLsizei height, GLint border,
1162 GLenum format, GLenum type, const GLvoid *pixels)
1163 {
1164 ogles_context_t* c = ogles_context_t::get();
1165 if (target != GL_TEXTURE_2D) {
1166 ogles_error(c, GL_INVALID_ENUM);
1167 return;
1168 }
1169 if (width<0 || height<0 || border!=0 || level < 0) {
1170 ogles_error(c, GL_INVALID_VALUE);
1171 return;
1172 }
1173 if (format != (GLenum)internalformat) {
1174 ogles_error(c, GL_INVALID_OPERATION);
1175 return;
1176 }
1177 if (validFormatType(c, format, type)) {
1178 return;
1179 }
1180
1181 int32_t size = 0;
1182 GGLSurface* surface = 0;
1183 int error = createTextureSurface(c, &surface, &size,
1184 level, format, type, width, height);
1185 if (error) {
1186 ogles_error(c, error);
1187 return;
1188 }
1189
1190 if (pixels) {
1191 const int32_t formatIdx = convertGLPixelFormat(format, type);
1192 const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
1193 const int32_t align = c->textures.unpackAlignment-1;
1194 const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
1195 const size_t size = bpr * height;
1196 const int32_t stride = bpr / pixelFormat.size;
1197
1198 GGLSurface userSurface;
1199 userSurface.version = sizeof(userSurface);
1200 userSurface.width = width;
1201 userSurface.height = height;
1202 userSurface.stride = stride;
1203 userSurface.format = formatIdx;
1204 userSurface.compressedFormat = 0;
1205 userSurface.data = (GLubyte*)pixels;
1206
1207 int err = copyPixels(c, *surface, 0, 0, userSurface, 0, 0, width, height);
1208 if (err) {
1209 ogles_error(c, err);
1210 return;
1211 }
1212 generateMipmap(c, level);
1213 }
1214 }
1215
1216 // ----------------------------------------------------------------------------
1217
glCompressedTexSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLsizei imageSize,const GLvoid * data)1218 void glCompressedTexSubImage2D(
1219 GLenum target, GLint level, GLint xoffset,
1220 GLint yoffset, GLsizei width, GLsizei height,
1221 GLenum format, GLsizei imageSize,
1222 const GLvoid *data)
1223 {
1224 ogles_context_t* c = ogles_context_t::get();
1225 ogles_error(c, GL_INVALID_ENUM);
1226 }
1227
glTexSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLenum type,const GLvoid * pixels)1228 void glTexSubImage2D(
1229 GLenum target, GLint level, GLint xoffset,
1230 GLint yoffset, GLsizei width, GLsizei height,
1231 GLenum format, GLenum type, const GLvoid *pixels)
1232 {
1233 ogles_context_t* c = ogles_context_t::get();
1234 if (target != GL_TEXTURE_2D) {
1235 ogles_error(c, GL_INVALID_ENUM);
1236 return;
1237 }
1238 if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) {
1239 ogles_error(c, GL_INVALID_VALUE);
1240 return;
1241 }
1242 if (validFormatType(c, format, type)) {
1243 return;
1244 }
1245
1246 // find out which texture is bound to the current unit
1247 const int active = c->textures.active;
1248 EGLTextureObject* tex = c->textures.tmu[active].texture;
1249 const GGLSurface& surface(tex->mip(level));
1250
1251 if (!tex->internalformat || tex->direct) {
1252 ogles_error(c, GL_INVALID_OPERATION);
1253 return;
1254 }
1255
1256 if (format != tex->internalformat) {
1257 ogles_error(c, GL_INVALID_OPERATION);
1258 return;
1259 }
1260 if ((xoffset + width > GLsizei(surface.width)) ||
1261 (yoffset + height > GLsizei(surface.height))) {
1262 ogles_error(c, GL_INVALID_VALUE);
1263 return;
1264 }
1265 if (!width || !height) {
1266 return; // okay, but no-op.
1267 }
1268
1269 // figure out the size we need as well as the stride
1270 const int32_t formatIdx = convertGLPixelFormat(format, type);
1271 if (formatIdx == 0) { // we don't know what to do with this
1272 ogles_error(c, GL_INVALID_OPERATION);
1273 return;
1274 }
1275
1276 const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
1277 const int32_t align = c->textures.unpackAlignment-1;
1278 const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
1279 const size_t size = bpr * height;
1280 const int32_t stride = bpr / pixelFormat.size;
1281 GGLSurface userSurface;
1282 userSurface.version = sizeof(userSurface);
1283 userSurface.width = width;
1284 userSurface.height = height;
1285 userSurface.stride = stride;
1286 userSurface.format = formatIdx;
1287 userSurface.compressedFormat = 0;
1288 userSurface.data = (GLubyte*)pixels;
1289
1290 int err = copyPixels(c,
1291 surface, xoffset, yoffset,
1292 userSurface, 0, 0, width, height);
1293 if (err) {
1294 ogles_error(c, err);
1295 return;
1296 }
1297
1298 generateMipmap(c, level);
1299
1300 // since we only changed the content of the texture, we don't need
1301 // to call bindTexture on the main rasterizer.
1302 }
1303
1304 // ----------------------------------------------------------------------------
1305
glCopyTexImage2D(GLenum target,GLint level,GLenum internalformat,GLint x,GLint y,GLsizei width,GLsizei height,GLint border)1306 void glCopyTexImage2D(
1307 GLenum target, GLint level, GLenum internalformat,
1308 GLint x, GLint y, GLsizei width, GLsizei height,
1309 GLint border)
1310 {
1311 ogles_context_t* c = ogles_context_t::get();
1312 if (target != GL_TEXTURE_2D) {
1313 ogles_error(c, GL_INVALID_ENUM);
1314 return;
1315 }
1316 if (internalformat<GL_ALPHA || internalformat>GL_LUMINANCE_ALPHA) {
1317 ogles_error(c, GL_INVALID_ENUM);
1318 return;
1319 }
1320 if (width<0 || height<0 || border!=0 || level<0) {
1321 ogles_error(c, GL_INVALID_VALUE);
1322 return;
1323 }
1324
1325 GLenum format = 0;
1326 GLenum type = GL_UNSIGNED_BYTE;
1327 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
1328 const int cbFormatIdx = cbSurface.format;
1329 switch (cbFormatIdx) {
1330 case GGL_PIXEL_FORMAT_RGB_565:
1331 type = GL_UNSIGNED_SHORT_5_6_5;
1332 break;
1333 case GGL_PIXEL_FORMAT_RGBA_5551:
1334 type = GL_UNSIGNED_SHORT_5_5_5_1;
1335 break;
1336 case GGL_PIXEL_FORMAT_RGBA_4444:
1337 type = GL_UNSIGNED_SHORT_4_4_4_4;
1338 break;
1339 }
1340 switch (internalformat) {
1341 case GL_ALPHA:
1342 case GL_LUMINANCE_ALPHA:
1343 case GL_LUMINANCE:
1344 type = GL_UNSIGNED_BYTE;
1345 break;
1346 }
1347
1348 // figure out the format to use for the new texture
1349 switch (cbFormatIdx) {
1350 case GGL_PIXEL_FORMAT_RGBA_8888:
1351 case GGL_PIXEL_FORMAT_A_8:
1352 case GGL_PIXEL_FORMAT_RGBA_5551:
1353 case GGL_PIXEL_FORMAT_RGBA_4444:
1354 format = internalformat;
1355 break;
1356 case GGL_PIXEL_FORMAT_RGBX_8888:
1357 case GGL_PIXEL_FORMAT_RGB_888:
1358 case GGL_PIXEL_FORMAT_RGB_565:
1359 case GGL_PIXEL_FORMAT_L_8:
1360 switch (internalformat) {
1361 case GL_LUMINANCE:
1362 case GL_RGB:
1363 format = internalformat;
1364 break;
1365 }
1366 break;
1367 }
1368
1369 if (format == 0) {
1370 // invalid combination
1371 ogles_error(c, GL_INVALID_ENUM);
1372 return;
1373 }
1374
1375 // create the new texture...
1376 int32_t size;
1377 GGLSurface* surface;
1378 int error = createTextureSurface(c, &surface, &size,
1379 level, format, type, width, height);
1380 if (error) {
1381 ogles_error(c, error);
1382 return;
1383 }
1384
1385 // The bottom row is stored first in textures
1386 GGLSurface txSurface(*surface);
1387 txSurface.stride = -txSurface.stride;
1388
1389 // (x,y) is the lower-left corner of colorBuffer
1390 y = cbSurface.height - (y + height);
1391
1392 int err = copyPixels(c,
1393 txSurface, 0, 0,
1394 cbSurface, x, y, cbSurface.width, cbSurface.height);
1395 if (err) {
1396 ogles_error(c, err);
1397 }
1398
1399 generateMipmap(c, level);
1400 }
1401
glCopyTexSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint x,GLint y,GLsizei width,GLsizei height)1402 void glCopyTexSubImage2D(
1403 GLenum target, GLint level, GLint xoffset, GLint yoffset,
1404 GLint x, GLint y, GLsizei width, GLsizei height)
1405 {
1406 ogles_context_t* c = ogles_context_t::get();
1407 if (target != GL_TEXTURE_2D) {
1408 ogles_error(c, GL_INVALID_ENUM);
1409 return;
1410 }
1411 if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) {
1412 ogles_error(c, GL_INVALID_VALUE);
1413 return;
1414 }
1415 if (!width || !height) {
1416 return; // okay, but no-op.
1417 }
1418
1419 // find out which texture is bound to the current unit
1420 const int active = c->textures.active;
1421 EGLTextureObject* tex = c->textures.tmu[active].texture;
1422 const GGLSurface& surface(tex->mip(level));
1423
1424 if (!tex->internalformat) {
1425 ogles_error(c, GL_INVALID_OPERATION);
1426 return;
1427 }
1428 if ((xoffset + width > GLsizei(surface.width)) ||
1429 (yoffset + height > GLsizei(surface.height))) {
1430 ogles_error(c, GL_INVALID_VALUE);
1431 return;
1432 }
1433
1434 // The bottom row is stored first in textures
1435 GGLSurface txSurface(surface);
1436 txSurface.stride = -txSurface.stride;
1437
1438 // (x,y) is the lower-left corner of colorBuffer
1439 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
1440 y = cbSurface.height - (y + height);
1441
1442 int err = copyPixels(c,
1443 surface, xoffset, yoffset,
1444 cbSurface, x, y, width, height);
1445 if (err) {
1446 ogles_error(c, err);
1447 return;
1448 }
1449
1450 generateMipmap(c, level);
1451 }
1452
glReadPixels(GLint x,GLint y,GLsizei width,GLsizei height,GLenum format,GLenum type,GLvoid * pixels)1453 void glReadPixels(
1454 GLint x, GLint y, GLsizei width, GLsizei height,
1455 GLenum format, GLenum type, GLvoid *pixels)
1456 {
1457 ogles_context_t* c = ogles_context_t::get();
1458 if ((format != GL_RGBA) && (format != GL_RGB)) {
1459 ogles_error(c, GL_INVALID_ENUM);
1460 return;
1461 }
1462 if ((type != GL_UNSIGNED_BYTE) && (type != GL_UNSIGNED_SHORT_5_6_5)) {
1463 ogles_error(c, GL_INVALID_ENUM);
1464 return;
1465 }
1466 if (width<0 || height<0) {
1467 ogles_error(c, GL_INVALID_VALUE);
1468 return;
1469 }
1470 if (x<0 || x<0) {
1471 ogles_error(c, GL_INVALID_VALUE);
1472 return;
1473 }
1474
1475 int32_t formatIdx = GGL_PIXEL_FORMAT_NONE;
1476 if ((format == GL_RGBA) && (type == GL_UNSIGNED_BYTE)) {
1477 formatIdx = GGL_PIXEL_FORMAT_RGBA_8888;
1478 } else if ((format == GL_RGB) && (type == GL_UNSIGNED_SHORT_5_6_5)) {
1479 formatIdx = GGL_PIXEL_FORMAT_RGB_565;
1480 } else {
1481 ogles_error(c, GL_INVALID_OPERATION);
1482 return;
1483 }
1484
1485 const GGLSurface& readSurface = c->rasterizer.state.buffers.read.s;
1486 if ((x+width > GLint(readSurface.width)) ||
1487 (y+height > GLint(readSurface.height))) {
1488 ogles_error(c, GL_INVALID_VALUE);
1489 return;
1490 }
1491
1492 const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
1493 const int32_t align = c->textures.packAlignment-1;
1494 const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
1495 const int32_t stride = bpr / pixelFormat.size;
1496
1497 GGLSurface userSurface;
1498 userSurface.version = sizeof(userSurface);
1499 userSurface.width = width;
1500 userSurface.height = height;
1501 userSurface.stride = -stride; // bottom row is transfered first
1502 userSurface.format = formatIdx;
1503 userSurface.compressedFormat = 0;
1504 userSurface.data = (GLubyte*)pixels;
1505
1506 // use pixel-flinger to handle all the conversions
1507 GGLContext* ggl = getRasterizer(c);
1508 if (!ggl) {
1509 // the only reason this would fail is because we ran out of memory
1510 ogles_error(c, GL_OUT_OF_MEMORY);
1511 return;
1512 }
1513
1514 ggl->colorBuffer(ggl, &userSurface); // destination is user buffer
1515 ggl->bindTexture(ggl, &readSurface); // source is read-buffer
1516 ggl->texCoord2i(ggl, x, readSurface.height - (y + height));
1517 ggl->recti(ggl, 0, 0, width, height);
1518 }
1519
1520 // ----------------------------------------------------------------------------
1521 #if 0
1522 #pragma mark -
1523 #pragma mark DrawTexture Extension
1524 #endif
1525
glDrawTexsvOES(const GLshort * coords)1526 void glDrawTexsvOES(const GLshort* coords) {
1527 ogles_context_t* c = ogles_context_t::get();
1528 drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
1529 }
glDrawTexivOES(const GLint * coords)1530 void glDrawTexivOES(const GLint* coords) {
1531 ogles_context_t* c = ogles_context_t::get();
1532 drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
1533 }
glDrawTexsOES(GLshort x,GLshort y,GLshort z,GLshort w,GLshort h)1534 void glDrawTexsOES(GLshort x , GLshort y, GLshort z, GLshort w, GLshort h) {
1535 ogles_context_t* c = ogles_context_t::get();
1536 drawTexiOES(x, y, z, w, h, c);
1537 }
glDrawTexiOES(GLint x,GLint y,GLint z,GLint w,GLint h)1538 void glDrawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h) {
1539 ogles_context_t* c = ogles_context_t::get();
1540 drawTexiOES(x, y, z, w, h, c);
1541 }
1542
glDrawTexfvOES(const GLfloat * coords)1543 void glDrawTexfvOES(const GLfloat* coords) {
1544 ogles_context_t* c = ogles_context_t::get();
1545 drawTexxOES(
1546 gglFloatToFixed(coords[0]),
1547 gglFloatToFixed(coords[1]),
1548 gglFloatToFixed(coords[2]),
1549 gglFloatToFixed(coords[3]),
1550 gglFloatToFixed(coords[4]),
1551 c);
1552 }
glDrawTexxvOES(const GLfixed * coords)1553 void glDrawTexxvOES(const GLfixed* coords) {
1554 ogles_context_t* c = ogles_context_t::get();
1555 drawTexxOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
1556 }
glDrawTexfOES(GLfloat x,GLfloat y,GLfloat z,GLfloat w,GLfloat h)1557 void glDrawTexfOES(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h){
1558 ogles_context_t* c = ogles_context_t::get();
1559 drawTexxOES(
1560 gglFloatToFixed(x), gglFloatToFixed(y), gglFloatToFixed(z),
1561 gglFloatToFixed(w), gglFloatToFixed(h),
1562 c);
1563 }
glDrawTexxOES(GLfixed x,GLfixed y,GLfixed z,GLfixed w,GLfixed h)1564 void glDrawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h) {
1565 ogles_context_t* c = ogles_context_t::get();
1566 drawTexxOES(x, y, z, w, h, c);
1567 }
1568
1569 // ----------------------------------------------------------------------------
1570 #if 0
1571 #pragma mark -
1572 #pragma mark EGL Image Extension
1573 #endif
1574
glEGLImageTargetTexture2DOES(GLenum target,GLeglImageOES image)1575 void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
1576 {
1577 ogles_context_t* c = ogles_context_t::get();
1578 if (target != GL_TEXTURE_2D) {
1579 ogles_error(c, GL_INVALID_ENUM);
1580 return;
1581 }
1582
1583 android_native_buffer_t* native_buffer = (android_native_buffer_t*)image;
1584 if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) {
1585 ogles_error(c, GL_INVALID_VALUE);
1586 return;
1587 }
1588 if (native_buffer->common.version != sizeof(android_native_buffer_t)) {
1589 ogles_error(c, GL_INVALID_VALUE);
1590 return;
1591 }
1592
1593 // bind it to the texture unit
1594 sp<EGLTextureObject> tex = getAndBindActiveTextureObject(c);
1595 tex->setImage(native_buffer);
1596
1597 #ifdef LIBAGL_USE_GRALLOC_COPYBITS
1598 tex->try_copybit = false;
1599 if (c->copybits.blitEngine != NULL) {
1600 tex->try_copybit = true;
1601 }
1602 #endif // LIBAGL_USE_GRALLOC_COPYBITS
1603 }
1604
glEGLImageTargetRenderbufferStorageOES(GLenum target,GLeglImageOES image)1605 void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
1606 {
1607 }
1608