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