1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Texture.cpp: Implements the Texture class and its derived classes 16 // Texture2D, TextureCubeMap, Texture3D and Texture2DArray. Implements GL texture objects 17 // and related functionality. [OpenGL ES 2.0.24] section 3.7 page 63. 18 19 #include "Texture.h" 20 21 #include "main.h" 22 #include "mathutil.h" 23 #include "Framebuffer.h" 24 #include "Device.hpp" 25 #include "libEGL/Display.h" 26 #include "libEGL/Surface.h" 27 #include "common/debug.h" 28 29 #include <algorithm> 30 31 namespace es2 32 { 33 34 Texture::Texture(GLuint name) : egl::Texture(name) 35 { 36 mMinFilter = GL_NEAREST_MIPMAP_LINEAR; 37 mMagFilter = GL_LINEAR; 38 mWrapS = GL_REPEAT; 39 mWrapT = GL_REPEAT; 40 mWrapR = GL_REPEAT; 41 mMaxAnisotropy = 1.0f; 42 mBaseLevel = 0; 43 mCompareFunc = GL_LEQUAL; 44 mCompareMode = GL_NONE; 45 mImmutableFormat = GL_FALSE; 46 mImmutableLevels = 0; 47 mMaxLevel = 1000; 48 mMaxLOD = 1000; 49 mMinLOD = -1000; 50 mSwizzleR = GL_RED; 51 mSwizzleG = GL_GREEN; 52 mSwizzleB = GL_BLUE; 53 mSwizzleA = GL_ALPHA; 54 55 resource = new sw::Resource(0); 56 } 57 58 Texture::~Texture() 59 { 60 resource->destruct(); 61 } 62 63 sw::Resource *Texture::getResource() const 64 { 65 return resource; 66 } 67 68 // Returns true on successful filter state update (valid enum parameter) 69 bool Texture::setMinFilter(GLenum filter) 70 { 71 switch(filter) 72 { 73 case GL_NEAREST_MIPMAP_NEAREST: 74 case GL_LINEAR_MIPMAP_NEAREST: 75 case GL_NEAREST_MIPMAP_LINEAR: 76 case GL_LINEAR_MIPMAP_LINEAR: 77 if(getTarget() == GL_TEXTURE_EXTERNAL_OES) 78 { 79 return false; 80 } 81 // Fall through 82 case GL_NEAREST: 83 case GL_LINEAR: 84 mMinFilter = filter; 85 return true; 86 default: 87 return false; 88 } 89 } 90 91 // Returns true on successful filter state update (valid enum parameter) 92 bool Texture::setMagFilter(GLenum filter) 93 { 94 switch(filter) 95 { 96 case GL_NEAREST: 97 case GL_LINEAR: 98 mMagFilter = filter; 99 return true; 100 default: 101 return false; 102 } 103 } 104 105 // Returns true on successful wrap state update (valid enum parameter) 106 bool Texture::setWrapS(GLenum wrap) 107 { 108 switch(wrap) 109 { 110 case GL_REPEAT: 111 case GL_MIRRORED_REPEAT: 112 if(getTarget() == GL_TEXTURE_EXTERNAL_OES) 113 { 114 return false; 115 } 116 // Fall through 117 case GL_CLAMP_TO_EDGE: 118 mWrapS = wrap; 119 return true; 120 default: 121 return false; 122 } 123 } 124 125 // Returns true on successful wrap state update (valid enum parameter) 126 bool Texture::setWrapT(GLenum wrap) 127 { 128 switch(wrap) 129 { 130 case GL_REPEAT: 131 case GL_MIRRORED_REPEAT: 132 if(getTarget() == GL_TEXTURE_EXTERNAL_OES) 133 { 134 return false; 135 } 136 // Fall through 137 case GL_CLAMP_TO_EDGE: 138 mWrapT = wrap; 139 return true; 140 default: 141 return false; 142 } 143 } 144 145 // Returns true on successful wrap state update (valid enum parameter) 146 bool Texture::setWrapR(GLenum wrap) 147 { 148 switch(wrap) 149 { 150 case GL_REPEAT: 151 case GL_MIRRORED_REPEAT: 152 if(getTarget() == GL_TEXTURE_EXTERNAL_OES) 153 { 154 return false; 155 } 156 // Fall through 157 case GL_CLAMP_TO_EDGE: 158 mWrapR = wrap; 159 return true; 160 default: 161 return false; 162 } 163 } 164 165 // Returns true on successful max anisotropy update (valid anisotropy value) 166 bool Texture::setMaxAnisotropy(float textureMaxAnisotropy) 167 { 168 textureMaxAnisotropy = std::min(textureMaxAnisotropy, MAX_TEXTURE_MAX_ANISOTROPY); 169 170 if(textureMaxAnisotropy < 1.0f) 171 { 172 return false; 173 } 174 175 if(mMaxAnisotropy != textureMaxAnisotropy) 176 { 177 mMaxAnisotropy = textureMaxAnisotropy; 178 } 179 180 return true; 181 } 182 183 bool Texture::setBaseLevel(GLint baseLevel) 184 { 185 mBaseLevel = baseLevel; 186 return true; 187 } 188 189 bool Texture::setCompareFunc(GLenum compareFunc) 190 { 191 switch(compareFunc) 192 { 193 case GL_LEQUAL: 194 case GL_GEQUAL: 195 case GL_LESS: 196 case GL_GREATER: 197 case GL_EQUAL: 198 case GL_NOTEQUAL: 199 case GL_ALWAYS: 200 case GL_NEVER: 201 mCompareFunc = compareFunc; 202 return true; 203 default: 204 return false; 205 } 206 } 207 208 bool Texture::setCompareMode(GLenum compareMode) 209 { 210 switch(compareMode) 211 { 212 case GL_COMPARE_REF_TO_TEXTURE: 213 case GL_NONE: 214 mCompareMode = compareMode; 215 return true; 216 default: 217 return false; 218 } 219 } 220 221 void Texture::makeImmutable(GLsizei levels) 222 { 223 mImmutableFormat = GL_TRUE; 224 mImmutableLevels = levels; 225 } 226 227 bool Texture::setMaxLevel(GLint maxLevel) 228 { 229 mMaxLevel = maxLevel; 230 return true; 231 } 232 233 bool Texture::setMaxLOD(GLfloat maxLOD) 234 { 235 mMaxLOD = maxLOD; 236 return true; 237 } 238 239 bool Texture::setMinLOD(GLfloat minLOD) 240 { 241 mMinLOD = minLOD; 242 return true; 243 } 244 245 bool Texture::setSwizzleR(GLenum swizzleR) 246 { 247 switch(swizzleR) 248 { 249 case GL_RED: 250 case GL_GREEN: 251 case GL_BLUE: 252 case GL_ALPHA: 253 case GL_ZERO: 254 case GL_ONE: 255 mSwizzleR = swizzleR; 256 return true; 257 default: 258 return false; 259 } 260 } 261 262 bool Texture::setSwizzleG(GLenum swizzleG) 263 { 264 switch(swizzleG) 265 { 266 case GL_RED: 267 case GL_GREEN: 268 case GL_BLUE: 269 case GL_ALPHA: 270 case GL_ZERO: 271 case GL_ONE: 272 mSwizzleG = swizzleG; 273 return true; 274 default: 275 return false; 276 } 277 } 278 279 bool Texture::setSwizzleB(GLenum swizzleB) 280 { 281 switch(swizzleB) 282 { 283 case GL_RED: 284 case GL_GREEN: 285 case GL_BLUE: 286 case GL_ALPHA: 287 case GL_ZERO: 288 case GL_ONE: 289 mSwizzleB = swizzleB; 290 return true; 291 default: 292 return false; 293 } 294 } 295 296 bool Texture::setSwizzleA(GLenum swizzleA) 297 { 298 switch(swizzleA) 299 { 300 case GL_RED: 301 case GL_GREEN: 302 case GL_BLUE: 303 case GL_ALPHA: 304 case GL_ZERO: 305 case GL_ONE: 306 mSwizzleA = swizzleA; 307 return true; 308 default: 309 return false; 310 } 311 } 312 313 GLenum Texture::getMinFilter() const 314 { 315 return mMinFilter; 316 } 317 318 GLenum Texture::getMagFilter() const 319 { 320 return mMagFilter; 321 } 322 323 GLenum Texture::getWrapS() const 324 { 325 return mWrapS; 326 } 327 328 GLenum Texture::getWrapT() const 329 { 330 return mWrapT; 331 } 332 333 GLenum Texture::getWrapR() const 334 { 335 return mWrapR; 336 } 337 338 GLfloat Texture::getMaxAnisotropy() const 339 { 340 return mMaxAnisotropy; 341 } 342 343 GLint Texture::getBaseLevel() const 344 { 345 return mBaseLevel; 346 } 347 GLenum Texture::getCompareFunc() const 348 { 349 return mCompareFunc; 350 } 351 GLenum Texture::getCompareMode() const 352 { 353 return mCompareMode; 354 } 355 GLboolean Texture::getImmutableFormat() const 356 { 357 return mImmutableFormat; 358 } 359 GLsizei Texture::getImmutableLevels() const 360 { 361 return mImmutableLevels; 362 } 363 GLint Texture::getMaxLevel() const 364 { 365 return mMaxLevel; 366 } 367 GLfloat Texture::getMaxLOD() const 368 { 369 return mMaxLOD; 370 } 371 GLfloat Texture::getMinLOD() const 372 { 373 return mMinLOD; 374 } 375 GLenum Texture::getSwizzleR() const 376 { 377 return mSwizzleR; 378 } 379 GLenum Texture::getSwizzleG() const 380 { 381 return mSwizzleG; 382 } 383 GLenum Texture::getSwizzleB() const 384 { 385 return mSwizzleB; 386 } 387 GLenum Texture::getSwizzleA() const 388 { 389 return mSwizzleA; 390 } 391 392 GLsizei Texture::getDepth(GLenum target, GLint level) const 393 { 394 return 1; 395 } 396 397 egl::Image *Texture::createSharedImage(GLenum target, unsigned int level) 398 { 399 egl::Image *image = getRenderTarget(target, level); // Increments reference count 400 401 if(image) 402 { 403 image->markShared(); 404 } 405 406 return image; 407 } 408 409 void Texture::setImage(GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels, egl::Image *image) 410 { 411 if(pixels && image) 412 { 413 GLsizei depth = (getTarget() == GL_TEXTURE_3D_OES || getTarget() == GL_TEXTURE_2D_ARRAY) ? image->getDepth() : 1; 414 image->loadImageData(0, 0, 0, image->getWidth(), image->getHeight(), depth, format, type, unpackInfo, pixels); 415 } 416 } 417 418 void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, egl::Image *image) 419 { 420 if(pixels && image) 421 { 422 GLsizei depth = (getTarget() == GL_TEXTURE_3D_OES || getTarget() == GL_TEXTURE_2D_ARRAY) ? image->getDepth() : 1; 423 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), depth, imageSize, pixels); 424 } 425 } 426 427 void Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels, egl::Image *image) 428 { 429 if(!image) 430 { 431 return error(GL_INVALID_OPERATION); 432 } 433 434 if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight() || depth + zoffset > image->getDepth()) 435 { 436 return error(GL_INVALID_VALUE); 437 } 438 439 if(IsCompressed(image->getFormat(), egl::getClientVersion())) 440 { 441 return error(GL_INVALID_OPERATION); 442 } 443 444 if(format != image->getFormat()) 445 { 446 return error(GL_INVALID_OPERATION); 447 } 448 449 if(pixels) 450 { 451 image->loadImageData(xoffset, yoffset, zoffset, width, height, depth, format, type, unpackInfo, pixels); 452 } 453 } 454 455 void Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels, egl::Image *image) 456 { 457 if(!image) 458 { 459 return error(GL_INVALID_OPERATION); 460 } 461 462 if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight() || depth + zoffset > image->getDepth()) 463 { 464 return error(GL_INVALID_VALUE); 465 } 466 467 if(format != image->getFormat()) 468 { 469 return error(GL_INVALID_OPERATION); 470 } 471 472 if(pixels) 473 { 474 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, imageSize, pixels); 475 } 476 } 477 478 bool Texture::copy(egl::Image *source, const sw::SliceRect &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, GLint zoffset, egl::Image *dest) 479 { 480 Device *device = getDevice(); 481 482 sw::SliceRect destRect(xoffset, yoffset, xoffset + (sourceRect.x1 - sourceRect.x0), yoffset + (sourceRect.y1 - sourceRect.y0), zoffset); 483 bool success = device->stretchRect(source, &sourceRect, dest, &destRect, false); 484 485 if(!success) 486 { 487 return error(GL_OUT_OF_MEMORY, false); 488 } 489 490 return true; 491 } 492 493 bool Texture::isMipmapFiltered() const 494 { 495 switch(mMinFilter) 496 { 497 case GL_NEAREST: 498 case GL_LINEAR: 499 return false; 500 case GL_NEAREST_MIPMAP_NEAREST: 501 case GL_LINEAR_MIPMAP_NEAREST: 502 case GL_NEAREST_MIPMAP_LINEAR: 503 case GL_LINEAR_MIPMAP_LINEAR: 504 return true; 505 default: UNREACHABLE(mMinFilter); 506 } 507 508 return false; 509 } 510 511 Texture2D::Texture2D(GLuint name) : Texture(name) 512 { 513 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) 514 { 515 image[i] = nullptr; 516 } 517 518 mSurface = nullptr; 519 520 mColorbufferProxy = nullptr; 521 mProxyRefs = 0; 522 } 523 524 Texture2D::~Texture2D() 525 { 526 resource->lock(sw::DESTRUCT); 527 528 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) 529 { 530 if(image[i]) 531 { 532 image[i]->unbind(this); 533 image[i] = nullptr; 534 } 535 } 536 537 resource->unlock(); 538 539 if(mSurface) 540 { 541 mSurface->setBoundTexture(nullptr); 542 mSurface = nullptr; 543 } 544 545 mColorbufferProxy = nullptr; 546 } 547 548 // We need to maintain a count of references to renderbuffers acting as 549 // proxies for this texture, so that we do not attempt to use a pointer 550 // to a renderbuffer proxy which has been deleted. 551 void Texture2D::addProxyRef(const Renderbuffer *proxy) 552 { 553 mProxyRefs++; 554 } 555 556 void Texture2D::releaseProxy(const Renderbuffer *proxy) 557 { 558 if(mProxyRefs > 0) 559 { 560 mProxyRefs--; 561 } 562 563 if(mProxyRefs == 0) 564 { 565 mColorbufferProxy = nullptr; 566 } 567 } 568 569 void Texture2D::sweep() 570 { 571 int imageCount = 0; 572 573 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) 574 { 575 if(image[i] && image[i]->isChildOf(this)) 576 { 577 if(!image[i]->hasSingleReference()) 578 { 579 return; 580 } 581 582 imageCount++; 583 } 584 } 585 586 if(imageCount == referenceCount) 587 { 588 destroy(); 589 } 590 } 591 592 GLenum Texture2D::getTarget() const 593 { 594 return GL_TEXTURE_2D; 595 } 596 597 GLsizei Texture2D::getWidth(GLenum target, GLint level) const 598 { 599 ASSERT(target == GL_TEXTURE_2D); 600 return image[level] ? image[level]->getWidth() : 0; 601 } 602 603 GLsizei Texture2D::getHeight(GLenum target, GLint level) const 604 { 605 ASSERT(target == GL_TEXTURE_2D); 606 return image[level] ? image[level]->getHeight() : 0; 607 } 608 609 GLenum Texture2D::getFormat(GLenum target, GLint level) const 610 { 611 ASSERT(target == GL_TEXTURE_2D); 612 return image[level] ? image[level]->getFormat() : GL_NONE; 613 } 614 615 GLenum Texture2D::getType(GLenum target, GLint level) const 616 { 617 ASSERT(target == GL_TEXTURE_2D); 618 return image[level] ? image[level]->getType() : GL_NONE; 619 } 620 621 sw::Format Texture2D::getInternalFormat(GLenum target, GLint level) const 622 { 623 ASSERT(target == GL_TEXTURE_2D); 624 return image[level] ? image[level]->getInternalFormat() : sw::FORMAT_NULL; 625 } 626 627 int Texture2D::getLevelCount() const 628 { 629 ASSERT(isSamplerComplete()); 630 int levels = 0; 631 632 while(levels < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[levels]) 633 { 634 levels++; 635 } 636 637 return levels; 638 } 639 640 void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels) 641 { 642 if(image[level]) 643 { 644 image[level]->release(); 645 } 646 647 image[level] = new egl::Image(this, width, height, format, type); 648 649 if(!image[level]) 650 { 651 return error(GL_OUT_OF_MEMORY); 652 } 653 654 Texture::setImage(format, type, unpackInfo, pixels, image[level]); 655 } 656 657 void Texture2D::bindTexImage(egl::Surface *surface) 658 { 659 GLenum format; 660 661 switch(surface->getInternalFormat()) 662 { 663 case sw::FORMAT_A8R8G8B8: 664 case sw::FORMAT_SRGB8_A8: 665 format = GL_BGRA_EXT; 666 break; 667 case sw::FORMAT_A8B8G8R8: 668 format = GL_RGBA; 669 break; 670 case sw::FORMAT_X8B8G8R8: 671 case sw::FORMAT_X8R8G8B8: 672 case sw::FORMAT_SRGB8_X8: 673 format = GL_RGB; 674 break; 675 default: 676 UNIMPLEMENTED(); 677 return; 678 } 679 680 for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) 681 { 682 if(image[level]) 683 { 684 image[level]->release(); 685 image[level] = nullptr; 686 } 687 } 688 689 image[0] = surface->getRenderTarget(); 690 691 mSurface = surface; 692 mSurface->setBoundTexture(this); 693 } 694 695 void Texture2D::releaseTexImage() 696 { 697 for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) 698 { 699 if(image[level]) 700 { 701 image[level]->release(); 702 image[level] = nullptr; 703 } 704 } 705 } 706 707 void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) 708 { 709 if(image[level]) 710 { 711 image[level]->release(); 712 } 713 714 GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); 715 image[level] = new egl::Image(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE); 716 717 if(!image[level]) 718 { 719 return error(GL_OUT_OF_MEMORY); 720 } 721 722 Texture::setCompressedImage(imageSize, pixels, image[level]); 723 } 724 725 void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels) 726 { 727 Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpackInfo, pixels, image[level]); 728 } 729 730 void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels) 731 { 732 Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, image[level]); 733 } 734 735 void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) 736 { 737 egl::Image *renderTarget = source->getRenderTarget(0); 738 739 if(!renderTarget) 740 { 741 ERR("Failed to retrieve the render target."); 742 return error(GL_OUT_OF_MEMORY); 743 } 744 745 if(image[level]) 746 { 747 image[level]->release(); 748 } 749 750 GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); 751 image[level] = new egl::Image(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE); 752 753 if(!image[level]) 754 { 755 return error(GL_OUT_OF_MEMORY); 756 } 757 758 if(width != 0 && height != 0) 759 { 760 Renderbuffer* renderbuffer = source->getReadColorbuffer(); 761 762 if(!renderbuffer) 763 { 764 ERR("Failed to retrieve the source colorbuffer."); 765 return; 766 } 767 768 sw::SliceRect sourceRect(x, y, x + width, y + height, 0); 769 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight()); 770 771 copy(renderTarget, sourceRect, sizedInternalFormat, 0, 0, 0, image[level]); 772 } 773 774 renderTarget->release(); 775 } 776 777 void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) 778 { 779 if(!image[level]) 780 { 781 return error(GL_INVALID_OPERATION); 782 } 783 784 if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight() || zoffset != 0) 785 { 786 return error(GL_INVALID_VALUE); 787 } 788 789 egl::Image *renderTarget = source->getRenderTarget(0); 790 791 if(!renderTarget) 792 { 793 ERR("Failed to retrieve the render target."); 794 return error(GL_OUT_OF_MEMORY); 795 } 796 797 Renderbuffer* renderbuffer = source->getReadColorbuffer(); 798 799 if(!renderbuffer) 800 { 801 ERR("Failed to retrieve the source colorbuffer."); 802 return; 803 } 804 805 sw::SliceRect sourceRect(x, y, x + width, y + height, 0); 806 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight()); 807 808 copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, zoffset, image[level]); 809 810 renderTarget->release(); 811 } 812 813 void Texture2D::setImage(egl::Image *sharedImage) 814 { 815 if(sharedImage == image[0]) 816 { 817 return; 818 } 819 820 sharedImage->addRef(); 821 822 if(image[0]) 823 { 824 image[0]->release(); 825 } 826 827 image[0] = sharedImage; 828 } 829 830 // Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85. 831 bool Texture2D::isSamplerComplete() const 832 { 833 if(!image[0]) 834 { 835 return false; 836 } 837 838 GLsizei width = image[0]->getWidth(); 839 GLsizei height = image[0]->getHeight(); 840 841 if(width <= 0 || height <= 0) 842 { 843 return false; 844 } 845 846 if(isMipmapFiltered()) 847 { 848 if(!isMipmapComplete()) 849 { 850 return false; 851 } 852 } 853 854 return true; 855 } 856 857 // Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. 858 bool Texture2D::isMipmapComplete() const 859 { 860 GLsizei width = image[mBaseLevel]->getWidth(); 861 GLsizei height = image[mBaseLevel]->getHeight(); 862 863 int q = std::min(log2(std::max(width, height)), mMaxLevel); 864 865 for(int level = mBaseLevel + 1; level <= q; level++) 866 { 867 if(!image[level]) 868 { 869 return false; 870 } 871 872 if(image[level]->getFormat() != image[0]->getFormat()) 873 { 874 return false; 875 } 876 877 if(image[level]->getType() != image[0]->getType()) 878 { 879 return false; 880 } 881 882 if(image[level]->getWidth() != std::max(1, width >> level)) 883 { 884 return false; 885 } 886 887 if(image[level]->getHeight() != std::max(1, height >> level)) 888 { 889 return false; 890 } 891 } 892 893 return true; 894 } 895 896 bool Texture2D::isCompressed(GLenum target, GLint level) const 897 { 898 return IsCompressed(getFormat(target, level), egl::getClientVersion()); 899 } 900 901 bool Texture2D::isDepth(GLenum target, GLint level) const 902 { 903 return IsDepthTexture(getFormat(target, level)); 904 } 905 906 void Texture2D::generateMipmaps() 907 { 908 if(!image[0]) 909 { 910 return; // FIXME: error? 911 } 912 913 unsigned int q = log2(std::max(image[0]->getWidth(), image[0]->getHeight())); 914 915 for(unsigned int i = 1; i <= q; i++) 916 { 917 if(image[i]) 918 { 919 image[i]->release(); 920 } 921 922 image[i] = new egl::Image(this, std::max(image[0]->getWidth() >> i, 1), std::max(image[0]->getHeight() >> i, 1), image[0]->getFormat(), image[0]->getType()); 923 924 if(!image[i]) 925 { 926 return error(GL_OUT_OF_MEMORY); 927 } 928 929 getDevice()->stretchRect(image[i - 1], 0, image[i], 0, true); 930 } 931 } 932 933 egl::Image *Texture2D::getImage(unsigned int level) 934 { 935 return image[level]; 936 } 937 938 Renderbuffer *Texture2D::getRenderbuffer(GLenum target, GLint level, GLint layer) 939 { 940 if(target != GL_TEXTURE_2D) 941 { 942 return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr); 943 } 944 945 if(!mColorbufferProxy) 946 { 947 mColorbufferProxy = new Renderbuffer(name, new RenderbufferTexture2D(this, level)); 948 } 949 else 950 { 951 mColorbufferProxy->setLevel(level); 952 } 953 954 return mColorbufferProxy; 955 } 956 957 egl::Image *Texture2D::getRenderTarget(GLenum target, unsigned int level) 958 { 959 ASSERT(target == GL_TEXTURE_2D); 960 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS); 961 962 if(image[level]) 963 { 964 image[level]->addRef(); 965 } 966 967 return image[level]; 968 } 969 970 bool Texture2D::isShared(GLenum target, unsigned int level) const 971 { 972 ASSERT(target == GL_TEXTURE_2D); 973 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS); 974 975 if(mSurface) // Bound to an EGLSurface 976 { 977 return true; 978 } 979 980 if(!image[level]) 981 { 982 return false; 983 } 984 985 return image[level]->isShared(); 986 } 987 988 TextureCubeMap::TextureCubeMap(GLuint name) : Texture(name) 989 { 990 for(int f = 0; f < 6; f++) 991 { 992 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) 993 { 994 image[f][i] = nullptr; 995 } 996 } 997 998 for(int f = 0; f < 6; f++) 999 { 1000 mFaceProxies[f] = nullptr; 1001 mFaceProxyRefs[f] = 0; 1002 } 1003 } 1004 1005 TextureCubeMap::~TextureCubeMap() 1006 { 1007 resource->lock(sw::DESTRUCT); 1008 1009 for(int f = 0; f < 6; f++) 1010 { 1011 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) 1012 { 1013 if(image[f][i]) 1014 { 1015 image[f][i]->unbind(this); 1016 image[f][i] = nullptr; 1017 } 1018 } 1019 } 1020 1021 resource->unlock(); 1022 1023 for(int i = 0; i < 6; i++) 1024 { 1025 mFaceProxies[i] = nullptr; 1026 } 1027 } 1028 1029 // We need to maintain a count of references to renderbuffers acting as 1030 // proxies for this texture, so that the texture is not deleted while 1031 // proxy references still exist. If the reference count drops to zero, 1032 // we set our proxy pointer null, so that a new attempt at referencing 1033 // will cause recreation. 1034 void TextureCubeMap::addProxyRef(const Renderbuffer *proxy) 1035 { 1036 for(int f = 0; f < 6; f++) 1037 { 1038 if(mFaceProxies[f] == proxy) 1039 { 1040 mFaceProxyRefs[f]++; 1041 } 1042 } 1043 } 1044 1045 void TextureCubeMap::releaseProxy(const Renderbuffer *proxy) 1046 { 1047 for(int f = 0; f < 6; f++) 1048 { 1049 if(mFaceProxies[f] == proxy) 1050 { 1051 if(mFaceProxyRefs[f] > 0) 1052 { 1053 mFaceProxyRefs[f]--; 1054 } 1055 1056 if(mFaceProxyRefs[f] == 0) 1057 { 1058 mFaceProxies[f] = nullptr; 1059 } 1060 } 1061 } 1062 } 1063 1064 void TextureCubeMap::sweep() 1065 { 1066 int imageCount = 0; 1067 1068 for(int f = 0; f < 6; f++) 1069 { 1070 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) 1071 { 1072 if(image[f][i] && image[f][i]->isChildOf(this)) 1073 { 1074 if(!image[f][i]->hasSingleReference()) 1075 { 1076 return; 1077 } 1078 1079 imageCount++; 1080 } 1081 } 1082 } 1083 1084 if(imageCount == referenceCount) 1085 { 1086 destroy(); 1087 } 1088 } 1089 1090 GLenum TextureCubeMap::getTarget() const 1091 { 1092 return GL_TEXTURE_CUBE_MAP; 1093 } 1094 1095 GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const 1096 { 1097 int face = CubeFaceIndex(target); 1098 return image[face][level] ? image[face][level]->getWidth() : 0; 1099 } 1100 1101 GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const 1102 { 1103 int face = CubeFaceIndex(target); 1104 return image[face][level] ? image[face][level]->getHeight() : 0; 1105 } 1106 1107 GLenum TextureCubeMap::getFormat(GLenum target, GLint level) const 1108 { 1109 int face = CubeFaceIndex(target); 1110 return image[face][level] ? image[face][level]->getFormat() : 0; 1111 } 1112 1113 GLenum TextureCubeMap::getType(GLenum target, GLint level) const 1114 { 1115 int face = CubeFaceIndex(target); 1116 return image[face][level] ? image[face][level]->getType() : 0; 1117 } 1118 1119 sw::Format TextureCubeMap::getInternalFormat(GLenum target, GLint level) const 1120 { 1121 int face = CubeFaceIndex(target); 1122 return image[face][level] ? image[face][level]->getInternalFormat() : sw::FORMAT_NULL; 1123 } 1124 1125 int TextureCubeMap::getLevelCount() const 1126 { 1127 ASSERT(isSamplerComplete()); 1128 int levels = 0; 1129 1130 while(levels < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[0][levels]) 1131 { 1132 levels++; 1133 } 1134 1135 return levels; 1136 } 1137 1138 void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) 1139 { 1140 int face = CubeFaceIndex(target); 1141 1142 if(image[face][level]) 1143 { 1144 image[face][level]->release(); 1145 } 1146 1147 GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); 1148 image[face][level] = new egl::Image(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE); 1149 1150 if(!image[face][level]) 1151 { 1152 return error(GL_OUT_OF_MEMORY); 1153 } 1154 1155 Texture::setCompressedImage(imageSize, pixels, image[face][level]); 1156 } 1157 1158 void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels) 1159 { 1160 Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpackInfo, pixels, image[CubeFaceIndex(target)][level]); 1161 } 1162 1163 void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels) 1164 { 1165 Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, image[CubeFaceIndex(target)][level]); 1166 } 1167 1168 // Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86. 1169 bool TextureCubeMap::isSamplerComplete() const 1170 { 1171 for(int face = 0; face < 6; face++) 1172 { 1173 if(!image[face][0]) 1174 { 1175 return false; 1176 } 1177 } 1178 1179 int size = image[0][0]->getWidth(); 1180 1181 if(size <= 0) 1182 { 1183 return false; 1184 } 1185 1186 if(!isMipmapFiltered()) 1187 { 1188 if(!isCubeComplete()) 1189 { 1190 return false; 1191 } 1192 } 1193 else 1194 { 1195 if(!isMipmapCubeComplete()) // Also tests for isCubeComplete() 1196 { 1197 return false; 1198 } 1199 } 1200 1201 return true; 1202 } 1203 1204 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. 1205 bool TextureCubeMap::isCubeComplete() const 1206 { 1207 if(image[0][mBaseLevel]->getWidth() <= 0 || image[0][mBaseLevel]->getHeight() != image[0][mBaseLevel]->getWidth()) 1208 { 1209 return false; 1210 } 1211 1212 for(unsigned int face = 1; face < 6; face++) 1213 { 1214 if(image[face][mBaseLevel]->getWidth() != image[0][mBaseLevel]->getWidth() || 1215 image[face][mBaseLevel]->getWidth() != image[0][mBaseLevel]->getHeight() || 1216 image[face][mBaseLevel]->getFormat() != image[0][mBaseLevel]->getFormat() || 1217 image[face][mBaseLevel]->getType() != image[0][mBaseLevel]->getType()) 1218 { 1219 return false; 1220 } 1221 } 1222 1223 return true; 1224 } 1225 1226 bool TextureCubeMap::isMipmapCubeComplete() const 1227 { 1228 if(!isCubeComplete()) 1229 { 1230 return false; 1231 } 1232 1233 GLsizei size = image[0][mBaseLevel]->getWidth(); 1234 int q = std::min(log2(size), mMaxLevel); 1235 1236 for(int face = 0; face < 6; face++) 1237 { 1238 for(int level = mBaseLevel + 1; level <= q; level++) 1239 { 1240 if(!image[face][level]) 1241 { 1242 return false; 1243 } 1244 1245 if(image[face][level]->getFormat() != image[0][mBaseLevel]->getFormat()) 1246 { 1247 return false; 1248 } 1249 1250 if(image[face][level]->getType() != image[0][mBaseLevel]->getType()) 1251 { 1252 return false; 1253 } 1254 1255 if(image[face][level]->getWidth() != std::max(1, size >> level)) 1256 { 1257 return false; 1258 } 1259 } 1260 } 1261 1262 return true; 1263 } 1264 1265 bool TextureCubeMap::isCompressed(GLenum target, GLint level) const 1266 { 1267 return IsCompressed(getFormat(target, level), egl::getClientVersion()); 1268 } 1269 1270 bool TextureCubeMap::isDepth(GLenum target, GLint level) const 1271 { 1272 return IsDepthTexture(getFormat(target, level)); 1273 } 1274 1275 void TextureCubeMap::releaseTexImage() 1276 { 1277 UNREACHABLE(0); // Cube maps cannot have an EGL surface bound as an image 1278 } 1279 1280 void TextureCubeMap::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels) 1281 { 1282 int face = CubeFaceIndex(target); 1283 1284 if(image[face][level]) 1285 { 1286 image[face][level]->release(); 1287 } 1288 1289 image[face][level] = new egl::Image(this, width, height, format, type); 1290 1291 if(!image[face][level]) 1292 { 1293 return error(GL_OUT_OF_MEMORY); 1294 } 1295 1296 Texture::setImage(format, type, unpackInfo, pixels, image[face][level]); 1297 } 1298 1299 void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) 1300 { 1301 egl::Image *renderTarget = source->getRenderTarget(0); 1302 1303 if(!renderTarget) 1304 { 1305 ERR("Failed to retrieve the render target."); 1306 return error(GL_OUT_OF_MEMORY); 1307 } 1308 1309 int face = CubeFaceIndex(target); 1310 1311 if(image[face][level]) 1312 { 1313 image[face][level]->release(); 1314 } 1315 1316 GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); 1317 image[face][level] = new egl::Image(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE); 1318 1319 if(!image[face][level]) 1320 { 1321 return error(GL_OUT_OF_MEMORY); 1322 } 1323 1324 if(width != 0 && height != 0) 1325 { 1326 Renderbuffer* renderbuffer = source->getReadColorbuffer(); 1327 1328 if(!renderbuffer) 1329 { 1330 ERR("Failed to retrieve the source colorbuffer."); 1331 return; 1332 } 1333 1334 sw::SliceRect sourceRect(x, y, x + width, y + height, 0); 1335 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight()); 1336 1337 copy(renderTarget, sourceRect, sizedInternalFormat, 0, 0, 0, image[face][level]); 1338 } 1339 1340 renderTarget->release(); 1341 } 1342 1343 egl::Image *TextureCubeMap::getImage(int face, unsigned int level) 1344 { 1345 return image[face][level]; 1346 } 1347 1348 egl::Image *TextureCubeMap::getImage(GLenum face, unsigned int level) 1349 { 1350 return image[CubeFaceIndex(face)][level]; 1351 } 1352 1353 void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) 1354 { 1355 int face = CubeFaceIndex(target); 1356 1357 if(!image[face][level]) 1358 { 1359 return error(GL_INVALID_OPERATION); 1360 } 1361 1362 GLsizei size = image[face][level]->getWidth(); 1363 1364 if(xoffset + width > size || yoffset + height > size || zoffset != 0) 1365 { 1366 return error(GL_INVALID_VALUE); 1367 } 1368 1369 egl::Image *renderTarget = source->getRenderTarget(0); 1370 1371 if(!renderTarget) 1372 { 1373 ERR("Failed to retrieve the render target."); 1374 return error(GL_OUT_OF_MEMORY); 1375 } 1376 1377 Renderbuffer* renderbuffer = source->getReadColorbuffer(); 1378 1379 if(!renderbuffer) 1380 { 1381 ERR("Failed to retrieve the source colorbuffer."); 1382 return; 1383 } 1384 1385 sw::SliceRect sourceRect(x, y, x + width, y + height, 0); 1386 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight()); 1387 1388 copy(renderTarget, sourceRect, image[face][level]->getFormat(), xoffset, yoffset, zoffset, image[face][level]); 1389 1390 renderTarget->release(); 1391 } 1392 1393 void TextureCubeMap::generateMipmaps() 1394 { 1395 if(!isCubeComplete()) 1396 { 1397 return error(GL_INVALID_OPERATION); 1398 } 1399 1400 unsigned int q = log2(image[0][0]->getWidth()); 1401 1402 for(unsigned int f = 0; f < 6; f++) 1403 { 1404 for(unsigned int i = 1; i <= q; i++) 1405 { 1406 if(image[f][i]) 1407 { 1408 image[f][i]->release(); 1409 } 1410 1411 image[f][i] = new egl::Image(this, std::max(image[0][0]->getWidth() >> i, 1), std::max(image[0][0]->getHeight() >> i, 1), image[0][0]->getFormat(), image[0][0]->getType()); 1412 1413 if(!image[f][i]) 1414 { 1415 return error(GL_OUT_OF_MEMORY); 1416 } 1417 1418 getDevice()->stretchRect(image[f][i - 1], 0, image[f][i], 0, true); 1419 } 1420 } 1421 } 1422 1423 Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level, GLint layer) 1424 { 1425 if(!IsCubemapTextureTarget(target)) 1426 { 1427 return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr); 1428 } 1429 1430 int face = CubeFaceIndex(target); 1431 1432 if(!mFaceProxies[face]) 1433 { 1434 mFaceProxies[face] = new Renderbuffer(name, new RenderbufferTextureCubeMap(this, target, level)); 1435 } 1436 else 1437 { 1438 mFaceProxies[face]->setLevel(level); 1439 } 1440 1441 return mFaceProxies[face]; 1442 } 1443 1444 egl::Image *TextureCubeMap::getRenderTarget(GLenum target, unsigned int level) 1445 { 1446 ASSERT(IsCubemapTextureTarget(target)); 1447 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS); 1448 1449 int face = CubeFaceIndex(target); 1450 1451 if(image[face][level]) 1452 { 1453 image[face][level]->addRef(); 1454 } 1455 1456 return image[face][level]; 1457 } 1458 1459 bool TextureCubeMap::isShared(GLenum target, unsigned int level) const 1460 { 1461 ASSERT(IsCubemapTextureTarget(target)); 1462 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS); 1463 1464 int face = CubeFaceIndex(target); 1465 1466 if(!image[face][level]) 1467 { 1468 return false; 1469 } 1470 1471 return image[face][level]->isShared(); 1472 } 1473 1474 Texture3D::Texture3D(GLuint name) : Texture(name) 1475 { 1476 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) 1477 { 1478 image[i] = nullptr; 1479 } 1480 1481 mSurface = nullptr; 1482 1483 mColorbufferProxy = nullptr; 1484 mProxyRefs = 0; 1485 } 1486 1487 Texture3D::~Texture3D() 1488 { 1489 resource->lock(sw::DESTRUCT); 1490 1491 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) 1492 { 1493 if(image[i]) 1494 { 1495 image[i]->unbind(this); 1496 image[i] = nullptr; 1497 } 1498 } 1499 1500 resource->unlock(); 1501 1502 if(mSurface) 1503 { 1504 mSurface->setBoundTexture(nullptr); 1505 mSurface = nullptr; 1506 } 1507 1508 mColorbufferProxy = nullptr; 1509 } 1510 1511 // We need to maintain a count of references to renderbuffers acting as 1512 // proxies for this texture, so that we do not attempt to use a pointer 1513 // to a renderbuffer proxy which has been deleted. 1514 void Texture3D::addProxyRef(const Renderbuffer *proxy) 1515 { 1516 mProxyRefs++; 1517 } 1518 1519 void Texture3D::releaseProxy(const Renderbuffer *proxy) 1520 { 1521 if(mProxyRefs > 0) 1522 { 1523 mProxyRefs--; 1524 } 1525 1526 if(mProxyRefs == 0) 1527 { 1528 mColorbufferProxy = nullptr; 1529 } 1530 } 1531 1532 void Texture3D::sweep() 1533 { 1534 int imageCount = 0; 1535 1536 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) 1537 { 1538 if(image[i] && image[i]->isChildOf(this)) 1539 { 1540 if(!image[i]->hasSingleReference()) 1541 { 1542 return; 1543 } 1544 1545 imageCount++; 1546 } 1547 } 1548 1549 if(imageCount == referenceCount) 1550 { 1551 destroy(); 1552 } 1553 } 1554 1555 GLenum Texture3D::getTarget() const 1556 { 1557 return GL_TEXTURE_3D_OES; 1558 } 1559 1560 GLsizei Texture3D::getWidth(GLenum target, GLint level) const 1561 { 1562 ASSERT(target == getTarget()); 1563 return image[level] ? image[level]->getWidth() : 0; 1564 } 1565 1566 GLsizei Texture3D::getHeight(GLenum target, GLint level) const 1567 { 1568 ASSERT(target == getTarget()); 1569 return image[level] ? image[level]->getHeight() : 0; 1570 } 1571 1572 GLsizei Texture3D::getDepth(GLenum target, GLint level) const 1573 { 1574 ASSERT(target == getTarget()); 1575 return image[level] ? image[level]->getDepth() : 0; 1576 } 1577 1578 GLenum Texture3D::getFormat(GLenum target, GLint level) const 1579 { 1580 ASSERT(target == getTarget()); 1581 return image[level] ? image[level]->getFormat() : GL_NONE; 1582 } 1583 1584 GLenum Texture3D::getType(GLenum target, GLint level) const 1585 { 1586 ASSERT(target == getTarget()); 1587 return image[level] ? image[level]->getType() : GL_NONE; 1588 } 1589 1590 sw::Format Texture3D::getInternalFormat(GLenum target, GLint level) const 1591 { 1592 ASSERT(target == getTarget()); 1593 return image[level] ? image[level]->getInternalFormat() : sw::FORMAT_NULL; 1594 } 1595 1596 int Texture3D::getLevelCount() const 1597 { 1598 ASSERT(isSamplerComplete()); 1599 int levels = 0; 1600 1601 while(levels < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[levels]) 1602 { 1603 levels++; 1604 } 1605 1606 return levels; 1607 } 1608 1609 void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels) 1610 { 1611 if(image[level]) 1612 { 1613 image[level]->release(); 1614 } 1615 1616 image[level] = new egl::Image(this, width, height, depth, format, type); 1617 1618 if(!image[level]) 1619 { 1620 return error(GL_OUT_OF_MEMORY); 1621 } 1622 1623 Texture::setImage(format, type, unpackInfo, pixels, image[level]); 1624 } 1625 1626 void Texture3D::bindTexImage(egl::Surface *surface) 1627 { 1628 GLenum format; 1629 1630 switch(surface->getInternalFormat()) 1631 { 1632 case sw::FORMAT_A8R8G8B8: 1633 format = GL_RGBA; 1634 break; 1635 case sw::FORMAT_X8R8G8B8: 1636 format = GL_RGB; 1637 break; 1638 default: 1639 UNIMPLEMENTED(); 1640 return; 1641 } 1642 1643 for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) 1644 { 1645 if(image[level]) 1646 { 1647 image[level]->release(); 1648 image[level] = nullptr; 1649 } 1650 } 1651 1652 image[0] = surface->getRenderTarget(); 1653 1654 mSurface = surface; 1655 mSurface->setBoundTexture(this); 1656 } 1657 1658 void Texture3D::releaseTexImage() 1659 { 1660 for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) 1661 { 1662 if(image[level]) 1663 { 1664 image[level]->release(); 1665 image[level] = nullptr; 1666 } 1667 } 1668 } 1669 1670 void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) 1671 { 1672 if(image[level]) 1673 { 1674 image[level]->release(); 1675 } 1676 1677 GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); 1678 image[level] = new egl::Image(this, width, height, depth, sizedInternalFormat, GL_UNSIGNED_BYTE); 1679 1680 if(!image[level]) 1681 { 1682 return error(GL_OUT_OF_MEMORY); 1683 } 1684 1685 Texture::setCompressedImage(imageSize, pixels, image[level]); 1686 } 1687 1688 void Texture3D::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels) 1689 { 1690 Texture::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpackInfo, pixels, image[level]); 1691 } 1692 1693 void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) 1694 { 1695 Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, image[level]); 1696 } 1697 1698 void Texture3D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLint z, GLsizei width, GLsizei height, GLsizei depth, Framebuffer *source) 1699 { 1700 egl::Image *renderTarget = source->getRenderTarget(0); 1701 1702 if(!renderTarget) 1703 { 1704 ERR("Failed to retrieve the render target."); 1705 return error(GL_OUT_OF_MEMORY); 1706 } 1707 1708 if(image[level]) 1709 { 1710 image[level]->release(); 1711 } 1712 1713 GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); 1714 image[level] = new egl::Image(this, width, height, depth, sizedInternalFormat, GL_UNSIGNED_BYTE); 1715 1716 if(!image[level]) 1717 { 1718 return error(GL_OUT_OF_MEMORY); 1719 } 1720 1721 if(width != 0 && height != 0 && depth != 0) 1722 { 1723 Renderbuffer* renderbuffer = source->getReadColorbuffer(); 1724 1725 if(!renderbuffer) 1726 { 1727 ERR("Failed to retrieve the source colorbuffer."); 1728 return; 1729 } 1730 1731 sw::SliceRect sourceRect(x, y, x + width, y + height, z); 1732 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight()); 1733 for(GLint sliceZ = 0; sliceZ < depth; ++sliceZ, ++sourceRect.slice) 1734 { 1735 copy(renderTarget, sourceRect, sizedInternalFormat, 0, 0, sliceZ, image[level]); 1736 } 1737 } 1738 1739 renderTarget->release(); 1740 } 1741 1742 void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) 1743 { 1744 if(!image[level]) 1745 { 1746 return error(GL_INVALID_OPERATION); 1747 } 1748 1749 if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight() || zoffset >= image[level]->getDepth()) 1750 { 1751 return error(GL_INVALID_VALUE); 1752 } 1753 1754 egl::Image *renderTarget = source->getRenderTarget(0); 1755 1756 if(!renderTarget) 1757 { 1758 ERR("Failed to retrieve the render target."); 1759 return error(GL_OUT_OF_MEMORY); 1760 } 1761 1762 Renderbuffer* renderbuffer = source->getReadColorbuffer(); 1763 1764 if(!renderbuffer) 1765 { 1766 ERR("Failed to retrieve the source colorbuffer."); 1767 return; 1768 } 1769 1770 sw::SliceRect sourceRect = {x, y, x + width, y + height, 0}; 1771 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight()); 1772 1773 copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, zoffset, image[level]); 1774 1775 renderTarget->release(); 1776 } 1777 1778 void Texture3D::setImage(egl::Image *sharedImage) 1779 { 1780 sharedImage->addRef(); 1781 1782 if(image[0]) 1783 { 1784 image[0]->release(); 1785 } 1786 1787 image[0] = sharedImage; 1788 } 1789 1790 // Tests for 3D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85. 1791 bool Texture3D::isSamplerComplete() const 1792 { 1793 if(!image[0]) 1794 { 1795 return false; 1796 } 1797 1798 GLsizei width = image[0]->getWidth(); 1799 GLsizei height = image[0]->getHeight(); 1800 GLsizei depth = image[0]->getDepth(); 1801 1802 if(width <= 0 || height <= 0 || depth <= 0) 1803 { 1804 return false; 1805 } 1806 1807 if(isMipmapFiltered()) 1808 { 1809 if(!isMipmapComplete()) 1810 { 1811 return false; 1812 } 1813 } 1814 1815 return true; 1816 } 1817 1818 // Tests for 3D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. 1819 bool Texture3D::isMipmapComplete() const 1820 { 1821 GLsizei width = image[mBaseLevel]->getWidth(); 1822 GLsizei height = image[mBaseLevel]->getHeight(); 1823 GLsizei depth = image[mBaseLevel]->getDepth(); 1824 bool isTexture2DArray = getTarget() == GL_TEXTURE_2D_ARRAY; 1825 1826 int q = isTexture2DArray ? std::min(log2(std::max(width, height)), mMaxLevel) : 1827 std::min(log2(std::max(std::max(width, height), depth)), mMaxLevel); 1828 1829 for(int level = mBaseLevel + 1; level <= q; level++) 1830 { 1831 if(!image[level]) 1832 { 1833 return false; 1834 } 1835 1836 if(image[level]->getFormat() != image[0]->getFormat()) 1837 { 1838 return false; 1839 } 1840 1841 if(image[level]->getType() != image[0]->getType()) 1842 { 1843 return false; 1844 } 1845 1846 if(image[level]->getWidth() != std::max(1, width >> level)) 1847 { 1848 return false; 1849 } 1850 1851 if(image[level]->getHeight() != std::max(1, height >> level)) 1852 { 1853 return false; 1854 } 1855 1856 int levelDepth = isTexture2DArray ? depth : std::max(1, depth >> level); 1857 if(image[level]->getDepth() != levelDepth) 1858 { 1859 return false; 1860 } 1861 } 1862 1863 return true; 1864 } 1865 1866 bool Texture3D::isCompressed(GLenum target, GLint level) const 1867 { 1868 return IsCompressed(getFormat(target, level), egl::getClientVersion()); 1869 } 1870 1871 bool Texture3D::isDepth(GLenum target, GLint level) const 1872 { 1873 return IsDepthTexture(getFormat(target, level)); 1874 } 1875 1876 void Texture3D::generateMipmaps() 1877 { 1878 if(!image[0]) 1879 { 1880 return; // FIXME: error? 1881 } 1882 1883 unsigned int q = log2(std::max(std::max(image[0]->getWidth(), image[0]->getHeight()), image[0]->getDepth())); 1884 1885 for(unsigned int i = 1; i <= q; i++) 1886 { 1887 if(image[i]) 1888 { 1889 image[i]->release(); 1890 } 1891 1892 image[i] = new egl::Image(this, std::max(image[0]->getWidth() >> i, 1), std::max(image[0]->getHeight() >> i, 1), std::max(image[0]->getDepth() >> i, 1), image[0]->getFormat(), image[0]->getType()); 1893 1894 if(!image[i]) 1895 { 1896 return error(GL_OUT_OF_MEMORY); 1897 } 1898 1899 getDevice()->stretchCube(image[i - 1], image[i]); 1900 } 1901 } 1902 1903 egl::Image *Texture3D::getImage(unsigned int level) 1904 { 1905 return image[level]; 1906 } 1907 1908 Renderbuffer *Texture3D::getRenderbuffer(GLenum target, GLint level, GLint layer) 1909 { 1910 if(target != getTarget()) 1911 { 1912 return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr); 1913 } 1914 1915 if(!mColorbufferProxy) 1916 { 1917 mColorbufferProxy = new Renderbuffer(name, new RenderbufferTexture3D(this, level, layer)); 1918 } 1919 else 1920 { 1921 mColorbufferProxy->setLevel(level); 1922 mColorbufferProxy->setLayer(layer); 1923 } 1924 1925 return mColorbufferProxy; 1926 } 1927 1928 egl::Image *Texture3D::getRenderTarget(GLenum target, unsigned int level) 1929 { 1930 ASSERT(target == getTarget()); 1931 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS); 1932 1933 if(image[level]) 1934 { 1935 image[level]->addRef(); 1936 } 1937 1938 return image[level]; 1939 } 1940 1941 bool Texture3D::isShared(GLenum target, unsigned int level) const 1942 { 1943 ASSERT(target == getTarget()); 1944 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS); 1945 1946 if(mSurface) // Bound to an EGLSurface 1947 { 1948 return true; 1949 } 1950 1951 if(!image[level]) 1952 { 1953 return false; 1954 } 1955 1956 return image[level]->isShared(); 1957 } 1958 1959 Texture2DArray::Texture2DArray(GLuint name) : Texture3D(name) 1960 { 1961 } 1962 1963 Texture2DArray::~Texture2DArray() 1964 { 1965 } 1966 1967 GLenum Texture2DArray::getTarget() const 1968 { 1969 return GL_TEXTURE_2D_ARRAY; 1970 } 1971 1972 void Texture2DArray::generateMipmaps() 1973 { 1974 int depth = image[0] ? image[0]->getDepth() : 0; 1975 if(!depth) 1976 { 1977 return; // FIXME: error? 1978 } 1979 1980 unsigned int q = log2(std::max(image[0]->getWidth(), image[0]->getHeight())); 1981 1982 for(unsigned int i = 1; i <= q; i++) 1983 { 1984 if(image[i]) 1985 { 1986 image[i]->release(); 1987 } 1988 1989 GLsizei w = std::max(image[0]->getWidth() >> i, 1); 1990 GLsizei h = std::max(image[0]->getHeight() >> i, 1); 1991 image[i] = new egl::Image(this, w, h, depth, image[0]->getFormat(), image[0]->getType()); 1992 1993 if(!image[i]) 1994 { 1995 return error(GL_OUT_OF_MEMORY); 1996 } 1997 1998 GLsizei srcw = image[i - 1]->getWidth(); 1999 GLsizei srch = image[i - 1]->getHeight(); 2000 for(int z = 0; z < depth; ++z) 2001 { 2002 sw::SliceRect srcRect(0, 0, srcw, srch, z); 2003 sw::SliceRect dstRect(0, 0, w, h, z); 2004 getDevice()->stretchRect(image[i - 1], &srcRect, image[i], &dstRect, true); 2005 } 2006 } 2007 } 2008 2009 TextureExternal::TextureExternal(GLuint name) : Texture2D(name) 2010 { 2011 mMinFilter = GL_LINEAR; 2012 mMagFilter = GL_LINEAR; 2013 mWrapS = GL_CLAMP_TO_EDGE; 2014 mWrapT = GL_CLAMP_TO_EDGE; 2015 mWrapR = GL_CLAMP_TO_EDGE; 2016 } 2017 2018 TextureExternal::~TextureExternal() 2019 { 2020 } 2021 2022 GLenum TextureExternal::getTarget() const 2023 { 2024 return GL_TEXTURE_EXTERNAL_OES; 2025 } 2026 2027 } 2028 2029 egl::Image *createBackBuffer(int width, int height, const egl::Config *config) 2030 { 2031 if(config) 2032 { 2033 return new egl::Image(width, height, config->mRenderTargetFormat, config->mSamples, false); 2034 } 2035 2036 return nullptr; 2037 } 2038 2039 egl::Image *createDepthStencil(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard) 2040 { 2041 if(width == 0 || height == 0 || height > sw::OUTLINE_RESOLUTION) 2042 { 2043 ERR("Invalid parameters: %dx%d", width, height); 2044 return nullptr; 2045 } 2046 2047 bool lockable = true; 2048 2049 switch(format) 2050 { 2051 // case sw::FORMAT_D15S1: 2052 case sw::FORMAT_D24S8: 2053 case sw::FORMAT_D24X8: 2054 // case sw::FORMAT_D24X4S4: 2055 case sw::FORMAT_D24FS8: 2056 case sw::FORMAT_D32: 2057 case sw::FORMAT_D16: 2058 lockable = false; 2059 break; 2060 // case sw::FORMAT_S8_LOCKABLE: 2061 // case sw::FORMAT_D16_LOCKABLE: 2062 case sw::FORMAT_D32F_LOCKABLE: 2063 // case sw::FORMAT_D32_LOCKABLE: 2064 case sw::FORMAT_DF24S8: 2065 case sw::FORMAT_DF16S8: 2066 lockable = true; 2067 break; 2068 default: 2069 UNREACHABLE(format); 2070 } 2071 2072 egl::Image *surface = new egl::Image(width, height, format, multiSampleDepth, lockable); 2073 2074 if(!surface) 2075 { 2076 ERR("Out of memory"); 2077 return nullptr; 2078 } 2079 2080 return surface; 2081 } 2082