1#include "precompiled.h" 2// 3// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. 4// Use of this source code is governed by a BSD-style license that can be 5// found in the LICENSE file. 6// 7 8// Texture.cpp: Implements the gl::Texture class and its derived classes 9// Texture2D and TextureCubeMap. Implements GL texture objects and related 10// functionality. [OpenGL ES 2.0.24] section 3.7 page 63. 11 12#include "libGLESv2/Texture.h" 13 14#include "libGLESv2/main.h" 15#include "common/mathutil.h" 16#include "common/utilities.h" 17#include "libGLESv2/formatutils.h" 18#include "libGLESv2/Renderbuffer.h" 19#include "libGLESv2/renderer/Image.h" 20#include "libGLESv2/renderer/Renderer.h" 21#include "libGLESv2/renderer/TextureStorage.h" 22#include "libEGL/Surface.h" 23#include "libGLESv2/Buffer.h" 24#include "libGLESv2/renderer/BufferStorage.h" 25#include "libGLESv2/renderer/RenderTarget.h" 26 27namespace gl 28{ 29 30bool IsMipmapFiltered(const SamplerState &samplerState) 31{ 32 switch (samplerState.minFilter) 33 { 34 case GL_NEAREST: 35 case GL_LINEAR: 36 return false; 37 case GL_NEAREST_MIPMAP_NEAREST: 38 case GL_LINEAR_MIPMAP_NEAREST: 39 case GL_NEAREST_MIPMAP_LINEAR: 40 case GL_LINEAR_MIPMAP_LINEAR: 41 return true; 42 default: UNREACHABLE(); 43 return false; 44 } 45} 46 47bool IsRenderTargetUsage(GLenum usage) 48{ 49 return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); 50} 51 52Texture::Texture(rx::Renderer *renderer, GLuint id, GLenum target) : RefCountObject(id) 53{ 54 mRenderer = renderer; 55 56 mSamplerState.minFilter = GL_NEAREST_MIPMAP_LINEAR; 57 mSamplerState.magFilter = GL_LINEAR; 58 mSamplerState.wrapS = GL_REPEAT; 59 mSamplerState.wrapT = GL_REPEAT; 60 mSamplerState.wrapR = GL_REPEAT; 61 mSamplerState.maxAnisotropy = 1.0f; 62 mSamplerState.baseLevel = 0; 63 mSamplerState.maxLevel = 1000; 64 mSamplerState.minLod = -1000.0f; 65 mSamplerState.maxLod = 1000.0f; 66 mSamplerState.compareMode = GL_NONE; 67 mSamplerState.compareFunc = GL_LEQUAL; 68 mSamplerState.swizzleRed = GL_RED; 69 mSamplerState.swizzleGreen = GL_GREEN; 70 mSamplerState.swizzleBlue = GL_BLUE; 71 mSamplerState.swizzleAlpha = GL_ALPHA; 72 mUsage = GL_NONE; 73 74 mDirtyImages = true; 75 76 mImmutable = false; 77 78 mTarget = target; 79} 80 81Texture::~Texture() 82{ 83} 84 85GLenum Texture::getTarget() const 86{ 87 return mTarget; 88} 89 90void Texture::addProxyRef(const FramebufferAttachment *proxy) 91{ 92 mRenderbufferProxies.addRef(proxy); 93} 94 95void Texture::releaseProxy(const FramebufferAttachment *proxy) 96{ 97 mRenderbufferProxies.release(proxy); 98} 99 100void Texture::setMinFilter(GLenum filter) 101{ 102 mSamplerState.minFilter = filter; 103} 104 105void Texture::setMagFilter(GLenum filter) 106{ 107 mSamplerState.magFilter = filter; 108} 109 110void Texture::setWrapS(GLenum wrap) 111{ 112 mSamplerState.wrapS = wrap; 113} 114 115void Texture::setWrapT(GLenum wrap) 116{ 117 mSamplerState.wrapT = wrap; 118} 119 120void Texture::setWrapR(GLenum wrap) 121{ 122 mSamplerState.wrapR = wrap; 123} 124 125void Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy) 126{ 127 mSamplerState.maxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy); 128} 129 130void Texture::setCompareMode(GLenum mode) 131{ 132 mSamplerState.compareMode = mode; 133} 134 135void Texture::setCompareFunc(GLenum func) 136{ 137 mSamplerState.compareFunc = func; 138} 139 140void Texture::setSwizzleRed(GLenum swizzle) 141{ 142 mSamplerState.swizzleRed = swizzle; 143} 144 145void Texture::setSwizzleGreen(GLenum swizzle) 146{ 147 mSamplerState.swizzleGreen = swizzle; 148} 149 150void Texture::setSwizzleBlue(GLenum swizzle) 151{ 152 mSamplerState.swizzleBlue = swizzle; 153} 154 155void Texture::setSwizzleAlpha(GLenum swizzle) 156{ 157 mSamplerState.swizzleAlpha = swizzle; 158} 159 160void Texture::setBaseLevel(GLint baseLevel) 161{ 162 mSamplerState.baseLevel = baseLevel; 163} 164 165void Texture::setMaxLevel(GLint maxLevel) 166{ 167 mSamplerState.maxLevel = maxLevel; 168} 169 170void Texture::setMinLod(GLfloat minLod) 171{ 172 mSamplerState.minLod = minLod; 173} 174 175void Texture::setMaxLod(GLfloat maxLod) 176{ 177 mSamplerState.maxLod = maxLod; 178} 179 180void Texture::setUsage(GLenum usage) 181{ 182 mUsage = usage; 183} 184 185GLenum Texture::getMinFilter() const 186{ 187 return mSamplerState.minFilter; 188} 189 190GLenum Texture::getMagFilter() const 191{ 192 return mSamplerState.magFilter; 193} 194 195GLenum Texture::getWrapS() const 196{ 197 return mSamplerState.wrapS; 198} 199 200GLenum Texture::getWrapT() const 201{ 202 return mSamplerState.wrapT; 203} 204 205GLenum Texture::getWrapR() const 206{ 207 return mSamplerState.wrapR; 208} 209 210float Texture::getMaxAnisotropy() const 211{ 212 return mSamplerState.maxAnisotropy; 213} 214 215GLenum Texture::getSwizzleRed() const 216{ 217 return mSamplerState.swizzleRed; 218} 219 220GLenum Texture::getSwizzleGreen() const 221{ 222 return mSamplerState.swizzleGreen; 223} 224 225GLenum Texture::getSwizzleBlue() const 226{ 227 return mSamplerState.swizzleBlue; 228} 229 230GLenum Texture::getSwizzleAlpha() const 231{ 232 return mSamplerState.swizzleAlpha; 233} 234 235GLint Texture::getBaseLevel() const 236{ 237 return mSamplerState.baseLevel; 238} 239 240GLint Texture::getMaxLevel() const 241{ 242 return mSamplerState.maxLevel; 243} 244 245GLfloat Texture::getMinLod() const 246{ 247 return mSamplerState.minLod; 248} 249 250GLfloat Texture::getMaxLod() const 251{ 252 return mSamplerState.maxLod; 253} 254 255bool Texture::isSwizzled() const 256{ 257 return mSamplerState.swizzleRed != GL_RED || 258 mSamplerState.swizzleGreen != GL_GREEN || 259 mSamplerState.swizzleBlue != GL_BLUE || 260 mSamplerState.swizzleAlpha != GL_ALPHA; 261} 262 263void Texture::getSamplerState(SamplerState *sampler) 264{ 265 *sampler = mSamplerState; 266 267 // Offset the effective base level by the texture storage's top level 268 rx::TextureStorageInterface *texture = getNativeTexture(); 269 int topLevel = texture ? texture->getTopLevel() : 0; 270 sampler->baseLevel = topLevel + mSamplerState.baseLevel; 271} 272 273GLenum Texture::getUsage() const 274{ 275 return mUsage; 276} 277 278GLint Texture::getBaseLevelWidth() const 279{ 280 const rx::Image *baseImage = getBaseLevelImage(); 281 return (baseImage ? baseImage->getWidth() : 0); 282} 283 284GLint Texture::getBaseLevelHeight() const 285{ 286 const rx::Image *baseImage = getBaseLevelImage(); 287 return (baseImage ? baseImage->getHeight() : 0); 288} 289 290GLint Texture::getBaseLevelDepth() const 291{ 292 const rx::Image *baseImage = getBaseLevelImage(); 293 return (baseImage ? baseImage->getDepth() : 0); 294} 295 296// Note: "base level image" is loosely defined to be any image from the base level, 297// where in the base of 2D array textures and cube maps there are several. Don't use 298// the base level image for anything except querying texture format and size. 299GLenum Texture::getBaseLevelInternalFormat() const 300{ 301 const rx::Image *baseImage = getBaseLevelImage(); 302 return (baseImage ? baseImage->getInternalFormat() : GL_NONE); 303} 304 305void Texture::setImage(const PixelUnpackState &unpack, GLenum type, const void *pixels, rx::Image *image) 306{ 307 // No-op 308 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0) 309 { 310 return; 311 } 312 313 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains. 314 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components. 315 const void *pixelData = pixels; 316 317 if (unpack.pixelBuffer.id() != 0) 318 { 319 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported 320 Buffer *pixelBuffer = unpack.pixelBuffer.get(); 321 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels); 322 const void *bufferData = pixelBuffer->getStorage()->getData(); 323 pixelData = static_cast<const unsigned char *>(bufferData) + offset; 324 } 325 326 if (pixelData != NULL) 327 { 328 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData); 329 mDirtyImages = true; 330 } 331} 332 333bool Texture::isFastUnpackable(const PixelUnpackState &unpack, GLenum sizedInternalFormat) 334{ 335 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat); 336} 337 338bool Texture::fastUnpackPixels(const PixelUnpackState &unpack, const void *pixels, const Box &destArea, 339 GLenum sizedInternalFormat, GLenum type, rx::RenderTarget *destRenderTarget) 340{ 341 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0) 342 { 343 return true; 344 } 345 346 // In order to perform the fast copy through the shader, we must have the right format, and be able 347 // to create a render target. 348 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat)); 349 350 unsigned int offset = reinterpret_cast<unsigned int>(pixels); 351 352 return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea); 353} 354 355void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image) 356{ 357 if (pixels != NULL) 358 { 359 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels); 360 mDirtyImages = true; 361 } 362} 363 364bool Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, 365 GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels, rx::Image *image) 366{ 367 const void *pixelData = pixels; 368 369 // CPU readback & copy where direct GPU copy is not supported 370 if (unpack.pixelBuffer.id() != 0) 371 { 372 Buffer *pixelBuffer = unpack.pixelBuffer.get(); 373 unsigned int offset = reinterpret_cast<unsigned int>(pixels); 374 const void *bufferData = pixelBuffer->getStorage()->getData(); 375 pixelData = static_cast<const unsigned char *>(bufferData) + offset; 376 } 377 378 if (pixelData != NULL) 379 { 380 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixelData); 381 mDirtyImages = true; 382 } 383 384 return true; 385} 386 387bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, 388 GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image) 389{ 390 if (pixels != NULL) 391 { 392 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels); 393 mDirtyImages = true; 394 } 395 396 return true; 397} 398 399rx::TextureStorageInterface *Texture::getNativeTexture() 400{ 401 // ensure the underlying texture is created 402 initializeStorage(false); 403 404 rx::TextureStorageInterface *storage = getBaseLevelStorage(); 405 if (storage) 406 { 407 updateStorage(); 408 } 409 410 return storage; 411} 412 413bool Texture::hasDirtyImages() const 414{ 415 return mDirtyImages; 416} 417 418void Texture::resetDirty() 419{ 420 mDirtyImages = false; 421} 422 423unsigned int Texture::getTextureSerial() 424{ 425 rx::TextureStorageInterface *texture = getNativeTexture(); 426 return texture ? texture->getTextureSerial() : 0; 427} 428 429bool Texture::isImmutable() const 430{ 431 return mImmutable; 432} 433 434int Texture::immutableLevelCount() 435{ 436 return (mImmutable ? getNativeTexture()->getStorageInstance()->getLevelCount() : 0); 437} 438 439GLint Texture::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const 440{ 441 if ((isPow2(width) && isPow2(height) && isPow2(depth)) || mRenderer->getNonPower2TextureSupport()) 442 { 443 // Maximum number of levels 444 return log2(std::max(std::max(width, height), depth)) + 1; 445 } 446 else 447 { 448 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps. 449 return 1; 450 } 451} 452 453int Texture::mipLevels() const 454{ 455 return log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1; 456} 457 458Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D) 459{ 460 mTexStorage = NULL; 461 mSurface = NULL; 462 463 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) 464 { 465 mImageArray[i] = renderer->createImage(); 466 } 467} 468 469Texture2D::~Texture2D() 470{ 471 delete mTexStorage; 472 mTexStorage = NULL; 473 474 if (mSurface) 475 { 476 mSurface->setBoundTexture(NULL); 477 mSurface = NULL; 478 } 479 480 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) 481 { 482 delete mImageArray[i]; 483 } 484} 485 486GLsizei Texture2D::getWidth(GLint level) const 487{ 488 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) 489 return mImageArray[level]->getWidth(); 490 else 491 return 0; 492} 493 494GLsizei Texture2D::getHeight(GLint level) const 495{ 496 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) 497 return mImageArray[level]->getHeight(); 498 else 499 return 0; 500} 501 502GLenum Texture2D::getInternalFormat(GLint level) const 503{ 504 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) 505 return mImageArray[level]->getInternalFormat(); 506 else 507 return GL_NONE; 508} 509 510GLenum Texture2D::getActualFormat(GLint level) const 511{ 512 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) 513 return mImageArray[level]->getActualFormat(); 514 else 515 return GL_NONE; 516} 517 518void Texture2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height) 519{ 520 releaseTexImage(); 521 522 // If there currently is a corresponding storage texture image, it has these parameters 523 const int storageWidth = std::max(1, getBaseLevelWidth() >> level); 524 const int storageHeight = std::max(1, getBaseLevelHeight() >> level); 525 const GLenum storageFormat = getBaseLevelInternalFormat(); 526 527 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false); 528 529 if (mTexStorage) 530 { 531 const int storageLevels = mTexStorage->getLevelCount(); 532 533 if ((level >= storageLevels && storageLevels != 0) || 534 width != storageWidth || 535 height != storageHeight || 536 internalformat != storageFormat) // Discard mismatched storage 537 { 538 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) 539 { 540 mImageArray[i]->markDirty(); 541 } 542 543 delete mTexStorage; 544 mTexStorage = NULL; 545 mDirtyImages = true; 546 } 547 } 548} 549 550void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) 551{ 552 GLuint clientVersion = mRenderer->getCurrentClientVersion(); 553 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat 554 : GetSizedInternalFormat(format, type, clientVersion); 555 redefineImage(level, sizedInternalFormat, width, height); 556 557 bool fastUnpacked = false; 558 559 // Attempt a fast gpu copy of the pixel data to the surface 560 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level)) 561 { 562 // Will try to create RT storage if it does not exist 563 rx::RenderTarget *destRenderTarget = getRenderTarget(level); 564 Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1); 565 566 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget)) 567 { 568 // Ensure we don't overwrite our newly initialized data 569 mImageArray[level]->markClean(); 570 571 fastUnpacked = true; 572 } 573 } 574 575 if (!fastUnpacked) 576 { 577 Texture::setImage(unpack, type, pixels, mImageArray[level]); 578 } 579} 580 581void Texture2D::bindTexImage(egl::Surface *surface) 582{ 583 releaseTexImage(); 584 585 GLenum internalformat = surface->getFormat(); 586 587 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true); 588 589 delete mTexStorage; 590 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain()); 591 592 mDirtyImages = true; 593 mSurface = surface; 594 mSurface->setBoundTexture(this); 595} 596 597void Texture2D::releaseTexImage() 598{ 599 if (mSurface) 600 { 601 mSurface->setBoundTexture(NULL); 602 mSurface = NULL; 603 604 if (mTexStorage) 605 { 606 delete mTexStorage; 607 mTexStorage = NULL; 608 } 609 610 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) 611 { 612 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true); 613 } 614 } 615} 616 617void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) 618{ 619 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly 620 redefineImage(level, format, width, height); 621 622 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]); 623} 624 625void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) 626{ 627 if (isValidLevel(level)) 628 { 629 rx::Image *image = mImageArray[level]; 630 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, width, height)) 631 { 632 image->markClean(); 633 } 634 } 635} 636 637void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) 638{ 639 bool fastUnpacked = false; 640 641 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level)) 642 { 643 rx::RenderTarget *renderTarget = getRenderTarget(level); 644 Box destArea(xoffset, yoffset, 0, width, height, 1); 645 646 if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget)) 647 { 648 // Ensure we don't overwrite our newly initialized data 649 mImageArray[level]->markClean(); 650 651 fastUnpacked = true; 652 } 653 } 654 655 if (!fastUnpacked && Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[level])) 656 { 657 commitRect(level, xoffset, yoffset, width, height); 658 } 659} 660 661void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels) 662{ 663 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level])) 664 { 665 commitRect(level, xoffset, yoffset, width, height); 666 } 667} 668 669void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) 670{ 671 GLuint clientVersion = mRenderer->getCurrentClientVersion(); 672 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format 673 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion); 674 redefineImage(level, sizedInternalFormat, width, height); 675 676 if (!mImageArray[level]->isRenderableFormat()) 677 { 678 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source); 679 mDirtyImages = true; 680 } 681 else 682 { 683 ensureRenderTarget(); 684 mImageArray[level]->markClean(); 685 686 if (width != 0 && height != 0 && isValidLevel(level)) 687 { 688 gl::Rectangle sourceRect; 689 sourceRect.x = x; 690 sourceRect.width = width; 691 sourceRect.y = y; 692 sourceRect.height = height; 693 694 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level); 695 } 696 } 697} 698 699void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) 700{ 701 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and 702 // the current level we're copying to is defined (with appropriate format, width & height) 703 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0); 704 705 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget)) 706 { 707 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source); 708 mDirtyImages = true; 709 } 710 else 711 { 712 ensureRenderTarget(); 713 714 if (isValidLevel(level)) 715 { 716 updateStorageLevel(level); 717 718 GLuint clientVersion = mRenderer->getCurrentClientVersion(); 719 720 gl::Rectangle sourceRect; 721 sourceRect.x = x; 722 sourceRect.width = width; 723 sourceRect.y = y; 724 sourceRect.height = height; 725 726 mRenderer->copyImage(source, sourceRect, 727 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion), 728 xoffset, yoffset, mTexStorage, level); 729 } 730 } 731} 732 733void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) 734{ 735 for (int level = 0; level < levels; level++) 736 { 737 GLsizei levelWidth = std::max(1, width >> level); 738 GLsizei levelHeight = std::max(1, height >> level); 739 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true); 740 } 741 742 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) 743 { 744 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true); 745 } 746 747 mImmutable = true; 748 749 setCompleteTexStorage(new rx::TextureStorageInterface2D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, levels)); 750} 751 752void Texture2D::setCompleteTexStorage(rx::TextureStorageInterface2D *newCompleteTexStorage) 753{ 754 SafeDelete(mTexStorage); 755 mTexStorage = newCompleteTexStorage; 756 757 if (mTexStorage && mTexStorage->isManaged()) 758 { 759 for (int level = 0; level < mTexStorage->getLevelCount(); level++) 760 { 761 mImageArray[level]->setManagedSurface(mTexStorage, level); 762 } 763 } 764 765 mDirtyImages = true; 766} 767 768// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85. 769bool Texture2D::isSamplerComplete(const SamplerState &samplerState) const 770{ 771 GLsizei width = getBaseLevelWidth(); 772 GLsizei height = getBaseLevelHeight(); 773 774 if (width <= 0 || height <= 0) 775 { 776 return false; 777 } 778 779 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer)) 780 { 781 if (samplerState.magFilter != GL_NEAREST || 782 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST)) 783 { 784 return false; 785 } 786 } 787 788 bool npotSupport = mRenderer->getNonPower2TextureSupport(); 789 790 if (!npotSupport) 791 { 792 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) || 793 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height))) 794 { 795 return false; 796 } 797 } 798 799 if (IsMipmapFiltered(samplerState)) 800 { 801 if (!npotSupport) 802 { 803 if (!isPow2(width) || !isPow2(height)) 804 { 805 return false; 806 } 807 } 808 809 if (!isMipmapComplete()) 810 { 811 return false; 812 } 813 } 814 815 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if: 816 // The internalformat specified for the texture arrays is a sized internal depth or 817 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_- 818 // MODE is NONE, and either the magnification filter is not NEAREST or the mini- 819 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST. 820 if (gl::GetDepthBits(getInternalFormat(0), mRenderer->getCurrentClientVersion()) > 0 && 821 mRenderer->getCurrentClientVersion() > 2) 822 { 823 if (mSamplerState.compareMode == GL_NONE) 824 { 825 if ((mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) || 826 mSamplerState.magFilter != GL_NEAREST) 827 { 828 return false; 829 } 830 } 831 } 832 833 return true; 834} 835 836// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. 837bool Texture2D::isMipmapComplete() const 838{ 839 int levelCount = mipLevels(); 840 841 for (int level = 0; level < levelCount; level++) 842 { 843 if (!isLevelComplete(level)) 844 { 845 return false; 846 } 847 } 848 849 return true; 850} 851 852bool Texture2D::isLevelComplete(int level) const 853{ 854 if (isImmutable()) 855 { 856 return true; 857 } 858 859 const rx::Image *baseImage = getBaseLevelImage(); 860 861 GLsizei width = baseImage->getWidth(); 862 GLsizei height = baseImage->getHeight(); 863 864 if (width <= 0 || height <= 0) 865 { 866 return false; 867 } 868 869 // The base image level is complete if the width and height are positive 870 if (level == 0) 871 { 872 return true; 873 } 874 875 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL); 876 rx::Image *image = mImageArray[level]; 877 878 if (image->getInternalFormat() != baseImage->getInternalFormat()) 879 { 880 return false; 881 } 882 883 if (image->getWidth() != std::max(1, width >> level)) 884 { 885 return false; 886 } 887 888 if (image->getHeight() != std::max(1, height >> level)) 889 { 890 return false; 891 } 892 893 return true; 894} 895 896bool Texture2D::isCompressed(GLint level) const 897{ 898 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion()); 899} 900 901bool Texture2D::isDepth(GLint level) const 902{ 903 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0; 904} 905 906// Constructs a native texture resource from the texture images 907void Texture2D::initializeStorage(bool renderTarget) 908{ 909 // Only initialize the first time this texture is used as a render target or shader resource 910 if (mTexStorage) 911 { 912 return; 913 } 914 915 // do not attempt to create storage for nonexistant data 916 if (!isLevelComplete(0)) 917 { 918 return; 919 } 920 921 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); 922 923 setCompleteTexStorage(createCompleteStorage(createRenderTarget)); 924 ASSERT(mTexStorage); 925 926 // flush image data to the storage 927 updateStorage(); 928} 929 930rx::TextureStorageInterface2D *Texture2D::createCompleteStorage(bool renderTarget) const 931{ 932 GLsizei width = getBaseLevelWidth(); 933 GLsizei height = getBaseLevelHeight(); 934 935 ASSERT(width > 0 && height > 0); 936 937 // use existing storage level count, when previously specified by TexStorage*D 938 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1)); 939 940 return new rx::TextureStorageInterface2D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, levels); 941} 942 943void Texture2D::updateStorage() 944{ 945 ASSERT(mTexStorage != NULL); 946 GLint storageLevels = mTexStorage->getLevelCount(); 947 for (int level = 0; level < storageLevels; level++) 948 { 949 if (mImageArray[level]->isDirty() && isLevelComplete(level)) 950 { 951 updateStorageLevel(level); 952 } 953 } 954} 955 956void Texture2D::updateStorageLevel(int level) 957{ 958 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL); 959 ASSERT(isLevelComplete(level)); 960 961 if (mImageArray[level]->isDirty()) 962 { 963 commitRect(level, 0, 0, getWidth(level), getHeight(level)); 964 } 965} 966 967bool Texture2D::ensureRenderTarget() 968{ 969 initializeStorage(true); 970 971 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0) 972 { 973 ASSERT(mTexStorage); 974 if (!mTexStorage->isRenderTarget()) 975 { 976 rx::TextureStorageInterface2D *newRenderTargetStorage = createCompleteStorage(true); 977 978 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage)) 979 { 980 delete newRenderTargetStorage; 981 return gl::error(GL_OUT_OF_MEMORY, false); 982 } 983 984 setCompleteTexStorage(newRenderTargetStorage); 985 } 986 } 987 988 return (mTexStorage && mTexStorage->isRenderTarget()); 989} 990 991void Texture2D::generateMipmaps() 992{ 993 // Purge array levels 1 through q and reset them to represent the generated mipmap levels. 994 int levelCount = mipLevels(); 995 for (int level = 1; level < levelCount; level++) 996 { 997 redefineImage(level, getBaseLevelInternalFormat(), 998 std::max(getBaseLevelWidth() >> level, 1), 999 std::max(getBaseLevelHeight() >> level, 1)); 1000 } 1001 1002 if (mTexStorage && mTexStorage->isRenderTarget()) 1003 { 1004 for (int level = 1; level < levelCount; level++) 1005 { 1006 mTexStorage->generateMipmap(level); 1007 1008 mImageArray[level]->markClean(); 1009 } 1010 } 1011 else 1012 { 1013 for (int level = 1; level < levelCount; level++) 1014 { 1015 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]); 1016 } 1017 } 1018} 1019 1020const rx::Image *Texture2D::getBaseLevelImage() const 1021{ 1022 return mImageArray[0]; 1023} 1024 1025rx::TextureStorageInterface *Texture2D::getBaseLevelStorage() 1026{ 1027 return mTexStorage; 1028} 1029 1030FramebufferAttachment *Texture2D::getAttachment(GLint level) 1031{ 1032 FramebufferAttachment *attachment = mRenderbufferProxies.get(level, 0); 1033 if (!attachment) 1034 { 1035 attachment = new FramebufferAttachment(mRenderer, id(), new Texture2DAttachment(this, level)); 1036 mRenderbufferProxies.add(level, 0, attachment); 1037 } 1038 1039 return attachment; 1040} 1041 1042unsigned int Texture2D::getRenderTargetSerial(GLint level) 1043{ 1044 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level) : 0); 1045} 1046 1047rx::RenderTarget *Texture2D::getRenderTarget(GLint level) 1048{ 1049 // ensure the underlying texture is created 1050 if (!ensureRenderTarget()) 1051 { 1052 return NULL; 1053 } 1054 1055 updateStorageLevel(level); 1056 1057 // ensure this is NOT a depth texture 1058 if (isDepth(level)) 1059 { 1060 return NULL; 1061 } 1062 1063 return mTexStorage->getRenderTarget(level); 1064} 1065 1066rx::RenderTarget *Texture2D::getDepthSencil(GLint level) 1067{ 1068 // ensure the underlying texture is created 1069 if (!ensureRenderTarget()) 1070 { 1071 return NULL; 1072 } 1073 1074 updateStorageLevel(level); 1075 1076 // ensure this is actually a depth texture 1077 if (!isDepth(level)) 1078 { 1079 return NULL; 1080 } 1081 1082 return mTexStorage->getRenderTarget(level); 1083} 1084 1085bool Texture2D::isValidLevel(int level) const 1086{ 1087 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false); 1088} 1089 1090TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP) 1091{ 1092 mTexStorage = NULL; 1093 for (int i = 0; i < 6; i++) 1094 { 1095 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j) 1096 { 1097 mImageArray[i][j] = renderer->createImage(); 1098 } 1099 } 1100} 1101 1102TextureCubeMap::~TextureCubeMap() 1103{ 1104 for (int i = 0; i < 6; i++) 1105 { 1106 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j) 1107 { 1108 delete mImageArray[i][j]; 1109 } 1110 } 1111 1112 delete mTexStorage; 1113 mTexStorage = NULL; 1114} 1115 1116GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const 1117{ 1118 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) 1119 return mImageArray[targetToIndex(target)][level]->getWidth(); 1120 else 1121 return 0; 1122} 1123 1124GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const 1125{ 1126 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) 1127 return mImageArray[targetToIndex(target)][level]->getHeight(); 1128 else 1129 return 0; 1130} 1131 1132GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const 1133{ 1134 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) 1135 return mImageArray[targetToIndex(target)][level]->getInternalFormat(); 1136 else 1137 return GL_NONE; 1138} 1139 1140GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const 1141{ 1142 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) 1143 return mImageArray[targetToIndex(target)][level]->getActualFormat(); 1144 else 1145 return GL_NONE; 1146} 1147 1148void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) 1149{ 1150 setImage(0, level, width, height, internalFormat, format, type, unpack, pixels); 1151} 1152 1153void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) 1154{ 1155 setImage(1, level, width, height, internalFormat, format, type, unpack, pixels); 1156} 1157 1158void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) 1159{ 1160 setImage(2, level, width, height, internalFormat, format, type, unpack, pixels); 1161} 1162 1163void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) 1164{ 1165 setImage(3, level, width, height, internalFormat, format, type, unpack, pixels); 1166} 1167 1168void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) 1169{ 1170 setImage(4, level, width, height, internalFormat, format, type, unpack, pixels); 1171} 1172 1173void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) 1174{ 1175 setImage(5, level, width, height, internalFormat, format, type, unpack, pixels); 1176} 1177 1178void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) 1179{ 1180 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly 1181 int faceIndex = targetToIndex(target); 1182 redefineImage(faceIndex, level, format, width, height); 1183 1184 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]); 1185} 1186 1187void TextureCubeMap::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) 1188{ 1189 if (isValidFaceLevel(faceIndex, level)) 1190 { 1191 rx::Image *image = mImageArray[faceIndex][level]; 1192 if (image->copyToStorage(mTexStorage, faceIndex, level, xoffset, yoffset, width, height)) 1193 image->markClean(); 1194 } 1195} 1196 1197void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) 1198{ 1199 int faceIndex = targetToIndex(target); 1200 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex][level])) 1201 { 1202 commitRect(faceIndex, level, xoffset, yoffset, width, height); 1203 } 1204} 1205 1206void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels) 1207{ 1208 int faceIndex = targetToIndex(target); 1209 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level])) 1210 { 1211 commitRect(faceIndex, level, xoffset, yoffset, width, height); 1212 } 1213} 1214 1215// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86. 1216bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const 1217{ 1218 int size = getBaseLevelWidth(); 1219 1220 bool mipmapping = IsMipmapFiltered(samplerState); 1221 1222 if (!IsTextureFilteringSupported(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0), mRenderer)) 1223 { 1224 if (samplerState.magFilter != GL_NEAREST || 1225 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST)) 1226 { 1227 return false; 1228 } 1229 } 1230 1231 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport()) 1232 { 1233 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping) 1234 { 1235 return false; 1236 } 1237 } 1238 1239 if (!mipmapping) 1240 { 1241 if (!isCubeComplete()) 1242 { 1243 return false; 1244 } 1245 } 1246 else 1247 { 1248 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete() 1249 { 1250 return false; 1251 } 1252 } 1253 1254 return true; 1255} 1256 1257// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. 1258bool TextureCubeMap::isCubeComplete() const 1259{ 1260 int baseWidth = getBaseLevelWidth(); 1261 int baseHeight = getBaseLevelHeight(); 1262 GLenum baseFormat = getBaseLevelInternalFormat(); 1263 1264 if (baseWidth <= 0 || baseWidth != baseHeight) 1265 { 1266 return false; 1267 } 1268 1269 for (int faceIndex = 1; faceIndex < 6; faceIndex++) 1270 { 1271 const rx::Image &faceBaseImage = *mImageArray[faceIndex][0]; 1272 1273 if (faceBaseImage.getWidth() != baseWidth || 1274 faceBaseImage.getHeight() != baseHeight || 1275 faceBaseImage.getInternalFormat() != baseFormat ) 1276 { 1277 return false; 1278 } 1279 } 1280 1281 return true; 1282} 1283 1284bool TextureCubeMap::isMipmapCubeComplete() const 1285{ 1286 if (isImmutable()) 1287 { 1288 return true; 1289 } 1290 1291 if (!isCubeComplete()) 1292 { 1293 return false; 1294 } 1295 1296 int levelCount = mipLevels(); 1297 1298 for (int face = 0; face < 6; face++) 1299 { 1300 for (int level = 1; level < levelCount; level++) 1301 { 1302 if (!isFaceLevelComplete(face, level)) 1303 { 1304 return false; 1305 } 1306 } 1307 } 1308 1309 return true; 1310} 1311 1312bool TextureCubeMap::isFaceLevelComplete(int faceIndex, int level) const 1313{ 1314 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL); 1315 1316 if (isImmutable()) 1317 { 1318 return true; 1319 } 1320 1321 int baseSize = getBaseLevelWidth(); 1322 1323 if (baseSize <= 0) 1324 { 1325 return false; 1326 } 1327 1328 // "isCubeComplete" checks for base level completeness and we must call that 1329 // to determine if any face at level 0 is complete. We omit that check here 1330 // to avoid re-checking cube-completeness for every face at level 0. 1331 if (level == 0) 1332 { 1333 return true; 1334 } 1335 1336 // Check that non-zero levels are consistent with the base level. 1337 const rx::Image *faceLevelImage = mImageArray[faceIndex][level]; 1338 1339 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat()) 1340 { 1341 return false; 1342 } 1343 1344 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level)) 1345 { 1346 return false; 1347 } 1348 1349 return true; 1350} 1351 1352bool TextureCubeMap::isCompressed(GLenum target, GLint level) const 1353{ 1354 return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion()); 1355} 1356 1357bool TextureCubeMap::isDepth(GLenum target, GLint level) const 1358{ 1359 return GetDepthBits(getInternalFormat(target, level), mRenderer->getCurrentClientVersion()) > 0; 1360} 1361 1362void TextureCubeMap::initializeStorage(bool renderTarget) 1363{ 1364 // Only initialize the first time this texture is used as a render target or shader resource 1365 if (mTexStorage) 1366 { 1367 return; 1368 } 1369 1370 // do not attempt to create storage for nonexistant data 1371 if (!isFaceLevelComplete(0, 0)) 1372 { 1373 return; 1374 } 1375 1376 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); 1377 1378 setCompleteTexStorage(createCompleteStorage(createRenderTarget)); 1379 ASSERT(mTexStorage); 1380 1381 // flush image data to the storage 1382 updateStorage(); 1383} 1384 1385rx::TextureStorageInterfaceCube *TextureCubeMap::createCompleteStorage(bool renderTarget) const 1386{ 1387 GLsizei size = getBaseLevelWidth(); 1388 1389 ASSERT(size > 0); 1390 1391 // use existing storage level count, when previously specified by TexStorage*D 1392 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1)); 1393 1394 return new rx::TextureStorageInterfaceCube(mRenderer, getBaseLevelInternalFormat(), renderTarget, size, levels); 1395} 1396 1397void TextureCubeMap::setCompleteTexStorage(rx::TextureStorageInterfaceCube *newCompleteTexStorage) 1398{ 1399 SafeDelete(mTexStorage); 1400 mTexStorage = newCompleteTexStorage; 1401 1402 if (mTexStorage && mTexStorage->isManaged()) 1403 { 1404 for (int faceIndex = 0; faceIndex < 6; faceIndex++) 1405 { 1406 for (int level = 0; level < mTexStorage->getLevelCount(); level++) 1407 { 1408 mImageArray[faceIndex][level]->setManagedSurface(mTexStorage, faceIndex, level); 1409 } 1410 } 1411 } 1412 1413 mDirtyImages = true; 1414} 1415 1416void TextureCubeMap::updateStorage() 1417{ 1418 ASSERT(mTexStorage != NULL); 1419 GLint storageLevels = mTexStorage->getLevelCount(); 1420 for (int face = 0; face < 6; face++) 1421 { 1422 for (int level = 0; level < storageLevels; level++) 1423 { 1424 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level)) 1425 { 1426 updateStorageFaceLevel(face, level); 1427 } 1428 } 1429 } 1430} 1431 1432void TextureCubeMap::updateStorageFaceLevel(int faceIndex, int level) 1433{ 1434 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL); 1435 rx::Image *image = mImageArray[faceIndex][level]; 1436 1437 if (image->isDirty()) 1438 { 1439 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight()); 1440 } 1441} 1442 1443bool TextureCubeMap::ensureRenderTarget() 1444{ 1445 initializeStorage(true); 1446 1447 if (getBaseLevelWidth() > 0) 1448 { 1449 ASSERT(mTexStorage); 1450 if (!mTexStorage->isRenderTarget()) 1451 { 1452 rx::TextureStorageInterfaceCube *newRenderTargetStorage = createCompleteStorage(true); 1453 1454 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage)) 1455 { 1456 delete newRenderTargetStorage; 1457 return gl::error(GL_OUT_OF_MEMORY, false); 1458 } 1459 1460 setCompleteTexStorage(newRenderTargetStorage); 1461 } 1462 } 1463 1464 return (mTexStorage && mTexStorage->isRenderTarget()); 1465} 1466 1467void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) 1468{ 1469 GLuint clientVersion = mRenderer->getCurrentClientVersion(); 1470 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat 1471 : GetSizedInternalFormat(format, type, clientVersion); 1472 1473 redefineImage(faceIndex, level, sizedInternalFormat, width, height); 1474 1475 Texture::setImage(unpack, type, pixels, mImageArray[faceIndex][level]); 1476} 1477 1478int TextureCubeMap::targetToIndex(GLenum target) 1479{ 1480 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1); 1481 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2); 1482 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3); 1483 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4); 1484 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5); 1485 1486 return target - GL_TEXTURE_CUBE_MAP_POSITIVE_X; 1487} 1488 1489void TextureCubeMap::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height) 1490{ 1491 // If there currently is a corresponding storage texture image, it has these parameters 1492 const int storageWidth = std::max(1, getBaseLevelWidth() >> level); 1493 const int storageHeight = std::max(1, getBaseLevelHeight() >> level); 1494 const GLenum storageFormat = getBaseLevelInternalFormat(); 1495 1496 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false); 1497 1498 if (mTexStorage) 1499 { 1500 const int storageLevels = mTexStorage->getLevelCount(); 1501 1502 if ((level >= storageLevels && storageLevels != 0) || 1503 width != storageWidth || 1504 height != storageHeight || 1505 internalformat != storageFormat) // Discard mismatched storage 1506 { 1507 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) 1508 { 1509 for (int faceIndex = 0; faceIndex < 6; faceIndex++) 1510 { 1511 mImageArray[faceIndex][level]->markDirty(); 1512 } 1513 } 1514 1515 delete mTexStorage; 1516 mTexStorage = NULL; 1517 1518 mDirtyImages = true; 1519 } 1520 } 1521} 1522 1523void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) 1524{ 1525 int faceIndex = targetToIndex(target); 1526 GLuint clientVersion = mRenderer->getCurrentClientVersion(); 1527 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format 1528 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion); 1529 redefineImage(faceIndex, level, sizedInternalFormat, width, height); 1530 1531 if (!mImageArray[faceIndex][level]->isRenderableFormat()) 1532 { 1533 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source); 1534 mDirtyImages = true; 1535 } 1536 else 1537 { 1538 ensureRenderTarget(); 1539 mImageArray[faceIndex][level]->markClean(); 1540 1541 ASSERT(width == height); 1542 1543 if (width > 0 && isValidFaceLevel(faceIndex, level)) 1544 { 1545 gl::Rectangle sourceRect; 1546 sourceRect.x = x; 1547 sourceRect.width = width; 1548 sourceRect.y = y; 1549 sourceRect.height = height; 1550 1551 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level); 1552 } 1553 } 1554} 1555 1556void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) 1557{ 1558 int faceIndex = targetToIndex(target); 1559 1560 // We can only make our texture storage to a render target if the level we're copying *to* is complete 1561 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot 1562 // rely on the "getBaseLevel*" methods reliably otherwise. 1563 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete(); 1564 1565 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget)) 1566 { 1567 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source); 1568 mDirtyImages = true; 1569 } 1570 else 1571 { 1572 ensureRenderTarget(); 1573 1574 if (isValidFaceLevel(faceIndex, level)) 1575 { 1576 updateStorageFaceLevel(faceIndex, level); 1577 1578 GLuint clientVersion = mRenderer->getCurrentClientVersion(); 1579 1580 gl::Rectangle sourceRect; 1581 sourceRect.x = x; 1582 sourceRect.width = width; 1583 sourceRect.y = y; 1584 sourceRect.height = height; 1585 1586 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat(), clientVersion), 1587 xoffset, yoffset, mTexStorage, target, level); 1588 } 1589 } 1590} 1591 1592void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size) 1593{ 1594 for (int level = 0; level < levels; level++) 1595 { 1596 GLsizei mipSize = std::max(1, size >> level); 1597 for (int faceIndex = 0; faceIndex < 6; faceIndex++) 1598 { 1599 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true); 1600 } 1601 } 1602 1603 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) 1604 { 1605 for (int faceIndex = 0; faceIndex < 6; faceIndex++) 1606 { 1607 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true); 1608 } 1609 } 1610 1611 mImmutable = true; 1612 1613 setCompleteTexStorage(new rx::TextureStorageInterfaceCube(mRenderer, internalformat, IsRenderTargetUsage(mUsage), size, levels)); 1614} 1615 1616void TextureCubeMap::generateMipmaps() 1617{ 1618 // Purge array levels 1 through q and reset them to represent the generated mipmap levels. 1619 int levelCount = mipLevels(); 1620 for (int faceIndex = 0; faceIndex < 6; faceIndex++) 1621 { 1622 for (int level = 1; level < levelCount; level++) 1623 { 1624 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1)); 1625 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize); 1626 } 1627 } 1628 1629 if (mTexStorage && mTexStorage->isRenderTarget()) 1630 { 1631 for (int faceIndex = 0; faceIndex < 6; faceIndex++) 1632 { 1633 for (int level = 1; level < levelCount; level++) 1634 { 1635 mTexStorage->generateMipmap(faceIndex, level); 1636 1637 mImageArray[faceIndex][level]->markClean(); 1638 } 1639 } 1640 } 1641 else 1642 { 1643 for (int faceIndex = 0; faceIndex < 6; faceIndex++) 1644 { 1645 for (int level = 1; level < levelCount; level++) 1646 { 1647 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]); 1648 } 1649 } 1650 } 1651} 1652 1653const rx::Image *TextureCubeMap::getBaseLevelImage() const 1654{ 1655 // Note: if we are not cube-complete, there is no single base level image that can describe all 1656 // cube faces, so this method is only well-defined for a cube-complete base level. 1657 return mImageArray[0][0]; 1658} 1659 1660rx::TextureStorageInterface *TextureCubeMap::getBaseLevelStorage() 1661{ 1662 return mTexStorage; 1663} 1664 1665FramebufferAttachment *TextureCubeMap::getAttachment(GLenum target, GLint level) 1666{ 1667 ASSERT(!IsCubemapTextureTarget(target)); 1668 int faceIndex = targetToIndex(target); 1669 1670 FramebufferAttachment *attachment = mRenderbufferProxies.get(level, faceIndex); 1671 if (!attachment) 1672 { 1673 attachment = new FramebufferAttachment(mRenderer, id(), new TextureCubeMapAttachment(this, target, level)); 1674 mRenderbufferProxies.add(level, faceIndex, attachment); 1675 } 1676 1677 return attachment; 1678} 1679 1680unsigned int TextureCubeMap::getRenderTargetSerial(GLenum target, GLint level) 1681{ 1682 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(target, level) : 0); 1683} 1684 1685rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level) 1686{ 1687 ASSERT(IsCubemapTextureTarget(target)); 1688 1689 // ensure the underlying texture is created 1690 if (!ensureRenderTarget()) 1691 { 1692 return NULL; 1693 } 1694 1695 updateStorageFaceLevel(targetToIndex(target), level); 1696 1697 // ensure this is NOT a depth texture 1698 if (isDepth(target, level)) 1699 { 1700 return NULL; 1701 } 1702 1703 return mTexStorage->getRenderTarget(target, level); 1704} 1705 1706rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level) 1707{ 1708 ASSERT(IsCubemapTextureTarget(target)); 1709 1710 // ensure the underlying texture is created 1711 if (!ensureRenderTarget()) 1712 { 1713 return NULL; 1714 } 1715 1716 updateStorageFaceLevel(targetToIndex(target), level); 1717 1718 // ensure this is a depth texture 1719 if (!isDepth(target, level)) 1720 { 1721 return NULL; 1722 } 1723 1724 return mTexStorage->getRenderTarget(target, level); 1725} 1726 1727bool TextureCubeMap::isValidFaceLevel(int faceIndex, int level) const 1728{ 1729 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0); 1730} 1731 1732Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D) 1733{ 1734 mTexStorage = NULL; 1735 1736 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) 1737 { 1738 mImageArray[i] = renderer->createImage(); 1739 } 1740} 1741 1742Texture3D::~Texture3D() 1743{ 1744 delete mTexStorage; 1745 mTexStorage = NULL; 1746 1747 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) 1748 { 1749 delete mImageArray[i]; 1750 } 1751} 1752 1753GLsizei Texture3D::getWidth(GLint level) const 1754{ 1755 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0; 1756} 1757 1758GLsizei Texture3D::getHeight(GLint level) const 1759{ 1760 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0; 1761} 1762 1763GLsizei Texture3D::getDepth(GLint level) const 1764{ 1765 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0; 1766} 1767 1768GLenum Texture3D::getInternalFormat(GLint level) const 1769{ 1770 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE; 1771} 1772 1773GLenum Texture3D::getActualFormat(GLint level) const 1774{ 1775 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : GL_NONE; 1776} 1777 1778bool Texture3D::isCompressed(GLint level) const 1779{ 1780 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion()); 1781} 1782 1783bool Texture3D::isDepth(GLint level) const 1784{ 1785 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0; 1786} 1787 1788void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) 1789{ 1790 GLuint clientVersion = mRenderer->getCurrentClientVersion(); 1791 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat 1792 : GetSizedInternalFormat(format, type, clientVersion); 1793 redefineImage(level, sizedInternalFormat, width, height, depth); 1794 1795 bool fastUnpacked = false; 1796 1797 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer 1798 if (isFastUnpackable(unpack, sizedInternalFormat)) 1799 { 1800 // Will try to create RT storage if it does not exist 1801 rx::RenderTarget *destRenderTarget = getRenderTarget(level); 1802 Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level)); 1803 1804 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget)) 1805 { 1806 // Ensure we don't overwrite our newly initialized data 1807 mImageArray[level]->markClean(); 1808 1809 fastUnpacked = true; 1810 } 1811 } 1812 1813 if (!fastUnpacked) 1814 { 1815 Texture::setImage(unpack, type, pixels, mImageArray[level]); 1816 } 1817} 1818 1819void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) 1820{ 1821 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly 1822 redefineImage(level, format, width, height, depth); 1823 1824 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]); 1825} 1826 1827void Texture3D::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) 1828{ 1829 bool fastUnpacked = false; 1830 1831 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer 1832 if (isFastUnpackable(unpack, getInternalFormat(level))) 1833 { 1834 rx::RenderTarget *destRenderTarget = getRenderTarget(level); 1835 Box destArea(xoffset, yoffset, zoffset, width, height, depth); 1836 1837 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget)) 1838 { 1839 // Ensure we don't overwrite our newly initialized data 1840 mImageArray[level]->markClean(); 1841 1842 fastUnpacked = true; 1843 } 1844 } 1845 1846 if (!fastUnpacked && Texture::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, mImageArray[level])) 1847 { 1848 commitRect(level, xoffset, yoffset, zoffset, width, height, depth); 1849 } 1850} 1851 1852void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) 1853{ 1854 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level])) 1855 { 1856 commitRect(level, xoffset, yoffset, zoffset, width, height, depth); 1857 } 1858} 1859 1860void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) 1861{ 1862 for (int level = 0; level < levels; level++) 1863 { 1864 GLsizei levelWidth = std::max(1, width >> level); 1865 GLsizei levelHeight = std::max(1, height >> level); 1866 GLsizei levelDepth = std::max(1, depth >> level); 1867 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true); 1868 } 1869 1870 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) 1871 { 1872 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true); 1873 } 1874 1875 mImmutable = true; 1876 1877 setCompleteTexStorage(new rx::TextureStorageInterface3D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels)); 1878} 1879 1880void Texture3D::generateMipmaps() 1881{ 1882 // Purge array levels 1 through q and reset them to represent the generated mipmap levels. 1883 int levelCount = mipLevels(); 1884 for (int level = 1; level < levelCount; level++) 1885 { 1886 redefineImage(level, getBaseLevelInternalFormat(), 1887 std::max(getBaseLevelWidth() >> level, 1), 1888 std::max(getBaseLevelHeight() >> level, 1), 1889 std::max(getBaseLevelDepth() >> level, 1)); 1890 } 1891 1892 if (mTexStorage && mTexStorage->isRenderTarget()) 1893 { 1894 for (int level = 1; level < levelCount; level++) 1895 { 1896 mTexStorage->generateMipmap(level); 1897 1898 mImageArray[level]->markClean(); 1899 } 1900 } 1901 else 1902 { 1903 for (int level = 1; level < levelCount; level++) 1904 { 1905 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]); 1906 } 1907 } 1908} 1909 1910const rx::Image *Texture3D::getBaseLevelImage() const 1911{ 1912 return mImageArray[0]; 1913} 1914 1915rx::TextureStorageInterface *Texture3D::getBaseLevelStorage() 1916{ 1917 return mTexStorage; 1918} 1919 1920void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) 1921{ 1922 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and 1923 // the current level we're copying to is defined (with appropriate format, width & height) 1924 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0); 1925 1926 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget)) 1927 { 1928 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source); 1929 mDirtyImages = true; 1930 } 1931 else 1932 { 1933 ensureRenderTarget(); 1934 1935 if (isValidLevel(level)) 1936 { 1937 updateStorageLevel(level); 1938 1939 gl::Rectangle sourceRect; 1940 sourceRect.x = x; 1941 sourceRect.width = width; 1942 sourceRect.y = y; 1943 sourceRect.height = height; 1944 1945 GLuint clientVersion = mRenderer->getCurrentClientVersion(); 1946 1947 mRenderer->copyImage(source, sourceRect, 1948 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion), 1949 xoffset, yoffset, zoffset, mTexStorage, level); 1950 } 1951 } 1952} 1953 1954bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const 1955{ 1956 GLsizei width = getBaseLevelWidth(); 1957 GLsizei height = getBaseLevelHeight(); 1958 GLsizei depth = getBaseLevelDepth(); 1959 1960 if (width <= 0 || height <= 0 || depth <= 0) 1961 { 1962 return false; 1963 } 1964 1965 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer)) 1966 { 1967 if (samplerState.magFilter != GL_NEAREST || 1968 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST)) 1969 { 1970 return false; 1971 } 1972 } 1973 1974 if (IsMipmapFiltered(samplerState) && !isMipmapComplete()) 1975 { 1976 return false; 1977 } 1978 1979 return true; 1980} 1981 1982bool Texture3D::isMipmapComplete() const 1983{ 1984 int levelCount = mipLevels(); 1985 1986 for (int level = 0; level < levelCount; level++) 1987 { 1988 if (!isLevelComplete(level)) 1989 { 1990 return false; 1991 } 1992 } 1993 1994 return true; 1995} 1996 1997bool Texture3D::isLevelComplete(int level) const 1998{ 1999 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL); 2000 2001 if (isImmutable()) 2002 { 2003 return true; 2004 } 2005 2006 GLsizei width = getBaseLevelWidth(); 2007 GLsizei height = getBaseLevelHeight(); 2008 GLsizei depth = getBaseLevelDepth(); 2009 2010 if (width <= 0 || height <= 0 || depth <= 0) 2011 { 2012 return false; 2013 } 2014 2015 if (level == 0) 2016 { 2017 return true; 2018 } 2019 2020 rx::Image *levelImage = mImageArray[level]; 2021 2022 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat()) 2023 { 2024 return false; 2025 } 2026 2027 if (levelImage->getWidth() != std::max(1, width >> level)) 2028 { 2029 return false; 2030 } 2031 2032 if (levelImage->getHeight() != std::max(1, height >> level)) 2033 { 2034 return false; 2035 } 2036 2037 if (levelImage->getDepth() != std::max(1, depth >> level)) 2038 { 2039 return false; 2040 } 2041 2042 return true; 2043} 2044 2045FramebufferAttachment *Texture3D::getAttachment(GLint level, GLint layer) 2046{ 2047 FramebufferAttachment *attachment = mRenderbufferProxies.get(level, layer); 2048 if (!attachment) 2049 { 2050 attachment = new FramebufferAttachment(mRenderer, id(), new Texture3DAttachment(this, level, layer)); 2051 mRenderbufferProxies.add(level, 0, attachment); 2052 } 2053 2054 return attachment; 2055} 2056 2057unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer) 2058{ 2059 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0); 2060} 2061 2062bool Texture3D::isValidLevel(int level) const 2063{ 2064 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0); 2065} 2066 2067void Texture3D::initializeStorage(bool renderTarget) 2068{ 2069 // Only initialize the first time this texture is used as a render target or shader resource 2070 if (mTexStorage) 2071 { 2072 return; 2073 } 2074 2075 // do not attempt to create storage for nonexistant data 2076 if (!isLevelComplete(0)) 2077 { 2078 return; 2079 } 2080 2081 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); 2082 2083 setCompleteTexStorage(createCompleteStorage(createRenderTarget)); 2084 ASSERT(mTexStorage); 2085 2086 // flush image data to the storage 2087 updateStorage(); 2088} 2089 2090rx::TextureStorageInterface3D *Texture3D::createCompleteStorage(bool renderTarget) const 2091{ 2092 GLsizei width = getBaseLevelWidth(); 2093 GLsizei height = getBaseLevelHeight(); 2094 GLsizei depth = getBaseLevelDepth(); 2095 2096 ASSERT(width > 0 && height > 0 && depth > 0); 2097 2098 // use existing storage level count, when previously specified by TexStorage*D 2099 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth)); 2100 2101 return new rx::TextureStorageInterface3D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels); 2102} 2103 2104void Texture3D::setCompleteTexStorage(rx::TextureStorageInterface3D *newCompleteTexStorage) 2105{ 2106 SafeDelete(mTexStorage); 2107 mTexStorage = newCompleteTexStorage; 2108 mDirtyImages = true; 2109 2110 // We do not support managed 3D storage, as that is D3D9/ES2-only 2111 ASSERT(!mTexStorage->isManaged()); 2112} 2113 2114void Texture3D::updateStorage() 2115{ 2116 ASSERT(mTexStorage != NULL); 2117 GLint storageLevels = mTexStorage->getLevelCount(); 2118 for (int level = 0; level < storageLevels; level++) 2119 { 2120 if (mImageArray[level]->isDirty() && isLevelComplete(level)) 2121 { 2122 updateStorageLevel(level); 2123 } 2124 } 2125} 2126 2127void Texture3D::updateStorageLevel(int level) 2128{ 2129 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL); 2130 ASSERT(isLevelComplete(level)); 2131 2132 if (mImageArray[level]->isDirty()) 2133 { 2134 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level)); 2135 } 2136} 2137 2138bool Texture3D::ensureRenderTarget() 2139{ 2140 initializeStorage(true); 2141 2142 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0) 2143 { 2144 ASSERT(mTexStorage); 2145 if (!mTexStorage->isRenderTarget()) 2146 { 2147 rx::TextureStorageInterface3D *newRenderTargetStorage = createCompleteStorage(true); 2148 2149 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage)) 2150 { 2151 delete newRenderTargetStorage; 2152 return gl::error(GL_OUT_OF_MEMORY, false); 2153 } 2154 2155 setCompleteTexStorage(newRenderTargetStorage); 2156 } 2157 } 2158 2159 return (mTexStorage && mTexStorage->isRenderTarget()); 2160} 2161 2162rx::RenderTarget *Texture3D::getRenderTarget(GLint level) 2163{ 2164 // ensure the underlying texture is created 2165 if (!ensureRenderTarget()) 2166 { 2167 return NULL; 2168 } 2169 2170 updateStorageLevel(level); 2171 2172 // ensure this is NOT a depth texture 2173 if (isDepth(level)) 2174 { 2175 return NULL; 2176 } 2177 2178 return mTexStorage->getRenderTarget(level); 2179} 2180 2181rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer) 2182{ 2183 // ensure the underlying texture is created 2184 if (!ensureRenderTarget()) 2185 { 2186 return NULL; 2187 } 2188 2189 updateStorage(); 2190 2191 // ensure this is NOT a depth texture 2192 if (isDepth(level)) 2193 { 2194 return NULL; 2195 } 2196 2197 return mTexStorage->getRenderTarget(level, layer); 2198} 2199 2200rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer) 2201{ 2202 // ensure the underlying texture is created 2203 if (!ensureRenderTarget()) 2204 { 2205 return NULL; 2206 } 2207 2208 updateStorageLevel(level); 2209 2210 // ensure this is a depth texture 2211 if (!isDepth(level)) 2212 { 2213 return NULL; 2214 } 2215 2216 return mTexStorage->getRenderTarget(level, layer); 2217} 2218 2219void Texture3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) 2220{ 2221 // If there currently is a corresponding storage texture image, it has these parameters 2222 const int storageWidth = std::max(1, getBaseLevelWidth() >> level); 2223 const int storageHeight = std::max(1, getBaseLevelHeight() >> level); 2224 const int storageDepth = std::max(1, getBaseLevelDepth() >> level); 2225 const GLenum storageFormat = getBaseLevelInternalFormat(); 2226 2227 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false); 2228 2229 if (mTexStorage) 2230 { 2231 const int storageLevels = mTexStorage->getLevelCount(); 2232 2233 if ((level >= storageLevels && storageLevels != 0) || 2234 width != storageWidth || 2235 height != storageHeight || 2236 depth != storageDepth || 2237 internalformat != storageFormat) // Discard mismatched storage 2238 { 2239 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) 2240 { 2241 mImageArray[i]->markDirty(); 2242 } 2243 2244 delete mTexStorage; 2245 mTexStorage = NULL; 2246 mDirtyImages = true; 2247 } 2248 } 2249} 2250 2251void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth) 2252{ 2253 if (isValidLevel(level)) 2254 { 2255 rx::Image *image = mImageArray[level]; 2256 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth)) 2257 { 2258 image->markClean(); 2259 } 2260 } 2261} 2262 2263Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY) 2264{ 2265 mTexStorage = NULL; 2266 2267 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level) 2268 { 2269 mLayerCounts[level] = 0; 2270 mImageArray[level] = NULL; 2271 } 2272} 2273 2274Texture2DArray::~Texture2DArray() 2275{ 2276 delete mTexStorage; 2277 mTexStorage = NULL; 2278 2279 deleteImages(); 2280} 2281 2282void Texture2DArray::deleteImages() 2283{ 2284 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level) 2285 { 2286 for (int layer = 0; layer < mLayerCounts[level]; ++layer) 2287 { 2288 delete mImageArray[level][layer]; 2289 } 2290 delete[] mImageArray[level]; 2291 mImageArray[level] = NULL; 2292 mLayerCounts[level] = 0; 2293 } 2294} 2295 2296GLsizei Texture2DArray::getWidth(GLint level) const 2297{ 2298 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0; 2299} 2300 2301GLsizei Texture2DArray::getHeight(GLint level) const 2302{ 2303 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0; 2304} 2305 2306GLsizei Texture2DArray::getLayers(GLint level) const 2307{ 2308 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0; 2309} 2310 2311GLenum Texture2DArray::getInternalFormat(GLint level) const 2312{ 2313 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE; 2314} 2315 2316GLenum Texture2DArray::getActualFormat(GLint level) const 2317{ 2318 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getActualFormat() : GL_NONE; 2319} 2320 2321bool Texture2DArray::isCompressed(GLint level) const 2322{ 2323 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion()); 2324} 2325 2326bool Texture2DArray::isDepth(GLint level) const 2327{ 2328 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0; 2329} 2330 2331void Texture2DArray::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) 2332{ 2333 GLuint clientVersion = mRenderer->getCurrentClientVersion(); 2334 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat 2335 : GetSizedInternalFormat(format, type, clientVersion); 2336 redefineImage(level, sizedInternalFormat, width, height, depth); 2337 2338 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, clientVersion, width, height, unpack.alignment); 2339 2340 for (int i = 0; i < depth; i++) 2341 { 2342 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL; 2343 Texture::setImage(unpack, type, layerPixels, mImageArray[level][i]); 2344 } 2345} 2346 2347void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) 2348{ 2349 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly 2350 redefineImage(level, format, width, height, depth); 2351 2352 GLuint clientVersion = mRenderer->getCurrentClientVersion(); 2353 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1); 2354 2355 for (int i = 0; i < depth; i++) 2356 { 2357 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL; 2358 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]); 2359 } 2360} 2361 2362void Texture2DArray::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) 2363{ 2364 GLenum internalformat = getInternalFormat(level); 2365 GLuint clientVersion = mRenderer->getCurrentClientVersion(); 2366 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, clientVersion, width, height, unpack.alignment); 2367 2368 for (int i = 0; i < depth; i++) 2369 { 2370 int layer = zoffset + i; 2371 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL; 2372 2373 if (Texture::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack, layerPixels, mImageArray[level][layer])) 2374 { 2375 commitRect(level, xoffset, yoffset, layer, width, height); 2376 } 2377 } 2378} 2379 2380void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) 2381{ 2382 GLuint clientVersion = mRenderer->getCurrentClientVersion(); 2383 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1); 2384 2385 for (int i = 0; i < depth; i++) 2386 { 2387 int layer = zoffset + i; 2388 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL; 2389 2390 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer])) 2391 { 2392 commitRect(level, xoffset, yoffset, layer, width, height); 2393 } 2394 } 2395} 2396 2397void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) 2398{ 2399 deleteImages(); 2400 2401 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) 2402 { 2403 GLsizei levelWidth = std::max(1, width >> level); 2404 GLsizei levelHeight = std::max(1, height >> level); 2405 2406 mLayerCounts[level] = (level < levels ? depth : 0); 2407 2408 if (mLayerCounts[level] > 0) 2409 { 2410 // Create new images for this level 2411 mImageArray[level] = new rx::Image*[mLayerCounts[level]]; 2412 2413 for (int layer = 0; layer < mLayerCounts[level]; layer++) 2414 { 2415 mImageArray[level][layer] = mRenderer->createImage(); 2416 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth, 2417 levelHeight, 1, true); 2418 } 2419 } 2420 } 2421 2422 mImmutable = true; 2423 setCompleteTexStorage(new rx::TextureStorageInterface2DArray(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels)); 2424} 2425 2426void Texture2DArray::generateMipmaps() 2427{ 2428 int baseWidth = getBaseLevelWidth(); 2429 int baseHeight = getBaseLevelHeight(); 2430 int baseDepth = getBaseLevelDepth(); 2431 GLenum baseFormat = getBaseLevelInternalFormat(); 2432 2433 // Purge array levels 1 through q and reset them to represent the generated mipmap levels. 2434 int levelCount = mipLevels(); 2435 for (int level = 1; level < levelCount; level++) 2436 { 2437 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth); 2438 } 2439 2440 if (mTexStorage && mTexStorage->isRenderTarget()) 2441 { 2442 for (int level = 1; level < levelCount; level++) 2443 { 2444 mTexStorage->generateMipmap(level); 2445 2446 for (int layer = 0; layer < mLayerCounts[level]; layer++) 2447 { 2448 mImageArray[level][layer]->markClean(); 2449 } 2450 } 2451 } 2452 else 2453 { 2454 for (int level = 1; level < levelCount; level++) 2455 { 2456 for (int layer = 0; layer < mLayerCounts[level]; layer++) 2457 { 2458 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]); 2459 } 2460 } 2461 } 2462} 2463 2464const rx::Image *Texture2DArray::getBaseLevelImage() const 2465{ 2466 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL); 2467} 2468 2469rx::TextureStorageInterface *Texture2DArray::getBaseLevelStorage() 2470{ 2471 return mTexStorage; 2472} 2473 2474void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) 2475{ 2476 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and 2477 // the current level we're copying to is defined (with appropriate format, width & height) 2478 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0); 2479 2480 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget)) 2481 { 2482 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source); 2483 mDirtyImages = true; 2484 } 2485 else 2486 { 2487 ensureRenderTarget(); 2488 2489 if (isValidLevel(level)) 2490 { 2491 updateStorageLevel(level); 2492 2493 GLuint clientVersion = mRenderer->getCurrentClientVersion(); 2494 2495 gl::Rectangle sourceRect; 2496 sourceRect.x = x; 2497 sourceRect.width = width; 2498 sourceRect.y = y; 2499 sourceRect.height = height; 2500 2501 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0), clientVersion), 2502 xoffset, yoffset, zoffset, mTexStorage, level); 2503 } 2504 } 2505} 2506 2507bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const 2508{ 2509 GLsizei width = getBaseLevelWidth(); 2510 GLsizei height = getBaseLevelHeight(); 2511 GLsizei depth = getLayers(0); 2512 2513 if (width <= 0 || height <= 0 || depth <= 0) 2514 { 2515 return false; 2516 } 2517 2518 if (!IsTextureFilteringSupported(getBaseLevelInternalFormat(), mRenderer)) 2519 { 2520 if (samplerState.magFilter != GL_NEAREST || 2521 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST)) 2522 { 2523 return false; 2524 } 2525 } 2526 2527 if (IsMipmapFiltered(samplerState) && !isMipmapComplete()) 2528 { 2529 return false; 2530 } 2531 2532 return true; 2533} 2534 2535bool Texture2DArray::isMipmapComplete() const 2536{ 2537 int levelCount = mipLevels(); 2538 2539 for (int level = 1; level < levelCount; level++) 2540 { 2541 if (!isLevelComplete(level)) 2542 { 2543 return false; 2544 } 2545 } 2546 2547 return true; 2548} 2549 2550bool Texture2DArray::isLevelComplete(int level) const 2551{ 2552 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray)); 2553 2554 if (isImmutable()) 2555 { 2556 return true; 2557 } 2558 2559 GLsizei width = getBaseLevelWidth(); 2560 GLsizei height = getBaseLevelHeight(); 2561 GLsizei layers = getLayers(0); 2562 2563 if (width <= 0 || height <= 0 || layers <= 0) 2564 { 2565 return false; 2566 } 2567 2568 if (level == 0) 2569 { 2570 return true; 2571 } 2572 2573 if (getInternalFormat(level) != getInternalFormat(0)) 2574 { 2575 return false; 2576 } 2577 2578 if (getWidth(level) != std::max(1, width >> level)) 2579 { 2580 return false; 2581 } 2582 2583 if (getHeight(level) != std::max(1, height >> level)) 2584 { 2585 return false; 2586 } 2587 2588 if (getLayers(level) != layers) 2589 { 2590 return false; 2591 } 2592 2593 return true; 2594} 2595 2596FramebufferAttachment *Texture2DArray::getAttachment(GLint level, GLint layer) 2597{ 2598 FramebufferAttachment *attachment = mRenderbufferProxies.get(level, layer); 2599 if (!attachment) 2600 { 2601 attachment = new FramebufferAttachment(mRenderer, id(), new Texture2DArrayAttachment(this, level, layer)); 2602 mRenderbufferProxies.add(level, 0, attachment); 2603 } 2604 2605 return attachment; 2606} 2607 2608unsigned int Texture2DArray::getRenderTargetSerial(GLint level, GLint layer) 2609{ 2610 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0); 2611} 2612 2613bool Texture2DArray::isValidLevel(int level) const 2614{ 2615 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0); 2616} 2617 2618void Texture2DArray::initializeStorage(bool renderTarget) 2619{ 2620 // Only initialize the first time this texture is used as a render target or shader resource 2621 if (mTexStorage) 2622 { 2623 return; 2624 } 2625 2626 // do not attempt to create storage for nonexistant data 2627 if (!isLevelComplete(0)) 2628 { 2629 return; 2630 } 2631 2632 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); 2633 2634 setCompleteTexStorage(createCompleteStorage(createRenderTarget)); 2635 ASSERT(mTexStorage); 2636 2637 // flush image data to the storage 2638 updateStorage(); 2639} 2640 2641rx::TextureStorageInterface2DArray *Texture2DArray::createCompleteStorage(bool renderTarget) const 2642{ 2643 GLsizei width = getBaseLevelWidth(); 2644 GLsizei height = getBaseLevelHeight(); 2645 GLsizei depth = getLayers(0); 2646 2647 ASSERT(width > 0 && height > 0 && depth > 0); 2648 2649 // use existing storage level count, when previously specified by TexStorage*D 2650 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1)); 2651 2652 return new rx::TextureStorageInterface2DArray(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels); 2653} 2654 2655void Texture2DArray::setCompleteTexStorage(rx::TextureStorageInterface2DArray *newCompleteTexStorage) 2656{ 2657 SafeDelete(mTexStorage); 2658 mTexStorage = newCompleteTexStorage; 2659 mDirtyImages = true; 2660 2661 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only 2662 ASSERT(!mTexStorage->isManaged()); 2663} 2664 2665void Texture2DArray::updateStorage() 2666{ 2667 ASSERT(mTexStorage != NULL); 2668 GLint storageLevels = mTexStorage->getLevelCount(); 2669 for (int level = 0; level < storageLevels; level++) 2670 { 2671 if (isLevelComplete(level)) 2672 { 2673 updateStorageLevel(level); 2674 } 2675 } 2676} 2677 2678void Texture2DArray::updateStorageLevel(int level) 2679{ 2680 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts)); 2681 ASSERT(isLevelComplete(level)); 2682 2683 for (int layer = 0; layer < mLayerCounts[level]; layer++) 2684 { 2685 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL); 2686 if (mImageArray[level][layer]->isDirty()) 2687 { 2688 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level)); 2689 } 2690 } 2691} 2692 2693bool Texture2DArray::ensureRenderTarget() 2694{ 2695 initializeStorage(true); 2696 2697 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0) 2698 { 2699 ASSERT(mTexStorage); 2700 if (!mTexStorage->isRenderTarget()) 2701 { 2702 rx::TextureStorageInterface2DArray *newRenderTargetStorage = createCompleteStorage(true); 2703 2704 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage)) 2705 { 2706 delete newRenderTargetStorage; 2707 return gl::error(GL_OUT_OF_MEMORY, false); 2708 } 2709 2710 setCompleteTexStorage(newRenderTargetStorage); 2711 } 2712 } 2713 2714 return (mTexStorage && mTexStorage->isRenderTarget()); 2715} 2716 2717rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer) 2718{ 2719 // ensure the underlying texture is created 2720 if (!ensureRenderTarget()) 2721 { 2722 return NULL; 2723 } 2724 2725 updateStorageLevel(level); 2726 2727 // ensure this is NOT a depth texture 2728 if (isDepth(level)) 2729 { 2730 return NULL; 2731 } 2732 2733 return mTexStorage->getRenderTarget(level, layer); 2734} 2735 2736rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer) 2737{ 2738 // ensure the underlying texture is created 2739 if (!ensureRenderTarget()) 2740 { 2741 return NULL; 2742 } 2743 2744 updateStorageLevel(level); 2745 2746 // ensure this is a depth texture 2747 if (!isDepth(level)) 2748 { 2749 return NULL; 2750 } 2751 2752 return mTexStorage->getRenderTarget(level, layer); 2753} 2754 2755void Texture2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) 2756{ 2757 // If there currently is a corresponding storage texture image, it has these parameters 2758 const int storageWidth = std::max(1, getBaseLevelWidth() >> level); 2759 const int storageHeight = std::max(1, getBaseLevelHeight() >> level); 2760 const int storageDepth = getLayers(0); 2761 const GLenum storageFormat = getBaseLevelInternalFormat(); 2762 2763 for (int layer = 0; layer < mLayerCounts[level]; layer++) 2764 { 2765 delete mImageArray[level][layer]; 2766 } 2767 delete[] mImageArray[level]; 2768 mImageArray[level] = NULL; 2769 mLayerCounts[level] = depth; 2770 2771 if (depth > 0) 2772 { 2773 mImageArray[level] = new rx::Image*[depth](); 2774 2775 for (int layer = 0; layer < mLayerCounts[level]; layer++) 2776 { 2777 mImageArray[level][layer] = mRenderer->createImage(); 2778 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false); 2779 } 2780 } 2781 2782 if (mTexStorage) 2783 { 2784 const int storageLevels = mTexStorage->getLevelCount(); 2785 2786 if ((level >= storageLevels && storageLevels != 0) || 2787 width != storageWidth || 2788 height != storageHeight || 2789 depth != storageDepth || 2790 internalformat != storageFormat) // Discard mismatched storage 2791 { 2792 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) 2793 { 2794 for (int layer = 0; layer < mLayerCounts[level]; layer++) 2795 { 2796 mImageArray[level][layer]->markDirty(); 2797 } 2798 } 2799 2800 delete mTexStorage; 2801 mTexStorage = NULL; 2802 mDirtyImages = true; 2803 } 2804 } 2805} 2806 2807void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height) 2808{ 2809 if (isValidLevel(level) && layerTarget < getLayers(level)) 2810 { 2811 rx::Image *image = mImageArray[level][layerTarget]; 2812 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, layerTarget, width, height)) 2813 { 2814 image->markClean(); 2815 } 2816 } 2817} 2818 2819} 2820