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