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