1 // 2 // Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 // Texture.cpp: Implements the gl::Texture class and its derived classes 8 // Texture2D and TextureCubeMap. Implements GL texture objects and related 9 // functionality. [OpenGL ES 2.0.24] section 3.7 page 63. 10 11 #include "libGLESv2/Texture.h" 12 13 #include <d3dx9tex.h> 14 15 #include <algorithm> 16 17 #include "common/debug.h" 18 19 #include "libGLESv2/main.h" 20 #include "libGLESv2/mathutil.h" 21 #include "libGLESv2/utilities.h" 22 #include "libGLESv2/Blit.h" 23 24 namespace gl 25 { 26 27 Texture::Image::Image() 28 : width(0), height(0), dirty(false), surface(NULL), format(GL_NONE) 29 { 30 } 31 32 Texture::Image::~Image() 33 { 34 if (surface) surface->Release(); 35 } 36 37 Texture::Texture(GLuint id) : RefCountObject(id) 38 { 39 mMinFilter = GL_NEAREST_MIPMAP_LINEAR; 40 mMagFilter = GL_LINEAR; 41 mWrapS = GL_REPEAT; 42 mWrapT = GL_REPEAT; 43 44 mWidth = 0; 45 mHeight = 0; 46 47 mDirtyMetaData = true; 48 mDirty = true; 49 mIsRenderable = false; 50 mType = GL_UNSIGNED_BYTE; 51 mBaseTexture = NULL; 52 } 53 54 Texture::~Texture() 55 { 56 } 57 58 Blit *Texture::getBlitter() 59 { 60 Context *context = getContext(); 61 return context->getBlitter(); 62 } 63 64 // Returns true on successful filter state update (valid enum parameter) 65 bool Texture::setMinFilter(GLenum filter) 66 { 67 switch (filter) 68 { 69 case GL_NEAREST: 70 case GL_LINEAR: 71 case GL_NEAREST_MIPMAP_NEAREST: 72 case GL_LINEAR_MIPMAP_NEAREST: 73 case GL_NEAREST_MIPMAP_LINEAR: 74 case GL_LINEAR_MIPMAP_LINEAR: 75 { 76 if (mMinFilter != filter) 77 { 78 mMinFilter = filter; 79 mDirty = true; 80 } 81 return true; 82 } 83 default: 84 return false; 85 } 86 } 87 88 // Returns true on successful filter state update (valid enum parameter) 89 bool Texture::setMagFilter(GLenum filter) 90 { 91 switch (filter) 92 { 93 case GL_NEAREST: 94 case GL_LINEAR: 95 { 96 if (mMagFilter != filter) 97 { 98 mMagFilter = filter; 99 mDirty = true; 100 } 101 return true; 102 } 103 default: 104 return false; 105 } 106 } 107 108 // Returns true on successful wrap state update (valid enum parameter) 109 bool Texture::setWrapS(GLenum wrap) 110 { 111 switch (wrap) 112 { 113 case GL_REPEAT: 114 case GL_CLAMP_TO_EDGE: 115 case GL_MIRRORED_REPEAT: 116 { 117 if (mWrapS != wrap) 118 { 119 mWrapS = wrap; 120 mDirty = true; 121 } 122 return true; 123 } 124 default: 125 return false; 126 } 127 } 128 129 // Returns true on successful wrap state update (valid enum parameter) 130 bool Texture::setWrapT(GLenum wrap) 131 { 132 switch (wrap) 133 { 134 case GL_REPEAT: 135 case GL_CLAMP_TO_EDGE: 136 case GL_MIRRORED_REPEAT: 137 { 138 if (mWrapT != wrap) 139 { 140 mWrapT = wrap; 141 mDirty = true; 142 } 143 return true; 144 } 145 default: 146 return false; 147 } 148 } 149 150 GLenum Texture::getMinFilter() const 151 { 152 return mMinFilter; 153 } 154 155 GLenum Texture::getMagFilter() const 156 { 157 return mMagFilter; 158 } 159 160 GLenum Texture::getWrapS() const 161 { 162 return mWrapS; 163 } 164 165 GLenum Texture::getWrapT() const 166 { 167 return mWrapT; 168 } 169 170 GLuint Texture::getWidth() const 171 { 172 return mWidth; 173 } 174 175 GLuint Texture::getHeight() const 176 { 177 return mHeight; 178 } 179 180 bool Texture::isFloatingPoint() const 181 { 182 return (mType == GL_FLOAT || mType == GL_HALF_FLOAT_OES); 183 } 184 185 bool Texture::isRenderableFormat() const 186 { 187 D3DFORMAT format = getD3DFormat(); 188 189 switch(format) 190 { 191 case D3DFMT_L8: 192 case D3DFMT_A8L8: 193 case D3DFMT_DXT1: 194 return false; 195 case D3DFMT_A8R8G8B8: 196 case D3DFMT_X8R8G8B8: 197 case D3DFMT_A16B16G16R16F: 198 case D3DFMT_A32B32G32R32F: 199 return true; 200 default: 201 UNREACHABLE(); 202 } 203 204 return false; 205 } 206 207 // Selects an internal Direct3D 9 format for storing an Image 208 D3DFORMAT Texture::selectFormat(GLenum format, GLenum type) 209 { 210 if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT || 211 format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) 212 { 213 return D3DFMT_DXT1; 214 } 215 else if (type == GL_FLOAT) 216 { 217 return D3DFMT_A32B32G32R32F; 218 } 219 else if (type == GL_HALF_FLOAT_OES) 220 { 221 return D3DFMT_A16B16G16R16F; 222 } 223 else if (type == GL_UNSIGNED_BYTE) 224 { 225 if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures()) 226 { 227 return D3DFMT_L8; 228 } 229 else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures()) 230 { 231 return D3DFMT_A8L8; 232 } 233 else if (format == GL_RGB) 234 { 235 return D3DFMT_X8R8G8B8; 236 } 237 238 return D3DFMT_A8R8G8B8; 239 } 240 241 return D3DFMT_A8R8G8B8; 242 } 243 244 // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input 245 // into the target pixel rectangle at output with outputPitch bytes in between each line. 246 void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, 247 GLint unpackAlignment, const void *input, size_t outputPitch, void *output, D3DSURFACE_DESC *description) const 248 { 249 GLsizei inputPitch = ComputePitch(width, format, type, unpackAlignment); 250 251 switch (type) 252 { 253 case GL_UNSIGNED_BYTE: 254 switch (format) 255 { 256 case GL_ALPHA: 257 loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); 258 break; 259 case GL_LUMINANCE: 260 loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_L8); 261 break; 262 case GL_LUMINANCE_ALPHA: 263 loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_A8L8); 264 break; 265 case GL_RGB: 266 loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); 267 break; 268 case GL_RGBA: 269 loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); 270 break; 271 case GL_BGRA_EXT: 272 loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); 273 break; 274 default: UNREACHABLE(); 275 } 276 break; 277 case GL_UNSIGNED_SHORT_5_6_5: 278 switch (format) 279 { 280 case GL_RGB: 281 loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); 282 break; 283 default: UNREACHABLE(); 284 } 285 break; 286 case GL_UNSIGNED_SHORT_4_4_4_4: 287 switch (format) 288 { 289 case GL_RGBA: 290 loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); 291 break; 292 default: UNREACHABLE(); 293 } 294 break; 295 case GL_UNSIGNED_SHORT_5_5_5_1: 296 switch (format) 297 { 298 case GL_RGBA: 299 loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); 300 break; 301 default: UNREACHABLE(); 302 } 303 break; 304 case GL_FLOAT: 305 switch (format) 306 { 307 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D 308 case GL_ALPHA: 309 loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); 310 break; 311 case GL_LUMINANCE: 312 loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); 313 break; 314 case GL_LUMINANCE_ALPHA: 315 loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); 316 break; 317 case GL_RGB: 318 loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); 319 break; 320 case GL_RGBA: 321 loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); 322 break; 323 default: UNREACHABLE(); 324 } 325 break; 326 case GL_HALF_FLOAT_OES: 327 switch (format) 328 { 329 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D 330 case GL_ALPHA: 331 loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); 332 break; 333 case GL_LUMINANCE: 334 loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); 335 break; 336 case GL_LUMINANCE_ALPHA: 337 loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); 338 break; 339 case GL_RGB: 340 loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); 341 break; 342 case GL_RGBA: 343 loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); 344 break; 345 default: UNREACHABLE(); 346 } 347 break; 348 default: UNREACHABLE(); 349 } 350 } 351 352 void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, 353 size_t inputPitch, const void *input, size_t outputPitch, void *output) const 354 { 355 const unsigned char *source = NULL; 356 unsigned char *dest = NULL; 357 358 for (int y = 0; y < height; y++) 359 { 360 source = static_cast<const unsigned char*>(input) + y * inputPitch; 361 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4; 362 for (int x = 0; x < width; x++) 363 { 364 dest[4 * x + 0] = 0; 365 dest[4 * x + 1] = 0; 366 dest[4 * x + 2] = 0; 367 dest[4 * x + 3] = source[x]; 368 } 369 } 370 } 371 372 void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, 373 size_t inputPitch, const void *input, size_t outputPitch, void *output) const 374 { 375 const float *source = NULL; 376 float *dest = NULL; 377 378 for (int y = 0; y < height; y++) 379 { 380 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch); 381 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16); 382 for (int x = 0; x < width; x++) 383 { 384 dest[4 * x + 0] = 0; 385 dest[4 * x + 1] = 0; 386 dest[4 * x + 2] = 0; 387 dest[4 * x + 3] = source[x]; 388 } 389 } 390 } 391 392 void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, 393 size_t inputPitch, const void *input, size_t outputPitch, void *output) const 394 { 395 const unsigned short *source = NULL; 396 unsigned short *dest = NULL; 397 398 for (int y = 0; y < height; y++) 399 { 400 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); 401 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8); 402 for (int x = 0; x < width; x++) 403 { 404 dest[4 * x + 0] = 0; 405 dest[4 * x + 1] = 0; 406 dest[4 * x + 2] = 0; 407 dest[4 * x + 3] = source[x]; 408 } 409 } 410 } 411 412 void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, 413 size_t inputPitch, const void *input, size_t outputPitch, void *output, bool native) const 414 { 415 const int destBytesPerPixel = native? 1: 4; 416 const unsigned char *source = NULL; 417 unsigned char *dest = NULL; 418 419 for (int y = 0; y < height; y++) 420 { 421 source = static_cast<const unsigned char*>(input) + y * inputPitch; 422 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel; 423 424 if (!native) // BGRA8 destination format 425 { 426 for (int x = 0; x < width; x++) 427 { 428 dest[4 * x + 0] = source[x]; 429 dest[4 * x + 1] = source[x]; 430 dest[4 * x + 2] = source[x]; 431 dest[4 * x + 3] = 0xFF; 432 } 433 } 434 else // L8 destination format 435 { 436 memcpy(dest, source, width); 437 } 438 } 439 } 440 441 void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, 442 size_t inputPitch, const void *input, size_t outputPitch, void *output) const 443 { 444 const float *source = NULL; 445 float *dest = NULL; 446 447 for (int y = 0; y < height; y++) 448 { 449 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch); 450 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16); 451 for (int x = 0; x < width; x++) 452 { 453 dest[4 * x + 0] = source[x]; 454 dest[4 * x + 1] = source[x]; 455 dest[4 * x + 2] = source[x]; 456 dest[4 * x + 3] = 1.0f; 457 } 458 } 459 } 460 461 void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, 462 size_t inputPitch, const void *input, size_t outputPitch, void *output) const 463 { 464 const unsigned short *source = NULL; 465 unsigned short *dest = NULL; 466 467 for (int y = 0; y < height; y++) 468 { 469 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); 470 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8); 471 for (int x = 0; x < width; x++) 472 { 473 dest[4 * x + 0] = source[x]; 474 dest[4 * x + 1] = source[x]; 475 dest[4 * x + 2] = source[x]; 476 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1 477 } 478 } 479 } 480 481 void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, 482 size_t inputPitch, const void *input, size_t outputPitch, void *output, bool native) const 483 { 484 const int destBytesPerPixel = native? 2: 4; 485 const unsigned char *source = NULL; 486 unsigned char *dest = NULL; 487 488 for (int y = 0; y < height; y++) 489 { 490 source = static_cast<const unsigned char*>(input) + y * inputPitch; 491 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel; 492 493 if (!native) // BGRA8 destination format 494 { 495 for (int x = 0; x < width; x++) 496 { 497 dest[4 * x + 0] = source[2*x+0]; 498 dest[4 * x + 1] = source[2*x+0]; 499 dest[4 * x + 2] = source[2*x+0]; 500 dest[4 * x + 3] = source[2*x+1]; 501 } 502 } 503 else 504 { 505 memcpy(dest, source, width * 2); 506 } 507 } 508 } 509 510 void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, 511 size_t inputPitch, const void *input, size_t outputPitch, void *output) const 512 { 513 const float *source = NULL; 514 float *dest = NULL; 515 516 for (int y = 0; y < height; y++) 517 { 518 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch); 519 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16); 520 for (int x = 0; x < width; x++) 521 { 522 dest[4 * x + 0] = source[2*x+0]; 523 dest[4 * x + 1] = source[2*x+0]; 524 dest[4 * x + 2] = source[2*x+0]; 525 dest[4 * x + 3] = source[2*x+1]; 526 } 527 } 528 } 529 530 void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, 531 size_t inputPitch, const void *input, size_t outputPitch, void *output) const 532 { 533 const unsigned short *source = NULL; 534 unsigned short *dest = NULL; 535 536 for (int y = 0; y < height; y++) 537 { 538 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); 539 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8); 540 for (int x = 0; x < width; x++) 541 { 542 dest[4 * x + 0] = source[2*x+0]; 543 dest[4 * x + 1] = source[2*x+0]; 544 dest[4 * x + 2] = source[2*x+0]; 545 dest[4 * x + 3] = source[2*x+1]; 546 } 547 } 548 } 549 550 void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, 551 size_t inputPitch, const void *input, size_t outputPitch, void *output) const 552 { 553 const unsigned char *source = NULL; 554 unsigned char *dest = NULL; 555 556 for (int y = 0; y < height; y++) 557 { 558 source = static_cast<const unsigned char*>(input) + y * inputPitch; 559 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4; 560 for (int x = 0; x < width; x++) 561 { 562 dest[4 * x + 0] = source[x * 3 + 2]; 563 dest[4 * x + 1] = source[x * 3 + 1]; 564 dest[4 * x + 2] = source[x * 3 + 0]; 565 dest[4 * x + 3] = 0xFF; 566 } 567 } 568 } 569 570 void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, 571 size_t inputPitch, const void *input, size_t outputPitch, void *output) const 572 { 573 const unsigned short *source = NULL; 574 unsigned char *dest = NULL; 575 576 for (int y = 0; y < height; y++) 577 { 578 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); 579 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4; 580 for (int x = 0; x < width; x++) 581 { 582 unsigned short rgba = source[x]; 583 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2); 584 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9); 585 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13); 586 dest[4 * x + 3] = 0xFF; 587 } 588 } 589 } 590 591 void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, 592 size_t inputPitch, const void *input, size_t outputPitch, void *output) const 593 { 594 const float *source = NULL; 595 float *dest = NULL; 596 597 for (int y = 0; y < height; y++) 598 { 599 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch); 600 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16); 601 for (int x = 0; x < width; x++) 602 { 603 dest[4 * x + 0] = source[x * 3 + 0]; 604 dest[4 * x + 1] = source[x * 3 + 1]; 605 dest[4 * x + 2] = source[x * 3 + 2]; 606 dest[4 * x + 3] = 1.0f; 607 } 608 } 609 } 610 611 void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, 612 size_t inputPitch, const void *input, size_t outputPitch, void *output) const 613 { 614 const unsigned short *source = NULL; 615 unsigned short *dest = NULL; 616 617 for (int y = 0; y < height; y++) 618 { 619 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); 620 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8); 621 for (int x = 0; x < width; x++) 622 { 623 dest[4 * x + 0] = source[x * 3 + 0]; 624 dest[4 * x + 1] = source[x * 3 + 1]; 625 dest[4 * x + 2] = source[x * 3 + 2]; 626 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1 627 } 628 } 629 } 630 631 void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, 632 size_t inputPitch, const void *input, size_t outputPitch, void *output) const 633 { 634 const unsigned char *source = NULL; 635 unsigned char *dest = NULL; 636 637 for (int y = 0; y < height; y++) 638 { 639 source = static_cast<const unsigned char*>(input) + y * inputPitch; 640 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4; 641 for (int x = 0; x < width; x++) 642 { 643 dest[4 * x + 0] = source[x * 4 + 2]; 644 dest[4 * x + 1] = source[x * 4 + 1]; 645 dest[4 * x + 2] = source[x * 4 + 0]; 646 dest[4 * x + 3] = source[x * 4 + 3]; 647 } 648 } 649 } 650 651 void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, 652 size_t inputPitch, const void *input, size_t outputPitch, void *output) const 653 { 654 const unsigned short *source = NULL; 655 unsigned char *dest = NULL; 656 657 for (int y = 0; y < height; y++) 658 { 659 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); 660 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4; 661 for (int x = 0; x < width; x++) 662 { 663 unsigned short rgba = source[x]; 664 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4); 665 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8); 666 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12); 667 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0); 668 } 669 } 670 } 671 672 void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, 673 size_t inputPitch, const void *input, size_t outputPitch, void *output) const 674 { 675 const unsigned short *source = NULL; 676 unsigned char *dest = NULL; 677 678 for (int y = 0; y < height; y++) 679 { 680 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); 681 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4; 682 for (int x = 0; x < width; x++) 683 { 684 unsigned short rgba = source[x]; 685 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3); 686 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8); 687 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13); 688 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0; 689 } 690 } 691 } 692 693 void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, 694 size_t inputPitch, const void *input, size_t outputPitch, void *output) const 695 { 696 const float *source = NULL; 697 float *dest = NULL; 698 699 for (int y = 0; y < height; y++) 700 { 701 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch); 702 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16); 703 memcpy(dest, source, width * 16); 704 } 705 } 706 707 void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, 708 size_t inputPitch, const void *input, size_t outputPitch, void *output) const 709 { 710 const unsigned char *source = NULL; 711 unsigned char *dest = NULL; 712 713 for (int y = 0; y < height; y++) 714 { 715 source = static_cast<const unsigned char*>(input) + y * inputPitch; 716 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8; 717 memcpy(dest, source, width * 8); 718 } 719 } 720 721 void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, 722 size_t inputPitch, const void *input, size_t outputPitch, void *output) const 723 { 724 const unsigned char *source = NULL; 725 unsigned char *dest = NULL; 726 727 for (int y = 0; y < height; y++) 728 { 729 source = static_cast<const unsigned char*>(input) + y * inputPitch; 730 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4; 731 memcpy(dest, source, width*4); 732 } 733 } 734 735 void Texture::createSurface(GLsizei width, GLsizei height, GLenum format, GLenum type, Image *img) 736 { 737 IDirect3DTexture9 *newTexture = NULL; 738 IDirect3DSurface9 *newSurface = NULL; 739 740 if (width != 0 && height != 0) 741 { 742 int levelToFetch = 0; 743 GLsizei requestWidth = width; 744 GLsizei requestHeight = height; 745 if (IsCompressed(format) && (width % 4 != 0 || height % 4 != 0)) 746 { 747 bool isMult4 = false; 748 int upsampleCount = 0; 749 while (!isMult4) 750 { 751 requestWidth <<= 1; 752 requestHeight <<= 1; 753 upsampleCount++; 754 if (requestWidth % 4 == 0 && requestHeight % 4 == 0) 755 { 756 isMult4 = true; 757 } 758 } 759 levelToFetch = upsampleCount; 760 } 761 762 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, selectFormat(format, type), 763 D3DPOOL_SYSTEMMEM, &newTexture, NULL); 764 765 if (FAILED(result)) 766 { 767 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); 768 return error(GL_OUT_OF_MEMORY); 769 } 770 771 newTexture->GetSurfaceLevel(levelToFetch, &newSurface); 772 newTexture->Release(); 773 } 774 775 if (img->surface) img->surface->Release(); 776 img->surface = newSurface; 777 778 img->width = width; 779 img->height = height; 780 img->format = format; 781 } 782 783 void Texture::setImage(GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img) 784 { 785 createSurface(width, height, format, type, img); 786 787 if (pixels != NULL && img->surface != NULL) 788 { 789 D3DSURFACE_DESC description; 790 img->surface->GetDesc(&description); 791 792 D3DLOCKED_RECT locked; 793 HRESULT result = img->surface->LockRect(&locked, NULL, 0); 794 795 ASSERT(SUCCEEDED(result)); 796 797 if (SUCCEEDED(result)) 798 { 799 loadImageData(0, 0, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description); 800 img->surface->UnlockRect(); 801 } 802 803 img->dirty = true; 804 } 805 806 mDirtyMetaData = true; 807 } 808 809 void Texture::setCompressedImage(GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img) 810 { 811 createSurface(width, height, format, GL_UNSIGNED_BYTE, img); 812 813 if (pixels != NULL && img->surface != NULL) 814 { 815 D3DLOCKED_RECT locked; 816 HRESULT result = img->surface->LockRect(&locked, NULL, 0); 817 818 ASSERT(SUCCEEDED(result)); 819 820 if (SUCCEEDED(result)) 821 { 822 memcpy(locked.pBits, pixels, imageSize); 823 img->surface->UnlockRect(); 824 } 825 826 img->dirty = true; 827 } 828 829 mDirtyMetaData = true; 830 } 831 832 bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img) 833 { 834 if (width + xoffset > img->width || height + yoffset > img->height) 835 { 836 error(GL_INVALID_VALUE); 837 return false; 838 } 839 840 if (!img->surface) 841 { 842 createSurface(img->width, img->height, format, type, img); 843 } 844 845 if (pixels != NULL && img->surface != NULL) 846 { 847 D3DSURFACE_DESC description; 848 img->surface->GetDesc(&description); 849 850 D3DLOCKED_RECT locked; 851 HRESULT result = img->surface->LockRect(&locked, NULL, 0); 852 853 ASSERT(SUCCEEDED(result)); 854 855 if (SUCCEEDED(result)) 856 { 857 loadImageData(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description); 858 img->surface->UnlockRect(); 859 } 860 861 img->dirty = true; 862 } 863 864 return true; 865 } 866 867 bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img) 868 { 869 if (width + xoffset > img->width || height + yoffset > img->height) 870 { 871 error(GL_INVALID_VALUE); 872 return false; 873 } 874 875 if (format != getFormat()) 876 { 877 error(GL_INVALID_OPERATION); 878 return false; 879 } 880 881 if (!img->surface) 882 { 883 createSurface(img->width, img->height, format, GL_UNSIGNED_BYTE, img); 884 } 885 886 if (pixels != NULL && img->surface != NULL) 887 { 888 RECT updateRegion; 889 updateRegion.left = xoffset; 890 updateRegion.right = xoffset + width; 891 updateRegion.bottom = yoffset + height; 892 updateRegion.top = yoffset; 893 894 D3DLOCKED_RECT locked; 895 HRESULT result = img->surface->LockRect(&locked, &updateRegion, 0); 896 897 ASSERT(SUCCEEDED(result)); 898 899 if (SUCCEEDED(result)) 900 { 901 GLsizei inputPitch = ComputeCompressedPitch(width, format); 902 int rows = imageSize / inputPitch; 903 for (int i = 0; i < rows; ++i) 904 { 905 memcpy((void*)((BYTE*)locked.pBits + i * locked.Pitch), (void*)((BYTE*)pixels + i * inputPitch), inputPitch); 906 } 907 img->surface->UnlockRect(); 908 } 909 910 img->dirty = true; 911 } 912 913 return true; 914 } 915 916 // This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats 917 void Texture::copyNonRenderable(Image *image, GLenum internalFormat, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget) 918 { 919 IDirect3DDevice9 *device = getDevice(); 920 IDirect3DSurface9 *surface = NULL; 921 D3DSURFACE_DESC description; 922 renderTarget->GetDesc(&description); 923 924 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &surface, NULL); 925 926 if (!SUCCEEDED(result)) 927 { 928 ERR("Could not create matching destination surface."); 929 return error(GL_OUT_OF_MEMORY); 930 } 931 932 result = device->GetRenderTargetData(renderTarget, surface); 933 934 if (!SUCCEEDED(result)) 935 { 936 ERR("GetRenderTargetData unexpectedly failed."); 937 surface->Release(); 938 return error(GL_OUT_OF_MEMORY); 939 } 940 941 D3DLOCKED_RECT sourceLock = {0}; 942 RECT sourceRect = {x, y, x + width, y + height}; 943 result = surface->LockRect(&sourceLock, &sourceRect, 0); 944 945 if (FAILED(result)) 946 { 947 ERR("Failed to lock the source surface (rectangle might be invalid)."); 948 surface->UnlockRect(); 949 surface->Release(); 950 return error(GL_OUT_OF_MEMORY); 951 } 952 953 if (!image->surface) 954 { 955 createSurface(width, height, internalFormat, mType, image); 956 } 957 958 if (image->surface == NULL) 959 { 960 ERR("Failed to create an image surface."); 961 surface->UnlockRect(); 962 surface->Release(); 963 return error(GL_OUT_OF_MEMORY); 964 } 965 966 D3DLOCKED_RECT destLock = {0}; 967 RECT destRect = {xoffset, yoffset, xoffset + width, yoffset + height}; 968 result = image->surface->LockRect(&destLock, &destRect, 0); 969 970 if (FAILED(result)) 971 { 972 ERR("Failed to lock the destination surface (rectangle might be invalid)."); 973 surface->UnlockRect(); 974 surface->Release(); 975 return error(GL_OUT_OF_MEMORY); 976 } 977 978 if (destLock.pBits && sourceLock.pBits) 979 { 980 unsigned char *source = (unsigned char*)sourceLock.pBits; 981 unsigned char *dest = (unsigned char*)destLock.pBits; 982 983 switch (description.Format) 984 { 985 case D3DFMT_X8R8G8B8: 986 case D3DFMT_A8R8G8B8: 987 switch(getD3DFormat()) 988 { 989 case D3DFMT_L8: 990 for(int y = 0; y < height; y++) 991 { 992 for(int x = 0; x < width; x++) 993 { 994 dest[x] = source[x * 4 + 2]; 995 } 996 997 source += sourceLock.Pitch; 998 dest += destLock.Pitch; 999 } 1000 break; 1001 case D3DFMT_A8L8: 1002 for(int y = 0; y < height; y++) 1003 { 1004 for(int x = 0; x < width; x++) 1005 { 1006 dest[x * 2 + 0] = source[x * 4 + 2]; 1007 dest[x * 2 + 1] = source[x * 4 + 3]; 1008 } 1009 1010 source += sourceLock.Pitch; 1011 dest += destLock.Pitch; 1012 } 1013 break; 1014 default: 1015 UNREACHABLE(); 1016 } 1017 break; 1018 case D3DFMT_R5G6B5: 1019 switch(getD3DFormat()) 1020 { 1021 case D3DFMT_L8: 1022 for(int y = 0; y < height; y++) 1023 { 1024 for(int x = 0; x < width; x++) 1025 { 1026 unsigned char red = source[x * 2 + 1] & 0xF8; 1027 dest[x] = red | (red >> 5); 1028 } 1029 1030 source += sourceLock.Pitch; 1031 dest += destLock.Pitch; 1032 } 1033 break; 1034 default: 1035 UNREACHABLE(); 1036 } 1037 break; 1038 case D3DFMT_A1R5G5B5: 1039 switch(getD3DFormat()) 1040 { 1041 case D3DFMT_L8: 1042 for(int y = 0; y < height; y++) 1043 { 1044 for(int x = 0; x < width; x++) 1045 { 1046 unsigned char red = source[x * 2 + 1] & 0x7C; 1047 dest[x] = (red << 1) | (red >> 4); 1048 } 1049 1050 source += sourceLock.Pitch; 1051 dest += destLock.Pitch; 1052 } 1053 break; 1054 case D3DFMT_A8L8: 1055 for(int y = 0; y < height; y++) 1056 { 1057 for(int x = 0; x < width; x++) 1058 { 1059 unsigned char red = source[x * 2 + 1] & 0x7C; 1060 dest[x * 2 + 0] = (red << 1) | (red >> 4); 1061 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7; 1062 } 1063 1064 source += sourceLock.Pitch; 1065 dest += destLock.Pitch; 1066 } 1067 break; 1068 default: 1069 UNREACHABLE(); 1070 } 1071 break; 1072 default: 1073 UNREACHABLE(); 1074 } 1075 1076 image->dirty = true; 1077 mDirtyMetaData = true; 1078 } 1079 1080 image->surface->UnlockRect(); 1081 surface->UnlockRect(); 1082 surface->Release(); 1083 } 1084 1085 D3DFORMAT Texture::getD3DFormat() const 1086 { 1087 return selectFormat(getFormat(), mType); 1088 } 1089 1090 IDirect3DBaseTexture9 *Texture::getTexture() 1091 { 1092 if (!isComplete()) 1093 { 1094 return NULL; 1095 } 1096 1097 if (mDirtyMetaData) 1098 { 1099 mBaseTexture = createTexture(); 1100 mIsRenderable = false; 1101 } 1102 1103 if (mDirtyMetaData || dirtyImageData()) 1104 { 1105 updateTexture(); 1106 } 1107 1108 mDirtyMetaData = false; 1109 ASSERT(!dirtyImageData()); 1110 1111 return mBaseTexture; 1112 } 1113 1114 bool Texture::isDirty() const 1115 { 1116 return (mDirty || mDirtyMetaData || dirtyImageData()); 1117 } 1118 1119 // Returns the top-level texture surface as a render target 1120 void Texture::needRenderTarget() 1121 { 1122 if (!mIsRenderable) 1123 { 1124 mBaseTexture = convertToRenderTarget(); 1125 mIsRenderable = true; 1126 } 1127 1128 if (dirtyImageData()) 1129 { 1130 updateTexture(); 1131 } 1132 1133 mDirtyMetaData = false; 1134 } 1135 1136 void Texture::dropTexture() 1137 { 1138 if (mBaseTexture) 1139 { 1140 mBaseTexture = NULL; 1141 } 1142 1143 mIsRenderable = false; 1144 } 1145 1146 void Texture::pushTexture(IDirect3DBaseTexture9 *newTexture, bool renderable) 1147 { 1148 mBaseTexture = newTexture; 1149 mDirtyMetaData = false; 1150 mIsRenderable = renderable; 1151 mDirty = true; 1152 } 1153 1154 1155 GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const 1156 { 1157 if (isPow2(width) && isPow2(height)) 1158 { 1159 return maxlevel; 1160 } 1161 else 1162 { 1163 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps. 1164 return 1; 1165 } 1166 } 1167 1168 GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const 1169 { 1170 return creationLevels(size, size, maxlevel); 1171 } 1172 1173 int Texture::levelCount() const 1174 { 1175 return mBaseTexture ? mBaseTexture->GetLevelCount() : 0; 1176 } 1177 1178 bool Texture::isRenderable() const 1179 { 1180 return mIsRenderable; 1181 } 1182 1183 Texture2D::Texture2D(GLuint id) : Texture(id) 1184 { 1185 mTexture = NULL; 1186 } 1187 1188 Texture2D::~Texture2D() 1189 { 1190 mColorbufferProxy.set(NULL); 1191 1192 if (mTexture) 1193 { 1194 mTexture->Release(); 1195 mTexture = NULL; 1196 } 1197 } 1198 1199 GLenum Texture2D::getTarget() const 1200 { 1201 return GL_TEXTURE_2D; 1202 } 1203 1204 GLenum Texture2D::getFormat() const 1205 { 1206 return mImageArray[0].format; 1207 } 1208 1209 // While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture 1210 // for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels. 1211 // Call this when a particular level of the texture must be defined with a specific format, width and height. 1212 // 1213 // Returns true if the existing texture was unsuitable and had to be destroyed. If so, it will also set 1214 // a new height and width for the texture by working backwards from the given width and height. 1215 bool Texture2D::redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum type) 1216 { 1217 bool widthOkay = (mWidth >> level == width); 1218 bool heightOkay = (mHeight >> level == height); 1219 1220 bool sizeOkay = ((widthOkay && heightOkay) 1221 || (widthOkay && mHeight >> level == 0 && height == 1) 1222 || (heightOkay && mWidth >> level == 0 && width == 1)); 1223 1224 bool typeOkay = (type == mType); 1225 1226 bool textureOkay = (sizeOkay && typeOkay && internalFormat == mImageArray[0].format); 1227 1228 if (!textureOkay) 1229 { 1230 TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level, 1231 mImageArray[0].format, mWidth, mHeight, 1232 internalFormat, width, height); 1233 1234 // Purge all the levels and the texture. 1235 1236 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) 1237 { 1238 if (mImageArray[i].surface != NULL) 1239 { 1240 mImageArray[i].dirty = false; 1241 1242 mImageArray[i].surface->Release(); 1243 mImageArray[i].surface = NULL; 1244 } 1245 } 1246 1247 if (mTexture != NULL) 1248 { 1249 mTexture->Release(); 1250 mTexture = NULL; 1251 dropTexture(); 1252 } 1253 1254 mWidth = width << level; 1255 mHeight = height << level; 1256 mImageArray[0].format = internalFormat; 1257 mType = type; 1258 } 1259 1260 return !textureOkay; 1261 } 1262 1263 void Texture2D::setImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) 1264 { 1265 redefineTexture(level, internalFormat, width, height, type); 1266 1267 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]); 1268 } 1269 1270 void Texture2D::setCompressedImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) 1271 { 1272 redefineTexture(level, internalFormat, width, height, GL_UNSIGNED_BYTE); 1273 1274 Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[level]); 1275 } 1276 1277 void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) 1278 { 1279 ASSERT(mImageArray[level].surface != NULL); 1280 1281 if (level < levelCount()) 1282 { 1283 IDirect3DSurface9 *destLevel = NULL; 1284 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel); 1285 1286 ASSERT(SUCCEEDED(result)); 1287 1288 if (SUCCEEDED(result)) 1289 { 1290 Image *img = &mImageArray[level]; 1291 1292 RECT sourceRect; 1293 sourceRect.left = xoffset; 1294 sourceRect.top = yoffset; 1295 sourceRect.right = xoffset + width; 1296 sourceRect.bottom = yoffset + height; 1297 1298 POINT destPoint; 1299 destPoint.x = xoffset; 1300 destPoint.y = yoffset; 1301 1302 result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint); 1303 ASSERT(SUCCEEDED(result)); 1304 1305 destLevel->Release(); 1306 1307 img->dirty = false; 1308 } 1309 } 1310 } 1311 1312 void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) 1313 { 1314 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level])) 1315 { 1316 commitRect(level, xoffset, yoffset, width, height); 1317 } 1318 } 1319 1320 void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels) 1321 { 1322 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level])) 1323 { 1324 commitRect(level, xoffset, yoffset, width, height); 1325 } 1326 } 1327 1328 void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source) 1329 { 1330 IDirect3DSurface9 *renderTarget = source->getRenderTarget(); 1331 1332 if (!renderTarget) 1333 { 1334 ERR("Failed to retrieve the render target."); 1335 return error(GL_OUT_OF_MEMORY); 1336 } 1337 1338 bool redefined = redefineTexture(level, internalFormat, width, height, mType); 1339 1340 if (!isRenderableFormat()) 1341 { 1342 copyNonRenderable(&mImageArray[level], internalFormat, 0, 0, x, y, width, height, renderTarget); 1343 } 1344 else 1345 { 1346 if (redefined) 1347 { 1348 convertToRenderTarget(); 1349 pushTexture(mTexture, true); 1350 } 1351 else 1352 { 1353 needRenderTarget(); 1354 } 1355 1356 if (width != 0 && height != 0 && level < levelCount()) 1357 { 1358 RECT sourceRect; 1359 sourceRect.left = x; 1360 sourceRect.right = x + width; 1361 sourceRect.top = y; 1362 sourceRect.bottom = y + height; 1363 1364 IDirect3DSurface9 *dest; 1365 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest); 1366 1367 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest); 1368 dest->Release(); 1369 } 1370 } 1371 1372 mImageArray[level].width = width; 1373 mImageArray[level].height = height; 1374 mImageArray[level].format = internalFormat; 1375 } 1376 1377 void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source) 1378 { 1379 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height) 1380 { 1381 return error(GL_INVALID_VALUE); 1382 } 1383 1384 IDirect3DSurface9 *renderTarget = source->getRenderTarget(); 1385 1386 if (!renderTarget) 1387 { 1388 ERR("Failed to retrieve the render target."); 1389 return error(GL_OUT_OF_MEMORY); 1390 } 1391 1392 bool redefined = redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height, mType); 1393 1394 if (!isRenderableFormat()) 1395 { 1396 copyNonRenderable(&mImageArray[level], getFormat(), xoffset, yoffset, x, y, width, height, renderTarget); 1397 } 1398 else 1399 { 1400 if (redefined) 1401 { 1402 convertToRenderTarget(); 1403 pushTexture(mTexture, true); 1404 } 1405 else 1406 { 1407 needRenderTarget(); 1408 } 1409 1410 if (level < levelCount()) 1411 { 1412 RECT sourceRect; 1413 sourceRect.left = x; 1414 sourceRect.right = x + width; 1415 sourceRect.top = y; 1416 sourceRect.bottom = y + height; 1417 1418 IDirect3DSurface9 *dest; 1419 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest); 1420 1421 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, yoffset, dest); 1422 dest->Release(); 1423 } 1424 } 1425 } 1426 1427 // Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. 1428 bool Texture2D::isComplete() const 1429 { 1430 GLsizei width = mImageArray[0].width; 1431 GLsizei height = mImageArray[0].height; 1432 1433 if (width <= 0 || height <= 0) 1434 { 1435 return false; 1436 } 1437 1438 bool mipmapping = false; 1439 1440 switch (mMinFilter) 1441 { 1442 case GL_NEAREST: 1443 case GL_LINEAR: 1444 mipmapping = false; 1445 break; 1446 case GL_NEAREST_MIPMAP_NEAREST: 1447 case GL_LINEAR_MIPMAP_NEAREST: 1448 case GL_NEAREST_MIPMAP_LINEAR: 1449 case GL_LINEAR_MIPMAP_LINEAR: 1450 mipmapping = true; 1451 break; 1452 default: UNREACHABLE(); 1453 } 1454 1455 if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) || 1456 (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter())) 1457 { 1458 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST)) 1459 { 1460 return false; 1461 } 1462 } 1463 1464 1465 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width)) 1466 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height))) 1467 { 1468 return false; 1469 } 1470 1471 if (mipmapping) 1472 { 1473 if (!isPow2(width) || !isPow2(height)) 1474 { 1475 return false; 1476 } 1477 1478 int q = log2(std::max(width, height)); 1479 1480 for (int level = 1; level <= q; level++) 1481 { 1482 if (mImageArray[level].format != mImageArray[0].format) 1483 { 1484 return false; 1485 } 1486 1487 if (mImageArray[level].width != std::max(1, width >> level)) 1488 { 1489 return false; 1490 } 1491 1492 if (mImageArray[level].height != std::max(1, height >> level)) 1493 { 1494 return false; 1495 } 1496 } 1497 } 1498 1499 return true; 1500 } 1501 1502 bool Texture2D::isCompressed() const 1503 { 1504 return IsCompressed(getFormat()); 1505 } 1506 1507 // Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one 1508 IDirect3DBaseTexture9 *Texture2D::createTexture() 1509 { 1510 IDirect3DTexture9 *texture; 1511 1512 IDirect3DDevice9 *device = getDevice(); 1513 D3DFORMAT format = selectFormat(mImageArray[0].format, mType); 1514 1515 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL); 1516 1517 if (FAILED(result)) 1518 { 1519 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); 1520 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL); 1521 } 1522 1523 if (mTexture) mTexture->Release(); 1524 mTexture = texture; 1525 return texture; 1526 } 1527 1528 void Texture2D::updateTexture() 1529 { 1530 IDirect3DDevice9 *device = getDevice(); 1531 1532 int levels = levelCount(); 1533 1534 for (int level = 0; level < levels; level++) 1535 { 1536 if (mImageArray[level].dirty) 1537 { 1538 IDirect3DSurface9 *levelSurface = NULL; 1539 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface); 1540 1541 ASSERT(SUCCEEDED(result)); 1542 1543 if (SUCCEEDED(result)) 1544 { 1545 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL); 1546 ASSERT(SUCCEEDED(result)); 1547 1548 levelSurface->Release(); 1549 1550 mImageArray[level].dirty = false; 1551 } 1552 } 1553 } 1554 } 1555 1556 IDirect3DBaseTexture9 *Texture2D::convertToRenderTarget() 1557 { 1558 IDirect3DTexture9 *texture = NULL; 1559 1560 if (mWidth != 0 && mHeight != 0) 1561 { 1562 egl::Display *display = getDisplay(); 1563 IDirect3DDevice9 *device = getDevice(); 1564 D3DFORMAT format = selectFormat(mImageArray[0].format, mType); 1565 1566 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL); 1567 1568 if (FAILED(result)) 1569 { 1570 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); 1571 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL); 1572 } 1573 1574 if (mTexture != NULL) 1575 { 1576 int levels = levelCount(); 1577 for (int i = 0; i < levels; i++) 1578 { 1579 IDirect3DSurface9 *source; 1580 result = mTexture->GetSurfaceLevel(i, &source); 1581 1582 if (FAILED(result)) 1583 { 1584 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); 1585 1586 texture->Release(); 1587 1588 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL); 1589 } 1590 1591 IDirect3DSurface9 *dest; 1592 result = texture->GetSurfaceLevel(i, &dest); 1593 1594 if (FAILED(result)) 1595 { 1596 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); 1597 1598 texture->Release(); 1599 source->Release(); 1600 1601 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL); 1602 } 1603 1604 display->endScene(); 1605 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE); 1606 1607 if (FAILED(result)) 1608 { 1609 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); 1610 1611 texture->Release(); 1612 source->Release(); 1613 dest->Release(); 1614 1615 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL); 1616 } 1617 1618 source->Release(); 1619 dest->Release(); 1620 } 1621 } 1622 } 1623 1624 if (mTexture != NULL) 1625 { 1626 mTexture->Release(); 1627 } 1628 1629 mTexture = texture; 1630 return mTexture; 1631 } 1632 1633 bool Texture2D::dirtyImageData() const 1634 { 1635 int q = log2(std::max(mWidth, mHeight)); 1636 1637 for (int i = 0; i <= q; i++) 1638 { 1639 if (mImageArray[i].dirty) return true; 1640 } 1641 1642 return false; 1643 } 1644 1645 void Texture2D::generateMipmaps() 1646 { 1647 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height)) 1648 { 1649 return error(GL_INVALID_OPERATION); 1650 } 1651 1652 // Purge array levels 1 through q and reset them to represent the generated mipmap levels. 1653 unsigned int q = log2(std::max(mWidth, mHeight)); 1654 for (unsigned int i = 1; i <= q; i++) 1655 { 1656 if (mImageArray[i].surface != NULL) 1657 { 1658 mImageArray[i].surface->Release(); 1659 mImageArray[i].surface = NULL; 1660 } 1661 1662 mImageArray[i].dirty = false; 1663 1664 mImageArray[i].format = mImageArray[0].format; 1665 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1); 1666 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1); 1667 } 1668 1669 if (isRenderable()) 1670 { 1671 if (mTexture == NULL) 1672 { 1673 ERR(" failed because mTexture was null."); 1674 return; 1675 } 1676 1677 for (unsigned int i = 1; i <= q; i++) 1678 { 1679 IDirect3DSurface9 *upper = NULL; 1680 IDirect3DSurface9 *lower = NULL; 1681 1682 mTexture->GetSurfaceLevel(i-1, &upper); 1683 mTexture->GetSurfaceLevel(i, &lower); 1684 1685 if (upper != NULL && lower != NULL) 1686 { 1687 getBlitter()->boxFilter(upper, lower); 1688 } 1689 1690 if (upper != NULL) upper->Release(); 1691 if (lower != NULL) lower->Release(); 1692 } 1693 } 1694 else 1695 { 1696 for (unsigned int i = 1; i <= q; i++) 1697 { 1698 createSurface(mImageArray[i].width, mImageArray[i].height, mImageArray[i].format, mType, &mImageArray[i]); 1699 if (mImageArray[i].surface == NULL) 1700 { 1701 return error(GL_OUT_OF_MEMORY); 1702 } 1703 1704 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0))) 1705 { 1706 ERR(" failed to load filter %d to %d.", i - 1, i); 1707 } 1708 1709 mImageArray[i].dirty = true; 1710 } 1711 1712 mDirtyMetaData = true; 1713 } 1714 } 1715 1716 Renderbuffer *Texture2D::getColorbuffer(GLenum target) 1717 { 1718 if (target != GL_TEXTURE_2D) 1719 { 1720 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL); 1721 } 1722 1723 if (mColorbufferProxy.get() == NULL) 1724 { 1725 mColorbufferProxy.set(new Renderbuffer(id(), new TextureColorbufferProxy(this, target))); 1726 } 1727 1728 return mColorbufferProxy.get(); 1729 } 1730 1731 IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target) 1732 { 1733 ASSERT(target == GL_TEXTURE_2D); 1734 1735 needRenderTarget(); 1736 1737 if (mTexture == NULL) 1738 { 1739 return NULL; 1740 } 1741 1742 IDirect3DSurface9 *renderTarget = NULL; 1743 mTexture->GetSurfaceLevel(0, &renderTarget); 1744 1745 return renderTarget; 1746 } 1747 1748 TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id) 1749 { 1750 mTexture = NULL; 1751 } 1752 1753 TextureCubeMap::~TextureCubeMap() 1754 { 1755 for (int i = 0; i < 6; i++) 1756 { 1757 mFaceProxies[i].set(NULL); 1758 } 1759 1760 if (mTexture) 1761 { 1762 mTexture->Release(); 1763 mTexture = NULL; 1764 } 1765 } 1766 1767 GLenum TextureCubeMap::getTarget() const 1768 { 1769 return GL_TEXTURE_CUBE_MAP; 1770 } 1771 1772 GLenum TextureCubeMap::getFormat() const 1773 { 1774 return mImageArray[0][0].format; 1775 } 1776 1777 void TextureCubeMap::setImagePosX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) 1778 { 1779 setImage(0, level, internalFormat, width, height, format, type, unpackAlignment, pixels); 1780 } 1781 1782 void TextureCubeMap::setImageNegX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) 1783 { 1784 setImage(1, level, internalFormat, width, height, format, type, unpackAlignment, pixels); 1785 } 1786 1787 void TextureCubeMap::setImagePosY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) 1788 { 1789 setImage(2, level, internalFormat, width, height, format, type, unpackAlignment, pixels); 1790 } 1791 1792 void TextureCubeMap::setImageNegY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) 1793 { 1794 setImage(3, level, internalFormat, width, height, format, type, unpackAlignment, pixels); 1795 } 1796 1797 void TextureCubeMap::setImagePosZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) 1798 { 1799 setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels); 1800 } 1801 1802 void TextureCubeMap::setImageNegZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) 1803 { 1804 setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels); 1805 } 1806 1807 void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) 1808 { 1809 redefineTexture(level, internalFormat, width); 1810 1811 Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[faceIndex(face)][level]); 1812 } 1813 1814 void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) 1815 { 1816 int face = faceIndex(faceTarget); 1817 1818 ASSERT(mImageArray[face][level].surface != NULL); 1819 1820 if (level < levelCount()) 1821 { 1822 IDirect3DSurface9 *destLevel = getCubeMapSurface(face, level); 1823 ASSERT(destLevel != NULL); 1824 1825 if (destLevel != NULL) 1826 { 1827 Image *img = &mImageArray[face][level]; 1828 1829 RECT sourceRect; 1830 sourceRect.left = xoffset; 1831 sourceRect.top = yoffset; 1832 sourceRect.right = xoffset + width; 1833 sourceRect.bottom = yoffset + height; 1834 1835 POINT destPoint; 1836 destPoint.x = xoffset; 1837 destPoint.y = yoffset; 1838 1839 HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint); 1840 ASSERT(SUCCEEDED(result)); 1841 1842 destLevel->Release(); 1843 1844 img->dirty = false; 1845 } 1846 } 1847 } 1848 1849 void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) 1850 { 1851 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level])) 1852 { 1853 commitRect(target, level, xoffset, yoffset, width, height); 1854 } 1855 } 1856 1857 void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels) 1858 { 1859 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level])) 1860 { 1861 commitRect(target, level, xoffset, yoffset, width, height); 1862 } 1863 } 1864 1865 // Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. 1866 bool TextureCubeMap::isComplete() const 1867 { 1868 int size = mImageArray[0][0].width; 1869 1870 if (size <= 0) 1871 { 1872 return false; 1873 } 1874 1875 bool mipmapping; 1876 1877 switch (mMinFilter) 1878 { 1879 case GL_NEAREST: 1880 case GL_LINEAR: 1881 mipmapping = false; 1882 break; 1883 case GL_NEAREST_MIPMAP_NEAREST: 1884 case GL_LINEAR_MIPMAP_NEAREST: 1885 case GL_NEAREST_MIPMAP_LINEAR: 1886 case GL_LINEAR_MIPMAP_LINEAR: 1887 mipmapping = true; 1888 break; 1889 default: UNREACHABLE(); 1890 } 1891 1892 for (int face = 0; face < 6; face++) 1893 { 1894 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size) 1895 { 1896 return false; 1897 } 1898 } 1899 1900 if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) || 1901 (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter())) 1902 { 1903 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST)) 1904 { 1905 return false; 1906 } 1907 } 1908 1909 if (mipmapping) 1910 { 1911 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE)) 1912 { 1913 return false; 1914 } 1915 1916 int q = log2(size); 1917 1918 for (int face = 0; face < 6; face++) 1919 { 1920 for (int level = 1; level <= q; level++) 1921 { 1922 if (mImageArray[face][level].format != mImageArray[0][0].format) 1923 { 1924 return false; 1925 } 1926 1927 if (mImageArray[face][level].width != std::max(1, size >> level)) 1928 { 1929 return false; 1930 } 1931 1932 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width); 1933 } 1934 } 1935 } 1936 1937 return true; 1938 } 1939 1940 bool TextureCubeMap::isCompressed() const 1941 { 1942 return IsCompressed(getFormat()); 1943 } 1944 1945 // Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one 1946 IDirect3DBaseTexture9 *TextureCubeMap::createTexture() 1947 { 1948 IDirect3DDevice9 *device = getDevice(); 1949 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType); 1950 1951 IDirect3DCubeTexture9 *texture; 1952 1953 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL); 1954 1955 if (FAILED(result)) 1956 { 1957 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); 1958 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL); 1959 } 1960 1961 if (mTexture) mTexture->Release(); 1962 1963 mTexture = texture; 1964 return mTexture; 1965 } 1966 1967 void TextureCubeMap::updateTexture() 1968 { 1969 IDirect3DDevice9 *device = getDevice(); 1970 1971 for (int face = 0; face < 6; face++) 1972 { 1973 int levels = levelCount(); 1974 for (int level = 0; level < levels; level++) 1975 { 1976 Image *img = &mImageArray[face][level]; 1977 1978 if (img->dirty) 1979 { 1980 IDirect3DSurface9 *levelSurface = getCubeMapSurface(face, level); 1981 ASSERT(levelSurface != NULL); 1982 1983 if (levelSurface != NULL) 1984 { 1985 HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL); 1986 ASSERT(SUCCEEDED(result)); 1987 1988 levelSurface->Release(); 1989 1990 img->dirty = false; 1991 } 1992 } 1993 } 1994 } 1995 } 1996 1997 IDirect3DBaseTexture9 *TextureCubeMap::convertToRenderTarget() 1998 { 1999 IDirect3DCubeTexture9 *texture = NULL; 2000 2001 if (mWidth != 0) 2002 { 2003 egl::Display *display = getDisplay(); 2004 IDirect3DDevice9 *device = getDevice(); 2005 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType); 2006 2007 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL); 2008 2009 if (FAILED(result)) 2010 { 2011 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); 2012 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL); 2013 } 2014 2015 if (mTexture != NULL) 2016 { 2017 int levels = levelCount(); 2018 for (int f = 0; f < 6; f++) 2019 { 2020 for (int i = 0; i < levels; i++) 2021 { 2022 IDirect3DSurface9 *source; 2023 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source); 2024 2025 if (FAILED(result)) 2026 { 2027 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); 2028 2029 texture->Release(); 2030 2031 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL); 2032 } 2033 2034 IDirect3DSurface9 *dest; 2035 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest); 2036 2037 if (FAILED(result)) 2038 { 2039 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); 2040 2041 texture->Release(); 2042 source->Release(); 2043 2044 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL); 2045 } 2046 2047 display->endScene(); 2048 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE); 2049 2050 if (FAILED(result)) 2051 { 2052 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); 2053 2054 texture->Release(); 2055 source->Release(); 2056 dest->Release(); 2057 2058 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL); 2059 } 2060 } 2061 } 2062 } 2063 } 2064 2065 if (mTexture != NULL) 2066 { 2067 mTexture->Release(); 2068 } 2069 2070 mTexture = texture; 2071 return mTexture; 2072 } 2073 2074 void TextureCubeMap::setImage(int face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) 2075 { 2076 redefineTexture(level, internalFormat, width); 2077 2078 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]); 2079 } 2080 2081 unsigned int TextureCubeMap::faceIndex(GLenum face) 2082 { 2083 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1); 2084 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2); 2085 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3); 2086 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4); 2087 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5); 2088 2089 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X; 2090 } 2091 2092 bool TextureCubeMap::dirtyImageData() const 2093 { 2094 int q = log2(mWidth); 2095 2096 for (int f = 0; f < 6; f++) 2097 { 2098 for (int i = 0; i <= q; i++) 2099 { 2100 if (mImageArray[f][i].dirty) return true; 2101 } 2102 } 2103 2104 return false; 2105 } 2106 2107 // While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture 2108 // for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces. 2109 // Call this when a particular level of the texture must be defined with a specific format, width and height. 2110 // 2111 // Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set 2112 // a new size for the texture by working backwards from the given size. 2113 bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei width) 2114 { 2115 // Are these settings compatible with level 0? 2116 bool sizeOkay = (mImageArray[0][0].width >> level == width); 2117 2118 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0][0].format); 2119 2120 if (!textureOkay) 2121 { 2122 TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level, 2123 mImageArray[0][0].format, mImageArray[0][0].width, 2124 internalFormat, width); 2125 2126 // Purge all the levels and the texture. 2127 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) 2128 { 2129 for (int f = 0; f < 6; f++) 2130 { 2131 if (mImageArray[f][i].surface != NULL) 2132 { 2133 mImageArray[f][i].dirty = false; 2134 2135 mImageArray[f][i].surface->Release(); 2136 mImageArray[f][i].surface = NULL; 2137 } 2138 } 2139 } 2140 2141 if (mTexture != NULL) 2142 { 2143 mTexture->Release(); 2144 mTexture = NULL; 2145 dropTexture(); 2146 } 2147 2148 mWidth = width << level; 2149 mImageArray[0][0].width = width << level; 2150 mHeight = width << level; 2151 mImageArray[0][0].height = width << level; 2152 2153 mImageArray[0][0].format = internalFormat; 2154 } 2155 2156 return !textureOkay; 2157 } 2158 2159 void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source) 2160 { 2161 IDirect3DSurface9 *renderTarget = source->getRenderTarget(); 2162 2163 if (!renderTarget) 2164 { 2165 ERR("Failed to retrieve the render target."); 2166 return error(GL_OUT_OF_MEMORY); 2167 } 2168 2169 unsigned int faceindex = faceIndex(target); 2170 bool redefined = redefineTexture(level, internalFormat, width); 2171 2172 if (!isRenderableFormat()) 2173 { 2174 copyNonRenderable(&mImageArray[faceindex][level], internalFormat, 0, 0, x, y, width, height, renderTarget); 2175 } 2176 else 2177 { 2178 if (redefined) 2179 { 2180 convertToRenderTarget(); 2181 pushTexture(mTexture, true); 2182 } 2183 else 2184 { 2185 needRenderTarget(); 2186 } 2187 2188 ASSERT(width == height); 2189 2190 if (width > 0 && level < levelCount()) 2191 { 2192 RECT sourceRect; 2193 sourceRect.left = x; 2194 sourceRect.right = x + width; 2195 sourceRect.top = y; 2196 sourceRect.bottom = y + height; 2197 2198 IDirect3DSurface9 *dest = getCubeMapSurface(target, level); 2199 2200 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest); 2201 dest->Release(); 2202 } 2203 } 2204 2205 mImageArray[faceindex][level].width = width; 2206 mImageArray[faceindex][level].height = height; 2207 mImageArray[faceindex][level].format = internalFormat; 2208 } 2209 2210 IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(unsigned int faceIdentifier, unsigned int level) 2211 { 2212 unsigned int faceIndex; 2213 2214 if (faceIdentifier < 6) 2215 { 2216 faceIndex = faceIdentifier; 2217 } 2218 else if (faceIdentifier >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && faceIdentifier <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) 2219 { 2220 faceIndex = faceIdentifier - GL_TEXTURE_CUBE_MAP_POSITIVE_X; 2221 } 2222 else 2223 { 2224 UNREACHABLE(); 2225 faceIndex = 0; 2226 } 2227 2228 if (mTexture == NULL) 2229 { 2230 UNREACHABLE(); 2231 return NULL; 2232 } 2233 2234 IDirect3DSurface9 *surface = NULL; 2235 2236 HRESULT hr = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex), level, &surface); 2237 2238 return (SUCCEEDED(hr)) ? surface : NULL; 2239 } 2240 2241 void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source) 2242 { 2243 GLsizei size = mImageArray[faceIndex(target)][level].width; 2244 2245 if (xoffset + width > size || yoffset + height > size) 2246 { 2247 return error(GL_INVALID_VALUE); 2248 } 2249 2250 IDirect3DSurface9 *renderTarget = source->getRenderTarget(); 2251 2252 if (!renderTarget) 2253 { 2254 ERR("Failed to retrieve the render target."); 2255 return error(GL_OUT_OF_MEMORY); 2256 } 2257 2258 unsigned int faceindex = faceIndex(target); 2259 bool redefined = redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width); 2260 2261 if (!isRenderableFormat()) 2262 { 2263 copyNonRenderable(&mImageArray[faceindex][level], getFormat(), 0, 0, x, y, width, height, renderTarget); 2264 } 2265 else 2266 { 2267 if (redefined) 2268 { 2269 convertToRenderTarget(); 2270 pushTexture(mTexture, true); 2271 } 2272 else 2273 { 2274 needRenderTarget(); 2275 } 2276 2277 if (level < levelCount()) 2278 { 2279 RECT sourceRect; 2280 sourceRect.left = x; 2281 sourceRect.right = x + width; 2282 sourceRect.top = y; 2283 sourceRect.bottom = y + height; 2284 2285 IDirect3DSurface9 *dest = getCubeMapSurface(target, level); 2286 2287 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, yoffset, dest); 2288 dest->Release(); 2289 } 2290 } 2291 } 2292 2293 bool TextureCubeMap::isCubeComplete() const 2294 { 2295 if (mImageArray[0][0].width == 0) 2296 { 2297 return false; 2298 } 2299 2300 for (unsigned int f = 1; f < 6; f++) 2301 { 2302 if (mImageArray[f][0].width != mImageArray[0][0].width 2303 || mImageArray[f][0].format != mImageArray[0][0].format) 2304 { 2305 return false; 2306 } 2307 } 2308 2309 return true; 2310 } 2311 2312 void TextureCubeMap::generateMipmaps() 2313 { 2314 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete()) 2315 { 2316 return error(GL_INVALID_OPERATION); 2317 } 2318 2319 // Purge array levels 1 through q and reset them to represent the generated mipmap levels. 2320 unsigned int q = log2(mImageArray[0][0].width); 2321 for (unsigned int f = 0; f < 6; f++) 2322 { 2323 for (unsigned int i = 1; i <= q; i++) 2324 { 2325 if (mImageArray[f][i].surface != NULL) 2326 { 2327 mImageArray[f][i].surface->Release(); 2328 mImageArray[f][i].surface = NULL; 2329 } 2330 2331 mImageArray[f][i].dirty = false; 2332 2333 mImageArray[f][i].format = mImageArray[f][0].format; 2334 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1); 2335 mImageArray[f][i].height = mImageArray[f][i].width; 2336 } 2337 } 2338 2339 if (isRenderable()) 2340 { 2341 if (mTexture == NULL) 2342 { 2343 return; 2344 } 2345 2346 for (unsigned int f = 0; f < 6; f++) 2347 { 2348 for (unsigned int i = 1; i <= q; i++) 2349 { 2350 IDirect3DSurface9 *upper = getCubeMapSurface(f, i-1); 2351 IDirect3DSurface9 *lower = getCubeMapSurface(f, i); 2352 2353 if (upper != NULL && lower != NULL) 2354 { 2355 getBlitter()->boxFilter(upper, lower); 2356 } 2357 2358 if (upper != NULL) upper->Release(); 2359 if (lower != NULL) lower->Release(); 2360 } 2361 } 2362 } 2363 else 2364 { 2365 for (unsigned int f = 0; f < 6; f++) 2366 { 2367 for (unsigned int i = 1; i <= q; i++) 2368 { 2369 createSurface(mImageArray[f][i].width, mImageArray[f][i].height, mImageArray[f][i].format, mType, &mImageArray[f][i]); 2370 if (mImageArray[f][i].surface == NULL) 2371 { 2372 return error(GL_OUT_OF_MEMORY); 2373 } 2374 2375 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0))) 2376 { 2377 ERR(" failed to load filter %d to %d.", i - 1, i); 2378 } 2379 2380 mImageArray[f][i].dirty = true; 2381 } 2382 } 2383 2384 mDirtyMetaData = true; 2385 } 2386 } 2387 2388 Renderbuffer *TextureCubeMap::getColorbuffer(GLenum target) 2389 { 2390 if (!IsCubemapTextureTarget(target)) 2391 { 2392 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL); 2393 } 2394 2395 unsigned int face = faceIndex(target); 2396 2397 if (mFaceProxies[face].get() == NULL) 2398 { 2399 mFaceProxies[face].set(new Renderbuffer(id(), new TextureColorbufferProxy(this, target))); 2400 } 2401 2402 return mFaceProxies[face].get(); 2403 } 2404 2405 IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target) 2406 { 2407 ASSERT(IsCubemapTextureTarget(target)); 2408 2409 needRenderTarget(); 2410 2411 if (mTexture == NULL) 2412 { 2413 return NULL; 2414 } 2415 2416 IDirect3DSurface9 *renderTarget = NULL; 2417 mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex(target)), 0, &renderTarget); 2418 2419 return renderTarget; 2420 } 2421 2422 Texture::TextureColorbufferProxy::TextureColorbufferProxy(Texture *texture, GLenum target) 2423 : Colorbuffer(texture), mTexture(texture), mTarget(target) 2424 { 2425 ASSERT(IsTextureTarget(target)); 2426 } 2427 2428 void Texture::TextureColorbufferProxy::addRef() const 2429 { 2430 mTexture->addRef(); 2431 } 2432 2433 void Texture::TextureColorbufferProxy::release() const 2434 { 2435 mTexture->release(); 2436 } 2437 2438 IDirect3DSurface9 *Texture::TextureColorbufferProxy::getRenderTarget() 2439 { 2440 if (mRenderTarget) mRenderTarget->Release(); 2441 2442 mRenderTarget = mTexture->getRenderTarget(mTarget); 2443 2444 return mRenderTarget; 2445 } 2446 2447 int Texture::TextureColorbufferProxy::getWidth() const 2448 { 2449 return mTexture->getWidth(); 2450 } 2451 2452 int Texture::TextureColorbufferProxy::getHeight() const 2453 { 2454 return mTexture->getHeight(); 2455 } 2456 2457 GLenum Texture::TextureColorbufferProxy::getFormat() const 2458 { 2459 return mTexture->getFormat(); 2460 } 2461 2462 bool Texture::TextureColorbufferProxy::isFloatingPoint() const 2463 { 2464 return mTexture->isFloatingPoint(); 2465 } 2466 2467 } 2468