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