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