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