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