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