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