Home | History | Annotate | Download | only in libGLESv2
      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 "libGLESv2/mathutil.h"
     16 #include "libGLESv2/utilities.h"
     17 #include "libGLESv2/renderer/Blit.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 
     24 namespace gl
     25 {
     26 
     27 Texture::Texture(rx::Renderer *renderer, GLuint id) : RefCountObject(id)
     28 {
     29     mRenderer = renderer;
     30 
     31     mSamplerState.minFilter = GL_NEAREST_MIPMAP_LINEAR;
     32     mSamplerState.magFilter = GL_LINEAR;
     33     mSamplerState.wrapS = GL_REPEAT;
     34     mSamplerState.wrapT = GL_REPEAT;
     35     mSamplerState.maxAnisotropy = 1.0f;
     36     mSamplerState.lodOffset = 0;
     37     mUsage = GL_NONE;
     38 
     39     mDirtyImages = true;
     40 
     41     mImmutable = false;
     42 }
     43 
     44 Texture::~Texture()
     45 {
     46 }
     47 
     48 // Returns true on successful filter state update (valid enum parameter)
     49 bool Texture::setMinFilter(GLenum filter)
     50 {
     51     switch (filter)
     52     {
     53       case GL_NEAREST:
     54       case GL_LINEAR:
     55       case GL_NEAREST_MIPMAP_NEAREST:
     56       case GL_LINEAR_MIPMAP_NEAREST:
     57       case GL_NEAREST_MIPMAP_LINEAR:
     58       case GL_LINEAR_MIPMAP_LINEAR:
     59         mSamplerState.minFilter = filter;
     60         return true;
     61       default:
     62         return false;
     63     }
     64 }
     65 
     66 // Returns true on successful filter state update (valid enum parameter)
     67 bool Texture::setMagFilter(GLenum filter)
     68 {
     69     switch (filter)
     70     {
     71       case GL_NEAREST:
     72       case GL_LINEAR:
     73         mSamplerState.magFilter = filter;
     74         return true;
     75       default:
     76         return false;
     77     }
     78 }
     79 
     80 // Returns true on successful wrap state update (valid enum parameter)
     81 bool Texture::setWrapS(GLenum wrap)
     82 {
     83     switch (wrap)
     84     {
     85       case GL_REPEAT:
     86       case GL_CLAMP_TO_EDGE:
     87       case GL_MIRRORED_REPEAT:
     88         mSamplerState.wrapS = wrap;
     89         return true;
     90       default:
     91         return false;
     92     }
     93 }
     94 
     95 // Returns true on successful wrap state update (valid enum parameter)
     96 bool Texture::setWrapT(GLenum wrap)
     97 {
     98     switch (wrap)
     99     {
    100       case GL_REPEAT:
    101       case GL_CLAMP_TO_EDGE:
    102       case GL_MIRRORED_REPEAT:
    103         mSamplerState.wrapT = wrap;
    104         return true;
    105       default:
    106         return false;
    107     }
    108 }
    109 
    110 // Returns true on successful max anisotropy update (valid anisotropy value)
    111 bool Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy)
    112 {
    113     textureMaxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy);
    114     if (textureMaxAnisotropy < 1.0f)
    115     {
    116         return false;
    117     }
    118 
    119     mSamplerState.maxAnisotropy = textureMaxAnisotropy;
    120 
    121     return true;
    122 }
    123 
    124 // Returns true on successful usage state update (valid enum parameter)
    125 bool Texture::setUsage(GLenum usage)
    126 {
    127     switch (usage)
    128     {
    129       case GL_NONE:
    130       case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
    131         mUsage = usage;
    132         return true;
    133       default:
    134         return false;
    135     }
    136 }
    137 
    138 GLenum Texture::getMinFilter() const
    139 {
    140     return mSamplerState.minFilter;
    141 }
    142 
    143 GLenum Texture::getMagFilter() const
    144 {
    145     return mSamplerState.magFilter;
    146 }
    147 
    148 GLenum Texture::getWrapS() const
    149 {
    150     return mSamplerState.wrapS;
    151 }
    152 
    153 GLenum Texture::getWrapT() const
    154 {
    155     return mSamplerState.wrapT;
    156 }
    157 
    158 float Texture::getMaxAnisotropy() const
    159 {
    160     return mSamplerState.maxAnisotropy;
    161 }
    162 
    163 int Texture::getLodOffset()
    164 {
    165     rx::TextureStorageInterface *texture = getStorage(false);
    166     return texture ? texture->getLodOffset() : 0;
    167 }
    168 
    169 void Texture::getSamplerState(SamplerState *sampler)
    170 {
    171     *sampler = mSamplerState;
    172     sampler->lodOffset = getLodOffset();
    173 }
    174 
    175 GLenum Texture::getUsage() const
    176 {
    177     return mUsage;
    178 }
    179 
    180 bool Texture::isMipmapFiltered() const
    181 {
    182     switch (mSamplerState.minFilter)
    183     {
    184       case GL_NEAREST:
    185       case GL_LINEAR:
    186         return false;
    187       case GL_NEAREST_MIPMAP_NEAREST:
    188       case GL_LINEAR_MIPMAP_NEAREST:
    189       case GL_NEAREST_MIPMAP_LINEAR:
    190       case GL_LINEAR_MIPMAP_LINEAR:
    191         return true;
    192       default: UNREACHABLE();
    193         return false;
    194     }
    195 }
    196 
    197 void Texture::setImage(GLint unpackAlignment, const void *pixels, rx::Image *image)
    198 {
    199     if (pixels != NULL)
    200     {
    201         image->loadData(0, 0, image->getWidth(), image->getHeight(), unpackAlignment, pixels);
    202         mDirtyImages = true;
    203     }
    204 }
    205 
    206 void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
    207 {
    208     if (pixels != NULL)
    209     {
    210         image->loadCompressedData(0, 0, image->getWidth(), image->getHeight(), pixels);
    211         mDirtyImages = true;
    212     }
    213 }
    214 
    215 bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, rx::Image *image)
    216 {
    217     if (pixels != NULL)
    218     {
    219         image->loadData(xoffset, yoffset, width, height, unpackAlignment, pixels);
    220         mDirtyImages = true;
    221     }
    222 
    223     return true;
    224 }
    225 
    226 bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image)
    227 {
    228     if (pixels != NULL)
    229     {
    230         image->loadCompressedData(xoffset, yoffset, width, height, pixels);
    231         mDirtyImages = true;
    232     }
    233 
    234     return true;
    235 }
    236 
    237 rx::TextureStorageInterface *Texture::getNativeTexture()
    238 {
    239     // ensure the underlying texture is created
    240 
    241     rx::TextureStorageInterface *storage = getStorage(false);
    242     if (storage)
    243     {
    244         updateTexture();
    245     }
    246 
    247     return storage;
    248 }
    249 
    250 bool Texture::hasDirtyImages() const
    251 {
    252     return mDirtyImages;
    253 }
    254 
    255 void Texture::resetDirty()
    256 {
    257     mDirtyImages = false;
    258 }
    259 
    260 unsigned int Texture::getTextureSerial()
    261 {
    262     rx::TextureStorageInterface *texture = getStorage(false);
    263     return texture ? texture->getTextureSerial() : 0;
    264 }
    265 
    266 unsigned int Texture::getRenderTargetSerial(GLenum target)
    267 {
    268     rx::TextureStorageInterface *texture = getStorage(true);
    269     return texture ? texture->getRenderTargetSerial(target) : 0;
    270 }
    271 
    272 bool Texture::isImmutable() const
    273 {
    274     return mImmutable;
    275 }
    276 
    277 GLint Texture::creationLevels(GLsizei width, GLsizei height) const
    278 {
    279     if ((isPow2(width) && isPow2(height)) || mRenderer->getNonPower2TextureSupport())
    280     {
    281         return 0;   // Maximum number of levels
    282     }
    283     else
    284     {
    285         // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
    286         return 1;
    287     }
    288 }
    289 
    290 GLint Texture::creationLevels(GLsizei size) const
    291 {
    292     return creationLevels(size, size);
    293 }
    294 
    295 Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id)
    296 {
    297     mTexStorage = NULL;
    298     mSurface = NULL;
    299     mColorbufferProxy = NULL;
    300     mProxyRefs = 0;
    301 
    302     for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
    303     {
    304         mImageArray[i] = renderer->createImage();
    305     }
    306 }
    307 
    308 Texture2D::~Texture2D()
    309 {
    310     mColorbufferProxy = NULL;
    311 
    312     delete mTexStorage;
    313     mTexStorage = NULL;
    314 
    315     if (mSurface)
    316     {
    317         mSurface->setBoundTexture(NULL);
    318         mSurface = NULL;
    319     }
    320 
    321     for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
    322     {
    323         delete mImageArray[i];
    324     }
    325 }
    326 
    327 // We need to maintain a count of references to renderbuffers acting as
    328 // proxies for this texture, so that we do not attempt to use a pointer
    329 // to a renderbuffer proxy which has been deleted.
    330 void Texture2D::addProxyRef(const Renderbuffer *proxy)
    331 {
    332     mProxyRefs++;
    333 }
    334 
    335 void Texture2D::releaseProxy(const Renderbuffer *proxy)
    336 {
    337     if (mProxyRefs > 0)
    338         mProxyRefs--;
    339 
    340     if (mProxyRefs == 0)
    341         mColorbufferProxy = NULL;
    342 }
    343 
    344 GLenum Texture2D::getTarget() const
    345 {
    346     return GL_TEXTURE_2D;
    347 }
    348 
    349 GLsizei Texture2D::getWidth(GLint level) const
    350 {
    351     if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
    352         return mImageArray[level]->getWidth();
    353     else
    354         return 0;
    355 }
    356 
    357 GLsizei Texture2D::getHeight(GLint level) const
    358 {
    359     if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
    360         return mImageArray[level]->getHeight();
    361     else
    362         return 0;
    363 }
    364 
    365 GLenum Texture2D::getInternalFormat(GLint level) const
    366 {
    367     if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
    368         return mImageArray[level]->getInternalFormat();
    369     else
    370         return GL_NONE;
    371 }
    372 
    373 GLenum Texture2D::getActualFormat(GLint level) const
    374 {
    375     if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
    376         return mImageArray[level]->getActualFormat();
    377     else
    378         return D3DFMT_UNKNOWN;
    379 }
    380 
    381 void Texture2D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height)
    382 {
    383     releaseTexImage();
    384 
    385     // If there currently is a corresponding storage texture image, it has these parameters
    386     const int storageWidth = std::max(1, mImageArray[0]->getWidth() >> level);
    387     const int storageHeight = std::max(1, mImageArray[0]->getHeight() >> level);
    388     const int storageFormat = mImageArray[0]->getInternalFormat();
    389 
    390     mImageArray[level]->redefine(mRenderer, internalformat, width, height, false);
    391 
    392     if (mTexStorage)
    393     {
    394         const int storageLevels = mTexStorage->levelCount();
    395 
    396         if ((level >= storageLevels && storageLevels != 0) ||
    397             width != storageWidth ||
    398             height != storageHeight ||
    399             internalformat != storageFormat)   // Discard mismatched storage
    400         {
    401             for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
    402             {
    403                 mImageArray[i]->markDirty();
    404             }
    405 
    406             delete mTexStorage;
    407             mTexStorage = NULL;
    408             mDirtyImages = true;
    409         }
    410     }
    411 }
    412 
    413 void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
    414 {
    415     GLint internalformat = ConvertSizedInternalFormat(format, type);
    416     redefineImage(level, internalformat, width, height);
    417 
    418     Texture::setImage(unpackAlignment, pixels, mImageArray[level]);
    419 }
    420 
    421 void Texture2D::bindTexImage(egl::Surface *surface)
    422 {
    423     releaseTexImage();
    424 
    425     GLint internalformat = surface->getFormat();
    426 
    427     mImageArray[0]->redefine(mRenderer, internalformat, surface->getWidth(), surface->getHeight(), true);
    428 
    429     delete mTexStorage;
    430     mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
    431 
    432     mDirtyImages = true;
    433     mSurface = surface;
    434     mSurface->setBoundTexture(this);
    435 }
    436 
    437 void Texture2D::releaseTexImage()
    438 {
    439     if (mSurface)
    440     {
    441         mSurface->setBoundTexture(NULL);
    442         mSurface = NULL;
    443 
    444         if (mTexStorage)
    445         {
    446             delete mTexStorage;
    447             mTexStorage = NULL;
    448         }
    449 
    450         for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
    451         {
    452             mImageArray[i]->redefine(mRenderer, GL_NONE, 0, 0, true);
    453         }
    454     }
    455 }
    456 
    457 void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
    458 {
    459     // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
    460     redefineImage(level, format, width, height);
    461 
    462     Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
    463 }
    464 
    465 void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
    466 {
    467     if (level < levelCount())
    468     {
    469         rx::Image *image = mImageArray[level];
    470         if (image->updateSurface(mTexStorage, level, xoffset, yoffset, width, height))
    471         {
    472             image->markClean();
    473         }
    474     }
    475 }
    476 
    477 void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
    478 {
    479     if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, mImageArray[level]))
    480     {
    481         commitRect(level, xoffset, yoffset, width, height);
    482     }
    483 }
    484 
    485 void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
    486 {
    487     if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, mImageArray[level]))
    488     {
    489         commitRect(level, xoffset, yoffset, width, height);
    490     }
    491 }
    492 
    493 void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
    494 {
    495     GLint internalformat = ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE);
    496     redefineImage(level, internalformat, width, height);
    497 
    498     if (!mImageArray[level]->isRenderableFormat())
    499     {
    500         mImageArray[level]->copy(0, 0, x, y, width, height, source);
    501         mDirtyImages = true;
    502     }
    503     else
    504     {
    505         if (!mTexStorage || !mTexStorage->isRenderTarget())
    506         {
    507             convertToRenderTarget();
    508         }
    509 
    510         mImageArray[level]->markClean();
    511 
    512         if (width != 0 && height != 0 && level < levelCount())
    513         {
    514             gl::Rectangle sourceRect;
    515             sourceRect.x = x;
    516             sourceRect.width = width;
    517             sourceRect.y = y;
    518             sourceRect.height = height;
    519 
    520             mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
    521         }
    522     }
    523 }
    524 
    525 void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
    526 {
    527     if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight())
    528     {
    529         return gl::error(GL_INVALID_VALUE);
    530     }
    531 
    532     if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
    533     {
    534         mImageArray[level]->copy(xoffset, yoffset, x, y, width, height, source);
    535         mDirtyImages = true;
    536     }
    537     else
    538     {
    539         if (!mTexStorage || !mTexStorage->isRenderTarget())
    540         {
    541             convertToRenderTarget();
    542         }
    543 
    544         updateTexture();
    545 
    546         if (level < levelCount())
    547         {
    548             gl::Rectangle sourceRect;
    549             sourceRect.x = x;
    550             sourceRect.width = width;
    551             sourceRect.y = y;
    552             sourceRect.height = height;
    553 
    554             mRenderer->copyImage(source, sourceRect,
    555                                  gl::ExtractFormat(mImageArray[0]->getInternalFormat()),
    556                                  xoffset, yoffset, mTexStorage, level);
    557         }
    558     }
    559 }
    560 
    561 void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
    562 {
    563     delete mTexStorage;
    564     mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
    565     mImmutable = true;
    566 
    567     for (int level = 0; level < levels; level++)
    568     {
    569         mImageArray[level]->redefine(mRenderer, internalformat, width, height, true);
    570         width = std::max(1, width >> 1);
    571         height = std::max(1, height >> 1);
    572     }
    573 
    574     for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
    575     {
    576         mImageArray[level]->redefine(mRenderer, GL_NONE, 0, 0, true);
    577     }
    578 
    579     if (mTexStorage->isManaged())
    580     {
    581         int levels = levelCount();
    582 
    583         for (int level = 0; level < levels; level++)
    584         {
    585             mImageArray[level]->setManagedSurface(mTexStorage, level);
    586         }
    587     }
    588 }
    589 
    590 // Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
    591 bool Texture2D::isSamplerComplete() const
    592 {
    593     GLsizei width = mImageArray[0]->getWidth();
    594     GLsizei height = mImageArray[0]->getHeight();
    595 
    596     if (width <= 0 || height <= 0)
    597     {
    598         return false;
    599     }
    600 
    601     bool mipmapping = isMipmapFiltered();
    602     bool filtering, renderable;
    603 
    604     if ((IsFloat32Format(getInternalFormat(0)) && !mRenderer->getFloat32TextureSupport(&filtering, &renderable)) ||
    605         (IsFloat16Format(getInternalFormat(0)) && !mRenderer->getFloat16TextureSupport(&filtering, &renderable)))
    606     {
    607         if (mSamplerState.magFilter != GL_NEAREST ||
    608             (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
    609         {
    610             return false;
    611         }
    612     }
    613 
    614     bool npotSupport = mRenderer->getNonPower2TextureSupport();
    615 
    616     if (!npotSupport)
    617     {
    618         if ((mSamplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
    619             (mSamplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
    620         {
    621             return false;
    622         }
    623     }
    624 
    625     if (mipmapping)
    626     {
    627         if (!npotSupport)
    628         {
    629             if (!isPow2(width) || !isPow2(height))
    630             {
    631                 return false;
    632             }
    633         }
    634 
    635         if (!isMipmapComplete())
    636         {
    637             return false;
    638         }
    639     }
    640 
    641     return true;
    642 }
    643 
    644 // Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
    645 bool Texture2D::isMipmapComplete() const
    646 {
    647     if (isImmutable())
    648     {
    649         return true;
    650     }
    651 
    652     GLsizei width = mImageArray[0]->getWidth();
    653     GLsizei height = mImageArray[0]->getHeight();
    654 
    655     if (width <= 0 || height <= 0)
    656     {
    657         return false;
    658     }
    659 
    660     int q = log2(std::max(width, height));
    661 
    662     for (int level = 1; level <= q; level++)
    663     {
    664         if (mImageArray[level]->getInternalFormat() != mImageArray[0]->getInternalFormat())
    665         {
    666             return false;
    667         }
    668 
    669         if (mImageArray[level]->getWidth() != std::max(1, width >> level))
    670         {
    671             return false;
    672         }
    673 
    674         if (mImageArray[level]->getHeight() != std::max(1, height >> level))
    675         {
    676             return false;
    677         }
    678     }
    679 
    680     return true;
    681 }
    682 
    683 bool Texture2D::isCompressed(GLint level) const
    684 {
    685     return IsCompressed(getInternalFormat(level));
    686 }
    687 
    688 bool Texture2D::isDepth(GLint level) const
    689 {
    690     return IsDepthTexture(getInternalFormat(level));
    691 }
    692 
    693 // Constructs a native texture resource from the texture images
    694 void Texture2D::createTexture()
    695 {
    696     GLsizei width = mImageArray[0]->getWidth();
    697     GLsizei height = mImageArray[0]->getHeight();
    698 
    699     if (!(width > 0 && height > 0))
    700         return; // do not attempt to create native textures for nonexistant data
    701 
    702     GLint levels = creationLevels(width, height);
    703     GLenum internalformat = mImageArray[0]->getInternalFormat();
    704 
    705     delete mTexStorage;
    706     mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
    707 
    708     if (mTexStorage->isManaged())
    709     {
    710         int levels = levelCount();
    711 
    712         for (int level = 0; level < levels; level++)
    713         {
    714             mImageArray[level]->setManagedSurface(mTexStorage, level);
    715         }
    716     }
    717 
    718     mDirtyImages = true;
    719 }
    720 
    721 void Texture2D::updateTexture()
    722 {
    723     bool mipmapping = (isMipmapFiltered() && isMipmapComplete());
    724 
    725     int levels = (mipmapping ? levelCount() : 1);
    726 
    727     for (int level = 0; level < levels; level++)
    728     {
    729         rx::Image *image = mImageArray[level];
    730 
    731         if (image->isDirty())
    732         {
    733             commitRect(level, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight());
    734         }
    735     }
    736 }
    737 
    738 void Texture2D::convertToRenderTarget()
    739 {
    740     rx::TextureStorageInterface2D *newTexStorage = NULL;
    741 
    742     if (mImageArray[0]->getWidth() != 0 && mImageArray[0]->getHeight() != 0)
    743     {
    744         GLsizei width = mImageArray[0]->getWidth();
    745         GLsizei height = mImageArray[0]->getHeight();
    746         GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
    747         GLenum internalformat = mImageArray[0]->getInternalFormat();
    748 
    749         newTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, width, height);
    750 
    751         if (mTexStorage != NULL)
    752         {
    753             if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
    754             {
    755                 delete newTexStorage;
    756                 return gl::error(GL_OUT_OF_MEMORY);
    757             }
    758         }
    759     }
    760 
    761     delete mTexStorage;
    762     mTexStorage = newTexStorage;
    763 
    764     mDirtyImages = true;
    765 }
    766 
    767 void Texture2D::generateMipmaps()
    768 {
    769     if (!mRenderer->getNonPower2TextureSupport())
    770     {
    771         if (!isPow2(mImageArray[0]->getWidth()) || !isPow2(mImageArray[0]->getHeight()))
    772         {
    773             return gl::error(GL_INVALID_OPERATION);
    774         }
    775     }
    776 
    777     // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
    778     unsigned int q = log2(std::max(mImageArray[0]->getWidth(), mImageArray[0]->getHeight()));
    779     for (unsigned int i = 1; i <= q; i++)
    780     {
    781         redefineImage(i, mImageArray[0]->getInternalFormat(),
    782                       std::max(mImageArray[0]->getWidth() >> i, 1),
    783                       std::max(mImageArray[0]->getHeight() >> i, 1));
    784     }
    785 
    786     if (mTexStorage && mTexStorage->isRenderTarget())
    787     {
    788         for (unsigned int i = 1; i <= q; i++)
    789         {
    790             mTexStorage->generateMipmap(i);
    791 
    792             mImageArray[i]->markClean();
    793         }
    794     }
    795     else
    796     {
    797         for (unsigned int i = 1; i <= q; i++)
    798         {
    799             mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
    800         }
    801     }
    802 }
    803 
    804 Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
    805 {
    806     if (target != GL_TEXTURE_2D)
    807     {
    808         return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
    809     }
    810 
    811     if (mColorbufferProxy == NULL)
    812     {
    813         mColorbufferProxy = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, target));
    814     }
    815 
    816     return mColorbufferProxy;
    817 }
    818 
    819 rx::RenderTarget *Texture2D::getRenderTarget(GLenum target)
    820 {
    821     ASSERT(target == GL_TEXTURE_2D);
    822 
    823     // ensure the underlying texture is created
    824     if (getStorage(true) == NULL)
    825     {
    826         return NULL;
    827     }
    828 
    829     updateTexture();
    830 
    831     // ensure this is NOT a depth texture
    832     if (isDepth(0))
    833     {
    834         return NULL;
    835     }
    836 
    837     return mTexStorage->getRenderTarget();
    838 }
    839 
    840 rx::RenderTarget *Texture2D::getDepthStencil(GLenum target)
    841 {
    842     ASSERT(target == GL_TEXTURE_2D);
    843 
    844     // ensure the underlying texture is created
    845     if (getStorage(true) == NULL)
    846     {
    847         return NULL;
    848     }
    849 
    850     updateTexture();
    851 
    852     // ensure this is actually a depth texture
    853     if (!isDepth(0))
    854     {
    855         return NULL;
    856     }
    857     return mTexStorage->getRenderTarget();
    858 }
    859 
    860 int Texture2D::levelCount()
    861 {
    862     return mTexStorage ? mTexStorage->levelCount() : 0;
    863 }
    864 
    865 rx::TextureStorageInterface *Texture2D::getStorage(bool renderTarget)
    866 {
    867     if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
    868     {
    869         if (renderTarget)
    870         {
    871             convertToRenderTarget();
    872         }
    873         else
    874         {
    875             createTexture();
    876         }
    877     }
    878 
    879     return mTexStorage;
    880 }
    881 
    882 TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id)
    883 {
    884     mTexStorage = NULL;
    885     for (int i = 0; i < 6; i++)
    886     {
    887         mFaceProxies[i] = NULL;
    888         mFaceProxyRefs[i] = 0;
    889 
    890         for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
    891         {
    892             mImageArray[i][j] = renderer->createImage();
    893         }
    894     }
    895 }
    896 
    897 TextureCubeMap::~TextureCubeMap()
    898 {
    899     for (int i = 0; i < 6; i++)
    900     {
    901         mFaceProxies[i] = NULL;
    902 
    903         for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
    904         {
    905             delete mImageArray[i][j];
    906         }
    907     }
    908 
    909     delete mTexStorage;
    910     mTexStorage = NULL;
    911 }
    912 
    913 // We need to maintain a count of references to renderbuffers acting as
    914 // proxies for this texture, so that the texture is not deleted while
    915 // proxy references still exist. If the reference count drops to zero,
    916 // we set our proxy pointer NULL, so that a new attempt at referencing
    917 // will cause recreation.
    918 void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
    919 {
    920     for (int i = 0; i < 6; i++)
    921     {
    922         if (mFaceProxies[i] == proxy)
    923             mFaceProxyRefs[i]++;
    924     }
    925 }
    926 
    927 void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
    928 {
    929     for (int i = 0; i < 6; i++)
    930     {
    931         if (mFaceProxies[i] == proxy)
    932         {
    933             if (mFaceProxyRefs[i] > 0)
    934                 mFaceProxyRefs[i]--;
    935 
    936             if (mFaceProxyRefs[i] == 0)
    937                 mFaceProxies[i] = NULL;
    938         }
    939     }
    940 }
    941 
    942 GLenum TextureCubeMap::getTarget() const
    943 {
    944     return GL_TEXTURE_CUBE_MAP;
    945 }
    946 
    947 GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
    948 {
    949     if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
    950         return mImageArray[faceIndex(target)][level]->getWidth();
    951     else
    952         return 0;
    953 }
    954 
    955 GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
    956 {
    957     if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
    958         return mImageArray[faceIndex(target)][level]->getHeight();
    959     else
    960         return 0;
    961 }
    962 
    963 GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
    964 {
    965     if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
    966         return mImageArray[faceIndex(target)][level]->getInternalFormat();
    967     else
    968         return GL_NONE;
    969 }
    970 
    971 GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
    972 {
    973     if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
    974         return mImageArray[faceIndex(target)][level]->getActualFormat();
    975     else
    976         return D3DFMT_UNKNOWN;
    977 }
    978 
    979 void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
    980 {
    981     setImage(0, level, width, height, format, type, unpackAlignment, pixels);
    982 }
    983 
    984 void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
    985 {
    986     setImage(1, level, width, height, format, type, unpackAlignment, pixels);
    987 }
    988 
    989 void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
    990 {
    991     setImage(2, level, width, height, format, type, unpackAlignment, pixels);
    992 }
    993 
    994 void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
    995 {
    996     setImage(3, level, width, height, format, type, unpackAlignment, pixels);
    997 }
    998 
    999 void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
   1000 {
   1001     setImage(4, level, width, height, format, type, unpackAlignment, pixels);
   1002 }
   1003 
   1004 void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
   1005 {
   1006     setImage(5, level, width, height, format, type, unpackAlignment, pixels);
   1007 }
   1008 
   1009 void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
   1010 {
   1011     // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
   1012     redefineImage(faceIndex(face), level, format, width, height);
   1013 
   1014     Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex(face)][level]);
   1015 }
   1016 
   1017 void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
   1018 {
   1019     if (level < levelCount())
   1020     {
   1021         rx::Image *image = mImageArray[face][level];
   1022         if (image->updateSurface(mTexStorage, face, level, xoffset, yoffset, width, height))
   1023             image->markClean();
   1024     }
   1025 }
   1026 
   1027 void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
   1028 {
   1029     if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, mImageArray[faceIndex(target)][level]))
   1030     {
   1031         commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
   1032     }
   1033 }
   1034 
   1035 void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
   1036 {
   1037     if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, mImageArray[faceIndex(target)][level]))
   1038     {
   1039         commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
   1040     }
   1041 }
   1042 
   1043 // Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
   1044 bool TextureCubeMap::isSamplerComplete() const
   1045 {
   1046     int size = mImageArray[0][0]->getWidth();
   1047 
   1048     bool mipmapping = isMipmapFiltered();
   1049     bool filtering, renderable;
   1050 
   1051     if ((gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)) == GL_FLOAT && !mRenderer->getFloat32TextureSupport(&filtering, &renderable)) ||
   1052         (gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0) == GL_HALF_FLOAT_OES) && !mRenderer->getFloat16TextureSupport(&filtering, &renderable)))
   1053     {
   1054         if (mSamplerState.magFilter != GL_NEAREST ||
   1055             (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
   1056         {
   1057             return false;
   1058         }
   1059     }
   1060 
   1061     if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
   1062     {
   1063         if (mSamplerState.wrapS != GL_CLAMP_TO_EDGE || mSamplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
   1064         {
   1065             return false;
   1066         }
   1067     }
   1068 
   1069     if (!mipmapping)
   1070     {
   1071         if (!isCubeComplete())
   1072         {
   1073             return false;
   1074         }
   1075     }
   1076     else
   1077     {
   1078         if (!isMipmapCubeComplete())   // Also tests for isCubeComplete()
   1079         {
   1080             return false;
   1081         }
   1082     }
   1083 
   1084     return true;
   1085 }
   1086 
   1087 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
   1088 bool TextureCubeMap::isCubeComplete() const
   1089 {
   1090     if (mImageArray[0][0]->getWidth() <= 0 || mImageArray[0][0]->getHeight() != mImageArray[0][0]->getWidth())
   1091     {
   1092         return false;
   1093     }
   1094 
   1095     for (unsigned int face = 1; face < 6; face++)
   1096     {
   1097         if (mImageArray[face][0]->getWidth() != mImageArray[0][0]->getWidth() ||
   1098             mImageArray[face][0]->getWidth() != mImageArray[0][0]->getHeight() ||
   1099             mImageArray[face][0]->getInternalFormat() != mImageArray[0][0]->getInternalFormat())
   1100         {
   1101             return false;
   1102         }
   1103     }
   1104 
   1105     return true;
   1106 }
   1107 
   1108 bool TextureCubeMap::isMipmapCubeComplete() const
   1109 {
   1110     if (isImmutable())
   1111     {
   1112         return true;
   1113     }
   1114 
   1115     if (!isCubeComplete())
   1116     {
   1117         return false;
   1118     }
   1119 
   1120     GLsizei size = mImageArray[0][0]->getWidth();
   1121 
   1122     int q = log2(size);
   1123 
   1124     for (int face = 0; face < 6; face++)
   1125     {
   1126         for (int level = 1; level <= q; level++)
   1127         {
   1128             if (mImageArray[face][level]->getInternalFormat() != mImageArray[0][0]->getInternalFormat())
   1129             {
   1130                 return false;
   1131             }
   1132 
   1133             if (mImageArray[face][level]->getWidth() != std::max(1, size >> level))
   1134             {
   1135                 return false;
   1136             }
   1137         }
   1138     }
   1139 
   1140     return true;
   1141 }
   1142 
   1143 bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
   1144 {
   1145     return IsCompressed(getInternalFormat(target, level));
   1146 }
   1147 
   1148 // Constructs a native texture resource from the texture images, or returns an existing one
   1149 void TextureCubeMap::createTexture()
   1150 {
   1151     GLsizei size = mImageArray[0][0]->getWidth();
   1152 
   1153     if (!(size > 0))
   1154         return; // do not attempt to create native textures for nonexistant data
   1155 
   1156     GLint levels = creationLevels(size);
   1157     GLenum internalformat = mImageArray[0][0]->getInternalFormat();
   1158 
   1159     delete mTexStorage;
   1160     mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
   1161 
   1162     if (mTexStorage->isManaged())
   1163     {
   1164         int levels = levelCount();
   1165 
   1166         for (int face = 0; face < 6; face++)
   1167         {
   1168             for (int level = 0; level < levels; level++)
   1169             {
   1170                 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
   1171             }
   1172         }
   1173     }
   1174 
   1175     mDirtyImages = true;
   1176 }
   1177 
   1178 void TextureCubeMap::updateTexture()
   1179 {
   1180     bool mipmapping = isMipmapFiltered() && isMipmapCubeComplete();
   1181 
   1182     for (int face = 0; face < 6; face++)
   1183     {
   1184         int levels = (mipmapping ? levelCount() : 1);
   1185 
   1186         for (int level = 0; level < levels; level++)
   1187         {
   1188             rx::Image *image = mImageArray[face][level];
   1189 
   1190             if (image->isDirty())
   1191             {
   1192                 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
   1193             }
   1194         }
   1195     }
   1196 }
   1197 
   1198 void TextureCubeMap::convertToRenderTarget()
   1199 {
   1200     rx::TextureStorageInterfaceCube *newTexStorage = NULL;
   1201 
   1202     if (mImageArray[0][0]->getWidth() != 0)
   1203     {
   1204         GLsizei size = mImageArray[0][0]->getWidth();
   1205         GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(size);
   1206         GLenum internalformat = mImageArray[0][0]->getInternalFormat();
   1207 
   1208         newTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, size);
   1209 
   1210         if (mTexStorage != NULL)
   1211         {
   1212             if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
   1213             {
   1214                 delete newTexStorage;
   1215                 return gl::error(GL_OUT_OF_MEMORY);
   1216             }
   1217         }
   1218     }
   1219 
   1220     delete mTexStorage;
   1221     mTexStorage = newTexStorage;
   1222 
   1223     mDirtyImages = true;
   1224 }
   1225 
   1226 void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
   1227 {
   1228     GLint internalformat = ConvertSizedInternalFormat(format, type);
   1229     redefineImage(faceIndex, level, internalformat, width, height);
   1230 
   1231     Texture::setImage(unpackAlignment, pixels, mImageArray[faceIndex][level]);
   1232 }
   1233 
   1234 unsigned int TextureCubeMap::faceIndex(GLenum face)
   1235 {
   1236     META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
   1237     META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
   1238     META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
   1239     META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
   1240     META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
   1241 
   1242     return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
   1243 }
   1244 
   1245 void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height)
   1246 {
   1247     // If there currently is a corresponding storage texture image, it has these parameters
   1248     const int storageWidth = std::max(1, mImageArray[0][0]->getWidth() >> level);
   1249     const int storageHeight = std::max(1, mImageArray[0][0]->getHeight() >> level);
   1250     const int storageFormat = mImageArray[0][0]->getInternalFormat();
   1251 
   1252     mImageArray[face][level]->redefine(mRenderer, internalformat, width, height, false);
   1253 
   1254     if (mTexStorage)
   1255     {
   1256         const int storageLevels = mTexStorage->levelCount();
   1257 
   1258         if ((level >= storageLevels && storageLevels != 0) ||
   1259             width != storageWidth ||
   1260             height != storageHeight ||
   1261             internalformat != storageFormat)   // Discard mismatched storage
   1262         {
   1263             for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
   1264             {
   1265                 for (int f = 0; f < 6; f++)
   1266                 {
   1267                     mImageArray[f][i]->markDirty();
   1268                 }
   1269             }
   1270 
   1271             delete mTexStorage;
   1272             mTexStorage = NULL;
   1273 
   1274             mDirtyImages = true;
   1275         }
   1276     }
   1277 }
   1278 
   1279 void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
   1280 {
   1281     unsigned int faceindex = faceIndex(target);
   1282     GLint internalformat = gl::ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE);
   1283     redefineImage(faceindex, level, internalformat, width, height);
   1284 
   1285     if (!mImageArray[faceindex][level]->isRenderableFormat())
   1286     {
   1287         mImageArray[faceindex][level]->copy(0, 0, x, y, width, height, source);
   1288         mDirtyImages = true;
   1289     }
   1290     else
   1291     {
   1292         if (!mTexStorage || !mTexStorage->isRenderTarget())
   1293         {
   1294             convertToRenderTarget();
   1295         }
   1296 
   1297         mImageArray[faceindex][level]->markClean();
   1298 
   1299         ASSERT(width == height);
   1300 
   1301         if (width > 0 && level < levelCount())
   1302         {
   1303             gl::Rectangle sourceRect;
   1304             sourceRect.x = x;
   1305             sourceRect.width = width;
   1306             sourceRect.y = y;
   1307             sourceRect.height = height;
   1308 
   1309             mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
   1310         }
   1311     }
   1312 }
   1313 
   1314 void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
   1315 {
   1316     GLsizei size = mImageArray[faceIndex(target)][level]->getWidth();
   1317 
   1318     if (xoffset + width > size || yoffset + height > size)
   1319     {
   1320         return gl::error(GL_INVALID_VALUE);
   1321     }
   1322 
   1323     unsigned int faceindex = faceIndex(target);
   1324 
   1325     if (!mImageArray[faceindex][level]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
   1326     {
   1327         mImageArray[faceindex][level]->copy(0, 0, x, y, width, height, source);
   1328         mDirtyImages = true;
   1329     }
   1330     else
   1331     {
   1332         if (!mTexStorage || !mTexStorage->isRenderTarget())
   1333         {
   1334             convertToRenderTarget();
   1335         }
   1336 
   1337         updateTexture();
   1338 
   1339         if (level < levelCount())
   1340         {
   1341             gl::Rectangle sourceRect;
   1342             sourceRect.x = x;
   1343             sourceRect.width = width;
   1344             sourceRect.y = y;
   1345             sourceRect.height = height;
   1346 
   1347             mRenderer->copyImage(source, sourceRect, gl::ExtractFormat(mImageArray[0][0]->getInternalFormat()),
   1348                                  xoffset, yoffset, mTexStorage, target, level);
   1349         }
   1350     }
   1351 }
   1352 
   1353 void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
   1354 {
   1355     delete mTexStorage;
   1356     mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
   1357     mImmutable = true;
   1358 
   1359     for (int level = 0; level < levels; level++)
   1360     {
   1361         GLsizei mipSize = std::max(1, size >> level);
   1362         for (int face = 0; face < 6; face++)
   1363         {
   1364             mImageArray[face][level]->redefine(mRenderer, internalformat, mipSize, mipSize, true);
   1365         }
   1366     }
   1367 
   1368     for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
   1369     {
   1370         for (int face = 0; face < 6; face++)
   1371         {
   1372             mImageArray[face][level]->redefine(mRenderer, GL_NONE, 0, 0, true);
   1373         }
   1374     }
   1375 
   1376     if (mTexStorage->isManaged())
   1377     {
   1378         int levels = levelCount();
   1379 
   1380         for (int face = 0; face < 6; face++)
   1381         {
   1382             for (int level = 0; level < levels; level++)
   1383             {
   1384                 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
   1385             }
   1386         }
   1387     }
   1388 }
   1389 
   1390 void TextureCubeMap::generateMipmaps()
   1391 {
   1392     if (!isCubeComplete())
   1393     {
   1394         return gl::error(GL_INVALID_OPERATION);
   1395     }
   1396 
   1397     if (!mRenderer->getNonPower2TextureSupport())
   1398     {
   1399         if (!isPow2(mImageArray[0][0]->getWidth()))
   1400         {
   1401             return gl::error(GL_INVALID_OPERATION);
   1402         }
   1403     }
   1404 
   1405     // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
   1406     unsigned int q = log2(mImageArray[0][0]->getWidth());
   1407     for (unsigned int f = 0; f < 6; f++)
   1408     {
   1409         for (unsigned int i = 1; i <= q; i++)
   1410         {
   1411             redefineImage(f, i, mImageArray[f][0]->getInternalFormat(),
   1412                           std::max(mImageArray[f][0]->getWidth() >> i, 1),
   1413                           std::max(mImageArray[f][0]->getWidth() >> i, 1));
   1414         }
   1415     }
   1416 
   1417     if (mTexStorage && mTexStorage->isRenderTarget())
   1418     {
   1419         for (unsigned int f = 0; f < 6; f++)
   1420         {
   1421             for (unsigned int i = 1; i <= q; i++)
   1422             {
   1423                 mTexStorage->generateMipmap(f, i);
   1424 
   1425                 mImageArray[f][i]->markClean();
   1426             }
   1427         }
   1428     }
   1429     else
   1430     {
   1431         for (unsigned int f = 0; f < 6; f++)
   1432         {
   1433             for (unsigned int i = 1; i <= q; i++)
   1434             {
   1435                 mRenderer->generateMipmap(mImageArray[f][i], mImageArray[f][i - 1]);
   1436             }
   1437         }
   1438     }
   1439 }
   1440 
   1441 Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
   1442 {
   1443     if (!IsCubemapTextureTarget(target))
   1444     {
   1445         return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
   1446     }
   1447 
   1448     unsigned int face = faceIndex(target);
   1449 
   1450     if (mFaceProxies[face] == NULL)
   1451     {
   1452         mFaceProxies[face] = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target));
   1453     }
   1454 
   1455     return mFaceProxies[face];
   1456 }
   1457 
   1458 rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target)
   1459 {
   1460     ASSERT(IsCubemapTextureTarget(target));
   1461 
   1462     // ensure the underlying texture is created
   1463     if (getStorage(true) == NULL)
   1464     {
   1465         return NULL;
   1466     }
   1467 
   1468     updateTexture();
   1469 
   1470     return mTexStorage->getRenderTarget(target);
   1471 }
   1472 
   1473 int TextureCubeMap::levelCount()
   1474 {
   1475     return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0;
   1476 }
   1477 
   1478 rx::TextureStorageInterface *TextureCubeMap::getStorage(bool renderTarget)
   1479 {
   1480     if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
   1481     {
   1482         if (renderTarget)
   1483         {
   1484             convertToRenderTarget();
   1485         }
   1486         else
   1487         {
   1488             createTexture();
   1489         }
   1490     }
   1491 
   1492     return mTexStorage;
   1493 }
   1494 
   1495 }
   1496