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