texture.cpp revision edbf3b6af777b721cd2a1ef461947e51e88241e1
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 != GL_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_REPEAT) || 538 (param == GL_CLAMP_TO_EDGE)) { 539 textureObject->wraps = param; 540 } else { 541 goto invalid_enum; 542 } 543 break; 544 case GL_TEXTURE_WRAP_T: 545 if ((param == GL_REPEAT) || 546 (param == GL_CLAMP_TO_EDGE)) { 547 textureObject->wrapt = param; 548 } else { 549 goto invalid_enum; 550 } 551 break; 552 case GL_TEXTURE_MIN_FILTER: 553 if ((param == GL_NEAREST) || 554 (param == GL_LINEAR) || 555 (param == GL_NEAREST_MIPMAP_NEAREST) || 556 (param == GL_LINEAR_MIPMAP_NEAREST) || 557 (param == GL_NEAREST_MIPMAP_LINEAR) || 558 (param == GL_LINEAR_MIPMAP_LINEAR)) { 559 textureObject->min_filter = param; 560 } else { 561 goto invalid_enum; 562 } 563 break; 564 case GL_TEXTURE_MAG_FILTER: 565 if ((param == GL_NEAREST) || 566 (param == GL_LINEAR)) { 567 textureObject->mag_filter = param; 568 } else { 569 goto invalid_enum; 570 } 571 break; 572 case GL_GENERATE_MIPMAP: 573 textureObject->generate_mipmap = param; 574 break; 575 default: 576invalid_enum: 577 ogles_error(c, GL_INVALID_ENUM); 578 return; 579 } 580 invalidate_texture(c, c->textures.active); 581} 582 583 584static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h, 585 ogles_context_t* c) 586{ 587 // quickly reject empty rects 588 if ((w|h) <= 0) 589 return; 590 591 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s; 592 y = gglIntToFixed(cbSurface.height) - (y + h); 593 w >>= FIXED_BITS; 594 h >>= FIXED_BITS; 595 596 // set up all texture units 597 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) { 598 if (!c->rasterizer.state.texture[i].enable) 599 continue; 600 601 int32_t texcoords[8]; 602 texture_unit_t& u(c->textures.tmu[i]); 603 604 // validate this tmu (bind, wrap, filter) 605 validate_tmu(c, i); 606 // we CLAMP here, which works with premultiplied (s,t) 607 c->rasterizer.procs.texParameteri(c, 608 GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_S, GGL_CLAMP); 609 c->rasterizer.procs.texParameteri(c, 610 GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_T, GGL_CLAMP); 611 u.dirty = 0xFF; // XXX: should be more subtle 612 613 EGLTextureObject* textureObject = u.texture; 614 const GLint Ucr = textureObject->crop_rect[0] << 16; 615 const GLint Vcr = textureObject->crop_rect[1] << 16; 616 const GLint Wcr = textureObject->crop_rect[2] << 16; 617 const GLint Hcr = textureObject->crop_rect[3] << 16; 618 619 // computes texture coordinates (pre-multiplied) 620 int32_t dsdx = Wcr / w; // dsdx = ((Wcr/w)/Wt)*Wt 621 int32_t dtdy =-Hcr / h; // dtdy = -((Hcr/h)/Ht)*Ht 622 int32_t s0 = Ucr - gglMulx(dsdx, x); // s0 = Ucr - x * dsdx 623 int32_t t0 = (Vcr+Hcr) - gglMulx(dtdy, y); // t0 = (Vcr+Hcr) - y*dtdy 624 texcoords[0] = s0; 625 texcoords[1] = dsdx; 626 texcoords[2] = 0; 627 texcoords[3] = t0; 628 texcoords[4] = 0; 629 texcoords[5] = dtdy; 630 texcoords[6] = 0; 631 texcoords[7] = 0; 632 c->rasterizer.procs.texCoordGradScale8xv(c, i, texcoords); 633 } 634 635 const uint32_t enables = c->rasterizer.state.enables; 636 if (ggl_unlikely(enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG))) 637 set_depth_and_fog(c, z); 638 639 c->rasterizer.procs.activeTexture(c, c->textures.active); 640 c->rasterizer.procs.color4xv(c, c->currentColorClamped.v); 641 c->rasterizer.procs.disable(c, GGL_W_LERP); 642 c->rasterizer.procs.disable(c, GGL_AA); 643 c->rasterizer.procs.shadeModel(c, GL_FLAT); 644 c->rasterizer.procs.recti(c, 645 gglFixedToIntRound(x), 646 gglFixedToIntRound(y), 647 gglFixedToIntRound(x)+w, 648 gglFixedToIntRound(y)+h); 649} 650 651static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_context_t* c) 652{ 653 // All coordinates are integer, so if we have only one 654 // texture unit active and no scaling is required 655 // THEN, we can use our special 1:1 mapping 656 // which is a lot faster. 657 658 if (ggl_likely(c->rasterizer.state.enabled_tmu == 1)) { 659 const int tmu = 0; 660 texture_unit_t& u(c->textures.tmu[tmu]); 661 EGLTextureObject* textureObject = u.texture; 662 const GLint Wcr = textureObject->crop_rect[2]; 663 const GLint Hcr = textureObject->crop_rect[3]; 664 665 if ((w == Wcr) && (h == -Hcr)) { 666 if ((w|h) <= 0) return; // quickly reject empty rects 667 668 if (u.dirty) { 669 c->rasterizer.procs.activeTexture(c, tmu); 670 c->rasterizer.procs.bindTexture(c, &(u.texture->surface)); 671 c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D, 672 GGL_TEXTURE_MIN_FILTER, u.texture->min_filter); 673 c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D, 674 GGL_TEXTURE_MAG_FILTER, u.texture->mag_filter); 675 } 676 c->rasterizer.procs.texGeni(c, GGL_S, 677 GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE); 678 c->rasterizer.procs.texGeni(c, GGL_T, 679 GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE); 680 u.dirty = 0xFF; // XXX: should be more subtle 681 c->rasterizer.procs.activeTexture(c, c->textures.active); 682 683 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s; 684 y = cbSurface.height - (y + h); 685 const GLint Ucr = textureObject->crop_rect[0]; 686 const GLint Vcr = textureObject->crop_rect[1]; 687 const GLint s0 = Ucr - x; 688 const GLint t0 = (Vcr + Hcr) - y; 689 690 const GLuint tw = textureObject->surface.width; 691 const GLuint th = textureObject->surface.height; 692 if ((uint32_t(s0+x+w) > tw) || (uint32_t(t0+y+h) > th)) { 693 // The GL spec is unclear about what should happen 694 // in this case, so we just use the slow case, which 695 // at least won't crash 696 goto slow_case; 697 } 698 699 c->rasterizer.procs.texCoord2i(c, s0, t0); 700 const uint32_t enables = c->rasterizer.state.enables; 701 if (ggl_unlikely(enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG))) 702 set_depth_and_fog(c, z); 703 704 c->rasterizer.procs.color4xv(c, c->currentColorClamped.v); 705 c->rasterizer.procs.disable(c, GGL_W_LERP); 706 c->rasterizer.procs.disable(c, GGL_AA); 707 c->rasterizer.procs.shadeModel(c, GL_FLAT); 708 c->rasterizer.procs.recti(c, x, y, x+w, y+h); 709 return; 710 } 711 } 712 713slow_case: 714 drawTexxOES( 715 gglIntToFixed(x), gglIntToFixed(y), gglIntToFixed(z), 716 gglIntToFixed(w), gglIntToFixed(h), 717 c); 718} 719 720 721}; // namespace android 722// ---------------------------------------------------------------------------- 723 724using namespace android; 725 726 727#if 0 728#pragma mark - 729#pragma mark Texture API 730#endif 731 732void glActiveTexture(GLenum texture) 733{ 734 ogles_context_t* c = ogles_context_t::get(); 735 if (uint32_t(texture-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) { 736 ogles_error(c, GL_INVALID_ENUM); 737 return; 738 } 739 c->textures.active = texture - GL_TEXTURE0; 740 c->rasterizer.procs.activeTexture(c, c->textures.active); 741} 742 743void glBindTexture(GLenum target, GLuint texture) 744{ 745 ogles_context_t* c = ogles_context_t::get(); 746 if (target != GL_TEXTURE_2D) { 747 ogles_error(c, GL_INVALID_ENUM); 748 return; 749 } 750 751 // Bind or create a texture 752 sp<EGLTextureObject> tex; 753 if (texture == 0) { 754 // 0 is our local texture object 755 tex = c->textures.defaultTexture; 756 } else { 757 tex = c->surfaceManager->texture(texture); 758 if (ggl_unlikely(tex == 0)) { 759 tex = c->surfaceManager->createTexture(texture); 760 if (tex == 0) { 761 ogles_error(c, GL_OUT_OF_MEMORY); 762 return; 763 } 764 } 765 } 766 bindTextureTmu(c, c->textures.active, texture, tex); 767} 768 769void glGenTextures(GLsizei n, GLuint *textures) 770{ 771 ogles_context_t* c = ogles_context_t::get(); 772 if (n<0) { 773 ogles_error(c, GL_INVALID_VALUE); 774 return; 775 } 776 // generate unique (shared) texture names 777 c->surfaceManager->getToken(n, textures); 778} 779 780void glDeleteTextures(GLsizei n, const GLuint *textures) 781{ 782 ogles_context_t* c = ogles_context_t::get(); 783 if (n<0) { 784 ogles_error(c, GL_INVALID_VALUE); 785 return; 786 } 787 788 // If deleting a bound texture, bind this unit to 0 789 for (int t=0 ; t<GGL_TEXTURE_UNIT_COUNT ; t++) { 790 if (c->textures.tmu[t].name == 0) 791 continue; 792 for (int i=0 ; i<n ; i++) { 793 if (textures[i] && (textures[i] == c->textures.tmu[t].name)) { 794 // bind this tmu to texture 0 795 sp<EGLTextureObject> tex(c->textures.defaultTexture); 796 bindTextureTmu(c, t, 0, tex); 797 } 798 } 799 } 800 c->surfaceManager->deleteTextures(n, textures); 801 c->surfaceManager->recycleTokens(n, textures); 802} 803 804void glMultiTexCoord4f( 805 GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) 806{ 807 ogles_context_t* c = ogles_context_t::get(); 808 if (uint32_t(target-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) { 809 ogles_error(c, GL_INVALID_ENUM); 810 return; 811 } 812 const int tmu = target-GL_TEXTURE0; 813 c->current.texture[tmu].S = gglFloatToFixed(s); 814 c->current.texture[tmu].T = gglFloatToFixed(t); 815 c->current.texture[tmu].R = gglFloatToFixed(r); 816 c->current.texture[tmu].Q = gglFloatToFixed(q); 817} 818 819void glMultiTexCoord4x( 820 GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q) 821{ 822 ogles_context_t* c = ogles_context_t::get(); 823 if (uint32_t(target-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) { 824 ogles_error(c, GL_INVALID_ENUM); 825 return; 826 } 827 const int tmu = target-GL_TEXTURE0; 828 c->current.texture[tmu].S = s; 829 c->current.texture[tmu].T = t; 830 c->current.texture[tmu].R = r; 831 c->current.texture[tmu].Q = q; 832} 833 834void glPixelStorei(GLenum pname, GLint param) 835{ 836 ogles_context_t* c = ogles_context_t::get(); 837 if ((pname != GL_PACK_ALIGNMENT) && (pname != GL_UNPACK_ALIGNMENT)) { 838 ogles_error(c, GL_INVALID_ENUM); 839 return; 840 } 841 if ((param<=0 || param>8) || (param & (param-1))) { 842 ogles_error(c, GL_INVALID_VALUE); 843 return; 844 } 845 if (pname == GL_PACK_ALIGNMENT) 846 c->textures.packAlignment = param; 847 if (pname == GL_UNPACK_ALIGNMENT) 848 c->textures.unpackAlignment = param; 849} 850 851void glTexEnvf(GLenum target, GLenum pname, GLfloat param) 852{ 853 ogles_context_t* c = ogles_context_t::get(); 854 c->rasterizer.procs.texEnvi(c, target, pname, GLint(param)); 855} 856 857void glTexEnvfv( 858 GLenum target, GLenum pname, const GLfloat *params) 859{ 860 ogles_context_t* c = ogles_context_t::get(); 861 if (pname == GL_TEXTURE_ENV_MODE) { 862 c->rasterizer.procs.texEnvi(c, target, pname, GLint(*params)); 863 return; 864 } 865 if (pname == GL_TEXTURE_ENV_COLOR) { 866 GGLfixed fixed[4]; 867 for (int i=0 ; i<4 ; i++) 868 fixed[i] = gglFloatToFixed(params[i]); 869 c->rasterizer.procs.texEnvxv(c, target, pname, fixed); 870 return; 871 } 872 ogles_error(c, GL_INVALID_ENUM); 873} 874 875void glTexEnvx(GLenum target, GLenum pname, GLfixed param) 876{ 877 ogles_context_t* c = ogles_context_t::get(); 878 c->rasterizer.procs.texEnvi(c, target, pname, param); 879} 880 881void glTexEnvxv( 882 GLenum target, GLenum pname, const GLfixed *params) 883{ 884 ogles_context_t* c = ogles_context_t::get(); 885 c->rasterizer.procs.texEnvxv(c, target, pname, params); 886} 887 888void glTexParameteriv( 889 GLenum target, GLenum pname, const GLint* params) 890{ 891 ogles_context_t* c = ogles_context_t::get(); 892 if (target != GGL_TEXTURE_2D) { 893 ogles_error(c, GL_INVALID_ENUM); 894 return; 895 } 896 897 EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture; 898 switch (pname) { 899 case GL_TEXTURE_CROP_RECT_OES: 900 memcpy(textureObject->crop_rect, params, 4*sizeof(GLint)); 901 break; 902 default: 903 ogles_error(c, GL_INVALID_ENUM); 904 return; 905 } 906} 907 908void glTexParameterf( 909 GLenum target, GLenum pname, GLfloat param) 910{ 911 ogles_context_t* c = ogles_context_t::get(); 912 texParameterx(target, pname, GLfixed(param), c); 913} 914 915void glTexParameterx( 916 GLenum target, GLenum pname, GLfixed param) 917{ 918 ogles_context_t* c = ogles_context_t::get(); 919 texParameterx(target, pname, param, c); 920} 921 922// ---------------------------------------------------------------------------- 923#if 0 924#pragma mark - 925#endif 926 927void glCompressedTexImage2D( 928 GLenum target, GLint level, GLenum internalformat, 929 GLsizei width, GLsizei height, GLint border, 930 GLsizei imageSize, const GLvoid *data) 931{ 932 ogles_context_t* c = ogles_context_t::get(); 933 if (target != GL_TEXTURE_2D) { 934 ogles_error(c, GL_INVALID_ENUM); 935 return; 936 } 937 if ((internalformat < GL_PALETTE4_RGB8_OES || 938 internalformat > GL_PALETTE8_RGB5_A1_OES)) { 939 ogles_error(c, GL_INVALID_ENUM); 940 return; 941 } 942 if (width<0 || height<0 || border!=0) { 943 ogles_error(c, GL_INVALID_VALUE); 944 return; 945 } 946 947 // "uncompress" the texture since pixelflinger doesn't support 948 // any compressed texture format natively. 949 GLenum format; 950 GLenum type; 951 switch (internalformat) { 952 case GL_PALETTE8_RGB8_OES: 953 case GL_PALETTE4_RGB8_OES: 954 format = GL_RGB; 955 type = GL_UNSIGNED_BYTE; 956 break; 957 case GL_PALETTE8_RGBA8_OES: 958 case GL_PALETTE4_RGBA8_OES: 959 format = GL_RGBA; 960 type = GL_UNSIGNED_BYTE; 961 break; 962 case GL_PALETTE8_R5_G6_B5_OES: 963 case GL_PALETTE4_R5_G6_B5_OES: 964 format = GL_RGB; 965 type = GL_UNSIGNED_SHORT_5_6_5; 966 break; 967 case GL_PALETTE8_RGBA4_OES: 968 case GL_PALETTE4_RGBA4_OES: 969 format = GL_RGBA; 970 type = GL_UNSIGNED_SHORT_4_4_4_4; 971 break; 972 case GL_PALETTE8_RGB5_A1_OES: 973 case GL_PALETTE4_RGB5_A1_OES: 974 format = GL_RGBA; 975 type = GL_UNSIGNED_SHORT_5_5_5_1; 976 break; 977 default: 978 ogles_error(c, GL_INVALID_ENUM); 979 return; 980 } 981 982 if (!data || !width || !height) { 983 // unclear if this is an error or not... 984 return; 985 } 986 987 int32_t size; 988 GGLSurface* surface; 989 // all mipmap levels are specified at once. 990 const int numLevels = level<0 ? -level : 1; 991 for (int i=0 ; i<numLevels ; i++) { 992 int lod_w = (width >> i) ? : 1; 993 int lod_h = (height >> i) ? : 1; 994 int error = createTextureSurface(c, &surface, &size, 995 i, format, type, lod_w, lod_h); 996 if (error) { 997 ogles_error(c, error); 998 return; 999 } 1000 decodePalette4(data, i, width, height, 1001 surface->data, surface->stride, internalformat); 1002 } 1003} 1004 1005 1006void glTexImage2D( 1007 GLenum target, GLint level, GLint internalformat, 1008 GLsizei width, GLsizei height, GLint border, 1009 GLenum format, GLenum type, const GLvoid *pixels) 1010{ 1011 ogles_context_t* c = ogles_context_t::get(); 1012 if (target != GL_TEXTURE_2D && target != GL_DIRECT_TEXTURE_2D_QUALCOMM) { 1013 ogles_error(c, GL_INVALID_ENUM); 1014 return; 1015 } 1016 if (width<0 || height<0 || border!=0 || level < 0) { 1017 ogles_error(c, GL_INVALID_VALUE); 1018 return; 1019 } 1020 if (format != internalformat) { 1021 ogles_error(c, GL_INVALID_OPERATION); 1022 return; 1023 } 1024 if (validFormatType(c, format, type)) { 1025 return; 1026 } 1027 1028 int32_t size = 0; 1029 GGLSurface* surface = 0; 1030 if (target != GL_DIRECT_TEXTURE_2D_QUALCOMM) { 1031 int error = createTextureSurface(c, &surface, &size, 1032 level, format, type, width, height); 1033 if (error) { 1034 ogles_error(c, error); 1035 return; 1036 } 1037 } else if (pixels == 0 || level != 0) { 1038 // pixel can't be null for direct texture 1039 ogles_error(c, GL_INVALID_OPERATION); 1040 return; 1041 } 1042 1043 if (pixels) { 1044 const int32_t formatIdx = convertGLPixelFormat(format, type); 1045 const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]); 1046 const int32_t align = c->textures.unpackAlignment-1; 1047 const int32_t bpr = ((width * pixelFormat.size) + align) & ~align; 1048 const size_t size = bpr * height; 1049 const int32_t stride = bpr / pixelFormat.size; 1050 1051 GGLSurface userSurface; 1052 userSurface.version = sizeof(userSurface); 1053 userSurface.width = width; 1054 userSurface.height = height; 1055 userSurface.stride = stride; 1056 userSurface.format = formatIdx; 1057 userSurface.compressedFormat = 0; 1058 userSurface.data = (GLubyte*)pixels; 1059 1060 if (target != GL_DIRECT_TEXTURE_2D_QUALCOMM) { 1061 int err = copyPixels(c, *surface, 0, 0, userSurface, 0, 0, width, height); 1062 if (err) { 1063 ogles_error(c, err); 1064 return; 1065 } 1066 generateMipmap(c, level); 1067 } else { 1068 // bind it to the texture unit 1069 sp<EGLTextureObject> tex = getAndBindActiveTextureObject(c); 1070 tex->setSurface(&userSurface); 1071 } 1072 } 1073} 1074 1075// ---------------------------------------------------------------------------- 1076 1077void glCompressedTexSubImage2D( 1078 GLenum target, GLint level, GLint xoffset, 1079 GLint yoffset, GLsizei width, GLsizei height, 1080 GLenum format, GLsizei imageSize, 1081 const GLvoid *data) 1082{ 1083 ogles_context_t* c = ogles_context_t::get(); 1084 ogles_error(c, GL_INVALID_ENUM); 1085} 1086 1087void glTexSubImage2D( 1088 GLenum target, GLint level, GLint xoffset, 1089 GLint yoffset, GLsizei width, GLsizei height, 1090 GLenum format, GLenum type, const GLvoid *pixels) 1091{ 1092 ogles_context_t* c = ogles_context_t::get(); 1093 if (target != GL_TEXTURE_2D) { 1094 ogles_error(c, GL_INVALID_ENUM); 1095 return; 1096 } 1097 if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) { 1098 ogles_error(c, GL_INVALID_VALUE); 1099 return; 1100 } 1101 if (validFormatType(c, format, type)) { 1102 return; 1103 } 1104 1105 // find out which texture is bound to the current unit 1106 const int active = c->textures.active; 1107 EGLTextureObject* tex = c->textures.tmu[active].texture; 1108 const GGLSurface& surface(tex->mip(level)); 1109 1110 if (!tex->internalformat || tex->direct) { 1111 ogles_error(c, GL_INVALID_OPERATION); 1112 return; 1113 } 1114 if ((xoffset + width > GLsizei(surface.width)) || 1115 (yoffset + height > GLsizei(surface.height))) { 1116 ogles_error(c, GL_INVALID_VALUE); 1117 return; 1118 } 1119 if (!width || !height) { 1120 return; // okay, but no-op. 1121 } 1122 1123 // figure out the size we need as well as the stride 1124 const int32_t formatIdx = convertGLPixelFormat(format, type); 1125 if (formatIdx == 0) { // we don't know what to do with this 1126 ogles_error(c, GL_INVALID_OPERATION); 1127 return; 1128 } 1129 1130 const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]); 1131 const int32_t align = c->textures.unpackAlignment-1; 1132 const int32_t bpr = ((width * pixelFormat.size) + align) & ~align; 1133 const size_t size = bpr * height; 1134 const int32_t stride = bpr / pixelFormat.size; 1135 GGLSurface userSurface; 1136 userSurface.version = sizeof(userSurface); 1137 userSurface.width = width; 1138 userSurface.height = height; 1139 userSurface.stride = stride; 1140 userSurface.format = formatIdx; 1141 userSurface.compressedFormat = 0; 1142 userSurface.data = (GLubyte*)pixels; 1143 1144 int err = copyPixels(c, 1145 surface, xoffset, yoffset, 1146 userSurface, 0, 0, width, height); 1147 if (err) { 1148 ogles_error(c, err); 1149 return; 1150 } 1151 1152 generateMipmap(c, level); 1153 1154 // since we only changed the content of the texture, we don't need 1155 // to call bindTexture on the main rasterizer. 1156} 1157 1158// ---------------------------------------------------------------------------- 1159 1160void glCopyTexImage2D( 1161 GLenum target, GLint level, GLenum internalformat, 1162 GLint x, GLint y, GLsizei width, GLsizei height, 1163 GLint border) 1164{ 1165 ogles_context_t* c = ogles_context_t::get(); 1166 if (target != GL_TEXTURE_2D) { 1167 ogles_error(c, GL_INVALID_ENUM); 1168 return; 1169 } 1170 if (internalformat<GL_ALPHA || internalformat>GL_LUMINANCE_ALPHA) { 1171 ogles_error(c, GL_INVALID_ENUM); 1172 return; 1173 } 1174 if (width<0 || height<0 || border!=0 || level<0) { 1175 ogles_error(c, GL_INVALID_VALUE); 1176 return; 1177 } 1178 1179 GLenum format = 0; 1180 GLenum type = GL_UNSIGNED_BYTE; 1181 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s; 1182 const int cbFormatIdx = cbSurface.format; 1183 switch (cbFormatIdx) { 1184 case GGL_PIXEL_FORMAT_RGB_565: 1185 type = GL_UNSIGNED_SHORT_5_6_5; 1186 break; 1187 case GGL_PIXEL_FORMAT_RGBA_5551: 1188 type = GL_UNSIGNED_SHORT_5_5_5_1; 1189 break; 1190 case GGL_PIXEL_FORMAT_RGBA_4444: 1191 type = GL_UNSIGNED_SHORT_4_4_4_4; 1192 break; 1193 } 1194 switch (internalformat) { 1195 case GL_ALPHA: 1196 case GL_LUMINANCE_ALPHA: 1197 case GL_LUMINANCE: 1198 type = GL_UNSIGNED_BYTE; 1199 break; 1200 } 1201 1202 // figure out the format to use for the new texture 1203 switch (cbFormatIdx) { 1204 case GGL_PIXEL_FORMAT_RGBA_8888: 1205 case GGL_PIXEL_FORMAT_A_8: 1206 case GGL_PIXEL_FORMAT_RGBA_5551: 1207 case GGL_PIXEL_FORMAT_RGBA_4444: 1208 format = internalformat; 1209 break; 1210 case GGL_PIXEL_FORMAT_RGBX_8888: 1211 case GGL_PIXEL_FORMAT_RGB_888: 1212 case GGL_PIXEL_FORMAT_RGB_565: 1213 case GGL_PIXEL_FORMAT_L_8: 1214 switch (internalformat) { 1215 case GL_LUMINANCE: 1216 case GL_RGB: 1217 format = internalformat; 1218 break; 1219 } 1220 break; 1221 } 1222 1223 if (format == 0) { 1224 // invalid combination 1225 ogles_error(c, GL_INVALID_ENUM); 1226 return; 1227 } 1228 1229 // create the new texture... 1230 int32_t size; 1231 GGLSurface* surface; 1232 int error = createTextureSurface(c, &surface, &size, 1233 level, format, type, width, height); 1234 if (error) { 1235 ogles_error(c, error); 1236 return; 1237 } 1238 1239 // The bottom row is stored first in textures 1240 GGLSurface txSurface(*surface); 1241 txSurface.stride = -txSurface.stride; 1242 1243 // (x,y) is the lower-left corner of colorBuffer 1244 y = cbSurface.height - (y + height); 1245 1246 int err = copyPixels(c, 1247 txSurface, 0, 0, 1248 cbSurface, x, y, cbSurface.width, cbSurface.height); 1249 if (err) { 1250 ogles_error(c, err); 1251 } 1252 1253 generateMipmap(c, level); 1254} 1255 1256void glCopyTexSubImage2D( 1257 GLenum target, GLint level, GLint xoffset, GLint yoffset, 1258 GLint x, GLint y, GLsizei width, GLsizei height) 1259{ 1260 ogles_context_t* c = ogles_context_t::get(); 1261 if (target != GL_TEXTURE_2D) { 1262 ogles_error(c, GL_INVALID_ENUM); 1263 return; 1264 } 1265 if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) { 1266 ogles_error(c, GL_INVALID_VALUE); 1267 return; 1268 } 1269 if (!width || !height) { 1270 return; // okay, but no-op. 1271 } 1272 1273 // find out which texture is bound to the current unit 1274 const int active = c->textures.active; 1275 EGLTextureObject* tex = c->textures.tmu[active].texture; 1276 const GGLSurface& surface(tex->mip(level)); 1277 1278 if (!tex->internalformat) { 1279 ogles_error(c, GL_INVALID_OPERATION); 1280 return; 1281 } 1282 if ((xoffset + width > GLsizei(surface.width)) || 1283 (yoffset + height > GLsizei(surface.height))) { 1284 ogles_error(c, GL_INVALID_VALUE); 1285 return; 1286 } 1287 1288 // The bottom row is stored first in textures 1289 GGLSurface txSurface(surface); 1290 txSurface.stride = -txSurface.stride; 1291 1292 // (x,y) is the lower-left corner of colorBuffer 1293 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s; 1294 y = cbSurface.height - (y + height); 1295 1296 int err = copyPixels(c, 1297 surface, xoffset, yoffset, 1298 cbSurface, x, y, width, height); 1299 if (err) { 1300 ogles_error(c, err); 1301 return; 1302 } 1303 1304 generateMipmap(c, level); 1305} 1306 1307void glReadPixels( 1308 GLint x, GLint y, GLsizei width, GLsizei height, 1309 GLenum format, GLenum type, GLvoid *pixels) 1310{ 1311 ogles_context_t* c = ogles_context_t::get(); 1312 if ((format != GL_RGBA) && (format != GL_RGB)) { 1313 ogles_error(c, GL_INVALID_ENUM); 1314 return; 1315 } 1316 if ((type != GL_UNSIGNED_BYTE) && (type != GL_UNSIGNED_SHORT_5_6_5)) { 1317 ogles_error(c, GL_INVALID_ENUM); 1318 return; 1319 } 1320 if (width<0 || height<0) { 1321 ogles_error(c, GL_INVALID_VALUE); 1322 return; 1323 } 1324 if (x<0 || x<0) { 1325 ogles_error(c, GL_INVALID_VALUE); 1326 return; 1327 } 1328 1329 int32_t formatIdx = GGL_PIXEL_FORMAT_NONE; 1330 if ((format == GL_RGBA) && (type == GL_UNSIGNED_BYTE)) { 1331 formatIdx = GGL_PIXEL_FORMAT_RGBA_8888; 1332 } else if ((format == GL_RGB) && (type == GL_UNSIGNED_SHORT_5_6_5)) { 1333 formatIdx = GGL_PIXEL_FORMAT_RGB_565; 1334 } else { 1335 ogles_error(c, GL_INVALID_OPERATION); 1336 return; 1337 } 1338 1339 const GGLSurface& readSurface = c->rasterizer.state.buffers.read.s; 1340 if ((x+width > GLint(readSurface.width)) || 1341 (y+height > GLint(readSurface.height))) { 1342 ogles_error(c, GL_INVALID_VALUE); 1343 return; 1344 } 1345 1346 const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]); 1347 const int32_t align = c->textures.packAlignment-1; 1348 const int32_t bpr = ((width * pixelFormat.size) + align) & ~align; 1349 const int32_t stride = bpr / pixelFormat.size; 1350 1351 GGLSurface userSurface; 1352 userSurface.version = sizeof(userSurface); 1353 userSurface.width = width; 1354 userSurface.height = height; 1355 userSurface.stride = -stride; // bottom row is transfered first 1356 userSurface.format = formatIdx; 1357 userSurface.compressedFormat = 0; 1358 userSurface.data = (GLubyte*)pixels; 1359 1360 // use pixel-flinger to handle all the conversions 1361 GGLContext* ggl = getRasterizer(c); 1362 if (!ggl) { 1363 // the only reason this would fail is because we ran out of memory 1364 ogles_error(c, GL_OUT_OF_MEMORY); 1365 return; 1366 } 1367 1368 ggl->colorBuffer(ggl, &userSurface); // destination is user buffer 1369 ggl->bindTexture(ggl, &readSurface); // source is read-buffer 1370 ggl->texCoord2i(ggl, x, readSurface.height - (y + height)); 1371 ggl->recti(ggl, 0, 0, width, height); 1372} 1373 1374// ---------------------------------------------------------------------------- 1375#if 0 1376#pragma mark - 1377#pragma mark DrawTexture Extension 1378#endif 1379 1380void glDrawTexsvOES(const GLshort* coords) { 1381 ogles_context_t* c = ogles_context_t::get(); 1382 drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c); 1383} 1384void glDrawTexivOES(const GLint* coords) { 1385 ogles_context_t* c = ogles_context_t::get(); 1386 drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c); 1387} 1388void glDrawTexsOES(GLshort x , GLshort y, GLshort z, GLshort w, GLshort h) { 1389 ogles_context_t* c = ogles_context_t::get(); 1390 drawTexiOES(x, y, z, w, h, c); 1391} 1392void glDrawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h) { 1393 ogles_context_t* c = ogles_context_t::get(); 1394 drawTexiOES(x, y, z, w, h, c); 1395} 1396 1397void glDrawTexfvOES(const GLfloat* coords) { 1398 ogles_context_t* c = ogles_context_t::get(); 1399 drawTexxOES( 1400 gglFloatToFixed(coords[0]), 1401 gglFloatToFixed(coords[1]), 1402 gglFloatToFixed(coords[2]), 1403 gglFloatToFixed(coords[3]), 1404 gglFloatToFixed(coords[4]), 1405 c); 1406} 1407void glDrawTexxvOES(const GLfixed* coords) { 1408 ogles_context_t* c = ogles_context_t::get(); 1409 drawTexxOES(coords[0], coords[1], coords[2], coords[3], coords[4], c); 1410} 1411void glDrawTexfOES(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h){ 1412 ogles_context_t* c = ogles_context_t::get(); 1413 drawTexxOES( 1414 gglFloatToFixed(x), gglFloatToFixed(y), gglFloatToFixed(z), 1415 gglFloatToFixed(w), gglFloatToFixed(h), 1416 c); 1417} 1418void glDrawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h) { 1419 ogles_context_t* c = ogles_context_t::get(); 1420 drawTexxOES(x, y, z, w, h, c); 1421} 1422