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