Home | History | Annotate | Download | only in d3d
      1 //
      2 // Copyright 2014 The ANGLE Project Authors. All rights reserved.
      3 // Use of this source code is governed by a BSD-style license that can be
      4 // found in the LICENSE file.
      5 //
      6 
      7 // TextureD3D.cpp: Implementations of the Texture interfaces shared betweeen the D3D backends.
      8 
      9 #include "libGLESv2/renderer/d3d/TextureD3D.h"
     10 #include "libGLESv2/renderer/d3d/TextureStorage.h"
     11 #include "libGLESv2/renderer/d3d/ImageD3D.h"
     12 #include "libGLESv2/Buffer.h"
     13 #include "libGLESv2/Framebuffer.h"
     14 #include "libGLESv2/Texture.h"
     15 #include "libGLESv2/main.h"
     16 #include "libGLESv2/formatutils.h"
     17 #include "libGLESv2/renderer/BufferImpl.h"
     18 #include "libGLESv2/renderer/RenderTarget.h"
     19 #include "libGLESv2/renderer/Renderer.h"
     20 
     21 #include "libEGL/Surface.h"
     22 
     23 #include "common/mathutil.h"
     24 #include "common/utilities.h"
     25 
     26 namespace rx
     27 {
     28 
     29 bool IsRenderTargetUsage(GLenum usage)
     30 {
     31     return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
     32 }
     33 
     34 TextureD3D::TextureD3D(Renderer *renderer)
     35     : mRenderer(renderer),
     36       mUsage(GL_NONE),
     37       mDirtyImages(true),
     38       mImmutable(false)
     39 {
     40 }
     41 
     42 TextureD3D::~TextureD3D()
     43 {
     44 }
     45 
     46 TextureD3D *TextureD3D::makeTextureD3D(TextureImpl *texture)
     47 {
     48     ASSERT(HAS_DYNAMIC_TYPE(TextureD3D*, texture));
     49     return static_cast<TextureD3D*>(texture);
     50 }
     51 
     52 TextureStorage *TextureD3D::getNativeTexture()
     53 {
     54     // ensure the underlying texture is created
     55     initializeStorage(false);
     56 
     57     TextureStorage *storage = getBaseLevelStorage();
     58     if (storage)
     59     {
     60         updateStorage();
     61     }
     62 
     63     return storage;
     64 }
     65 
     66 GLint TextureD3D::getBaseLevelWidth() const
     67 {
     68     const Image *baseImage = getBaseLevelImage();
     69     return (baseImage ? baseImage->getWidth() : 0);
     70 }
     71 
     72 GLint TextureD3D::getBaseLevelHeight() const
     73 {
     74     const Image *baseImage = getBaseLevelImage();
     75     return (baseImage ? baseImage->getHeight() : 0);
     76 }
     77 
     78 GLint TextureD3D::getBaseLevelDepth() const
     79 {
     80     const Image *baseImage = getBaseLevelImage();
     81     return (baseImage ? baseImage->getDepth() : 0);
     82 }
     83 
     84 // Note: "base level image" is loosely defined to be any image from the base level,
     85 // where in the base of 2D array textures and cube maps there are several. Don't use
     86 // the base level image for anything except querying texture format and size.
     87 GLenum TextureD3D::getBaseLevelInternalFormat() const
     88 {
     89     const Image *baseImage = getBaseLevelImage();
     90     return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
     91 }
     92 
     93 void TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, Image *image)
     94 {
     95     // No-op
     96     if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
     97     {
     98         return;
     99     }
    100 
    101     // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
    102     // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
    103     const void *pixelData = pixels;
    104 
    105     if (unpack.pixelBuffer.id() != 0)
    106     {
    107         // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
    108         gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
    109         ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
    110         // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
    111         // This functionality should be moved into renderer and the getData method of BufferImpl removed.
    112         const void *bufferData = pixelBuffer->getImplementation()->getData();
    113         pixelData = static_cast<const unsigned char *>(bufferData) + offset;
    114     }
    115 
    116     if (pixelData != NULL)
    117     {
    118         image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
    119         mDirtyImages = true;
    120     }
    121 }
    122 
    123 bool TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
    124                           GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index)
    125 {
    126     const void *pixelData = pixels;
    127 
    128     // CPU readback & copy where direct GPU copy is not supported
    129     if (unpack.pixelBuffer.id() != 0)
    130     {
    131         gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
    132         unsigned int offset = reinterpret_cast<unsigned int>(pixels);
    133         // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
    134         // This functionality should be moved into renderer and the getData method of BufferImpl removed.
    135         const void *bufferData = pixelBuffer->getImplementation()->getData();
    136         pixelData = static_cast<const unsigned char *>(bufferData) + offset;
    137     }
    138 
    139     if (pixelData != NULL)
    140     {
    141         Image *image = getImage(index);
    142         ASSERT(image);
    143 
    144         image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixelData);
    145         mDirtyImages = true;
    146     }
    147 
    148     return true;
    149 }
    150 
    151 void TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
    152 {
    153     if (pixels != NULL)
    154     {
    155         image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
    156         mDirtyImages = true;
    157     }
    158 }
    159 
    160 bool TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
    161                                  GLenum format, GLsizei imageSize, const void *pixels, Image *image)
    162 {
    163     if (pixels != NULL)
    164     {
    165         image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
    166         mDirtyImages = true;
    167     }
    168 
    169     return true;
    170 }
    171 
    172 bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
    173 {
    174     return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
    175 }
    176 
    177 bool TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
    178                                GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget)
    179 {
    180     if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
    181     {
    182         return true;
    183     }
    184 
    185     // In order to perform the fast copy through the shader, we must have the right format, and be able
    186     // to create a render target.
    187     ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
    188 
    189     unsigned int offset = reinterpret_cast<unsigned int>(pixels);
    190 
    191     return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
    192 }
    193 
    194 GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
    195 {
    196     if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
    197     {
    198         // Maximum number of levels
    199         return gl::log2(std::max(std::max(width, height), depth)) + 1;
    200     }
    201     else
    202     {
    203         // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
    204         return 1;
    205     }
    206 }
    207 
    208 int TextureD3D::mipLevels() const
    209 {
    210     return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
    211 }
    212 
    213 
    214 TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
    215     : TextureD3D(renderer),
    216       mTexStorage(NULL)
    217 {
    218     for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
    219     {
    220         mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
    221     }
    222 }
    223 
    224 TextureD3D_2D::~TextureD3D_2D()
    225 {
    226     // Delete the Images before the TextureStorage.
    227     // Images might be relying on the TextureStorage for some of their data.
    228     // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images.
    229     for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
    230     {
    231         delete mImageArray[i];
    232     }
    233 
    234     SafeDelete(mTexStorage);
    235 }
    236 
    237 Image *TextureD3D_2D::getImage(int level, int layer) const
    238 {
    239     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
    240     ASSERT(layer == 0);
    241     return mImageArray[level];
    242 }
    243 
    244 Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
    245 {
    246     ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
    247     ASSERT(!index.hasLayer());
    248     ASSERT(index.type == GL_TEXTURE_2D);
    249     return mImageArray[index.mipIndex];
    250 }
    251 
    252 GLsizei TextureD3D_2D::getLayerCount(int level) const
    253 {
    254     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
    255     return 1;
    256 }
    257 
    258 GLsizei TextureD3D_2D::getWidth(GLint level) const
    259 {
    260     if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
    261         return mImageArray[level]->getWidth();
    262     else
    263         return 0;
    264 }
    265 
    266 GLsizei TextureD3D_2D::getHeight(GLint level) const
    267 {
    268     if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
    269         return mImageArray[level]->getHeight();
    270     else
    271         return 0;
    272 }
    273 
    274 GLenum TextureD3D_2D::getInternalFormat(GLint level) const
    275 {
    276     if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
    277         return mImageArray[level]->getInternalFormat();
    278     else
    279         return GL_NONE;
    280 }
    281 
    282 GLenum TextureD3D_2D::getActualFormat(GLint level) const
    283 {
    284     if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
    285         return mImageArray[level]->getActualFormat();
    286     else
    287         return GL_NONE;
    288 }
    289 
    290 bool TextureD3D_2D::isDepth(GLint level) const
    291 {
    292     return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
    293 }
    294 
    295 void TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
    296 {
    297     ASSERT(target == GL_TEXTURE_2D && depth == 1);
    298 
    299     GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
    300 
    301     bool fastUnpacked = false;
    302 
    303     redefineImage(level, sizedInternalFormat, width, height);
    304 
    305     // Attempt a fast gpu copy of the pixel data to the surface
    306     if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
    307     {
    308         gl::ImageIndex index = gl::ImageIndex::Make2D(level);
    309 
    310         // Will try to create RT storage if it does not exist
    311         RenderTarget *destRenderTarget = getRenderTarget(index);
    312         gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
    313 
    314         if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
    315         {
    316             // Ensure we don't overwrite our newly initialized data
    317             mImageArray[level]->markClean();
    318 
    319             fastUnpacked = true;
    320         }
    321     }
    322 
    323     if (!fastUnpacked)
    324     {
    325         TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
    326     }
    327 }
    328 
    329 void TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
    330 {
    331     ASSERT(target == GL_TEXTURE_2D && depth == 1);
    332 
    333     // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
    334     redefineImage(level, format, width, height);
    335 
    336     TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
    337 }
    338 
    339 void TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
    340 {
    341     ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
    342 
    343     bool fastUnpacked = false;
    344 
    345     gl::ImageIndex index = gl::ImageIndex::Make2D(level);
    346     if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
    347     {
    348         RenderTarget *renderTarget = getRenderTarget(index);
    349         gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
    350 
    351         if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget))
    352         {
    353             // Ensure we don't overwrite our newly initialized data
    354             mImageArray[level]->markClean();
    355 
    356             fastUnpacked = true;
    357         }
    358     }
    359 
    360     if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index))
    361     {
    362         commitRect(level, xoffset, yoffset, width, height);
    363     }
    364 }
    365 
    366 void TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
    367 {
    368     ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
    369 
    370     if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
    371     {
    372         commitRect(level, xoffset, yoffset, width, height);
    373     }
    374 }
    375 
    376 void TextureD3D_2D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
    377 {
    378     ASSERT(target == GL_TEXTURE_2D);
    379 
    380     GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
    381     redefineImage(level, sizedInternalFormat, width, height);
    382 
    383     if (!mImageArray[level]->isRenderableFormat())
    384     {
    385         mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
    386         mDirtyImages = true;
    387     }
    388     else
    389     {
    390         ensureRenderTarget();
    391         mImageArray[level]->markClean();
    392 
    393         if (width != 0 && height != 0 && isValidLevel(level))
    394         {
    395             gl::Rectangle sourceRect;
    396             sourceRect.x = x;
    397             sourceRect.width = width;
    398             sourceRect.y = y;
    399             sourceRect.height = height;
    400 
    401             mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
    402         }
    403     }
    404 }
    405 
    406 void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
    407 {
    408     ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
    409 
    410     // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
    411     // the current level we're copying to is defined (with appropriate format, width & height)
    412     bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
    413 
    414     if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
    415     {
    416         mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
    417         mDirtyImages = true;
    418     }
    419     else
    420     {
    421         ensureRenderTarget();
    422 
    423         if (isValidLevel(level))
    424         {
    425             updateStorageLevel(level);
    426 
    427             gl::Rectangle sourceRect;
    428             sourceRect.x = x;
    429             sourceRect.width = width;
    430             sourceRect.y = y;
    431             sourceRect.height = height;
    432 
    433             mRenderer->copyImage2D(source, sourceRect,
    434                                    gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
    435                                    xoffset, yoffset, mTexStorage, level);
    436         }
    437     }
    438 }
    439 
    440 void TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
    441 {
    442     ASSERT(target == GL_TEXTURE_2D && depth == 1);
    443 
    444     for (int level = 0; level < levels; level++)
    445     {
    446         GLsizei levelWidth = std::max(1, width >> level);
    447         GLsizei levelHeight = std::max(1, height >> level);
    448         mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
    449     }
    450 
    451     for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
    452     {
    453         mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
    454     }
    455 
    456     mImmutable = true;
    457 
    458     bool renderTarget = IsRenderTargetUsage(mUsage);
    459     TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels);
    460     setCompleteTexStorage(storage);
    461 }
    462 
    463 void TextureD3D_2D::bindTexImage(egl::Surface *surface)
    464 {
    465     GLenum internalformat = surface->getFormat();
    466 
    467     mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
    468 
    469     if (mTexStorage)
    470     {
    471         SafeDelete(mTexStorage);
    472     }
    473 
    474     mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain());
    475 
    476     mDirtyImages = true;
    477 }
    478 
    479 void TextureD3D_2D::releaseTexImage()
    480 {
    481     if (mTexStorage)
    482     {
    483         SafeDelete(mTexStorage);
    484     }
    485 
    486     for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
    487     {
    488         mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
    489     }
    490 }
    491 
    492 void TextureD3D_2D::generateMipmaps()
    493 {
    494     // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
    495     int levelCount = mipLevels();
    496     for (int level = 1; level < levelCount; level++)
    497     {
    498         redefineImage(level, getBaseLevelInternalFormat(),
    499                       std::max(getBaseLevelWidth() >> level, 1),
    500                       std::max(getBaseLevelHeight() >> level, 1));
    501     }
    502 
    503     if (mTexStorage && mTexStorage->isRenderTarget())
    504     {
    505         mTexStorage->generateMipmaps();
    506         for (int level = 1; level < levelCount; level++)
    507         {
    508             mImageArray[level]->markClean();
    509         }
    510     }
    511     else
    512     {
    513         for (int level = 1; level < levelCount; level++)
    514         {
    515             mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
    516         }
    517     }
    518 }
    519 
    520 unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
    521 {
    522     ASSERT(!index.hasLayer());
    523     return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
    524 }
    525 
    526 RenderTarget *TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index)
    527 {
    528     ASSERT(!index.hasLayer());
    529 
    530     // ensure the underlying texture is created
    531     if (!ensureRenderTarget())
    532     {
    533         return NULL;
    534     }
    535 
    536     updateStorageLevel(index.mipIndex);
    537     return mTexStorage->getRenderTarget(index);
    538 }
    539 
    540 bool TextureD3D_2D::isValidLevel(int level) const
    541 {
    542     return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
    543 }
    544 
    545 bool TextureD3D_2D::isLevelComplete(int level) const
    546 {
    547     if (isImmutable())
    548     {
    549         return true;
    550     }
    551 
    552     const Image *baseImage = getBaseLevelImage();
    553 
    554     GLsizei width = baseImage->getWidth();
    555     GLsizei height = baseImage->getHeight();
    556 
    557     if (width <= 0 || height <= 0)
    558     {
    559         return false;
    560     }
    561 
    562     // The base image level is complete if the width and height are positive
    563     if (level == 0)
    564     {
    565         return true;
    566     }
    567 
    568     ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
    569     ImageD3D *image = mImageArray[level];
    570 
    571     if (image->getInternalFormat() != baseImage->getInternalFormat())
    572     {
    573         return false;
    574     }
    575 
    576     if (image->getWidth() != std::max(1, width >> level))
    577     {
    578         return false;
    579     }
    580 
    581     if (image->getHeight() != std::max(1, height >> level))
    582     {
    583         return false;
    584     }
    585 
    586     return true;
    587 }
    588 
    589 // Constructs a native texture resource from the texture images
    590 void TextureD3D_2D::initializeStorage(bool renderTarget)
    591 {
    592     // Only initialize the first time this texture is used as a render target or shader resource
    593     if (mTexStorage)
    594     {
    595         return;
    596     }
    597 
    598     // do not attempt to create storage for nonexistant data
    599     if (!isLevelComplete(0))
    600     {
    601         return;
    602     }
    603 
    604     bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
    605 
    606     setCompleteTexStorage(createCompleteStorage(createRenderTarget));
    607     ASSERT(mTexStorage);
    608 
    609     // flush image data to the storage
    610     updateStorage();
    611 }
    612 
    613 TextureStorage *TextureD3D_2D::createCompleteStorage(bool renderTarget) const
    614 {
    615     GLsizei width = getBaseLevelWidth();
    616     GLsizei height = getBaseLevelHeight();
    617     GLenum internalFormat = getBaseLevelInternalFormat();
    618 
    619     ASSERT(width > 0 && height > 0);
    620 
    621     // use existing storage level count, when previously specified by TexStorage*D
    622     GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
    623 
    624     return mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
    625 }
    626 
    627 void TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
    628 {
    629     SafeDelete(mTexStorage);
    630     mTexStorage = newCompleteTexStorage;
    631 
    632     if (mTexStorage && mTexStorage->isManaged())
    633     {
    634         for (int level = 0; level < mTexStorage->getLevelCount(); level++)
    635         {
    636             mImageArray[level]->setManagedSurface2D(mTexStorage, level);
    637         }
    638     }
    639 
    640     mDirtyImages = true;
    641 }
    642 
    643 void TextureD3D_2D::updateStorage()
    644 {
    645     ASSERT(mTexStorage != NULL);
    646     GLint storageLevels = mTexStorage->getLevelCount();
    647     for (int level = 0; level < storageLevels; level++)
    648     {
    649         if (mImageArray[level]->isDirty() && isLevelComplete(level))
    650         {
    651             updateStorageLevel(level);
    652         }
    653     }
    654 }
    655 
    656 bool TextureD3D_2D::ensureRenderTarget()
    657 {
    658     initializeStorage(true);
    659 
    660     if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
    661     {
    662         ASSERT(mTexStorage);
    663         if (!mTexStorage->isRenderTarget())
    664         {
    665             TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
    666 
    667             if (!mRenderer->copyToRenderTarget2D(newRenderTargetStorage, mTexStorage))
    668             {
    669                 delete newRenderTargetStorage;
    670                 return gl::error(GL_OUT_OF_MEMORY, false);
    671             }
    672 
    673             setCompleteTexStorage(newRenderTargetStorage);
    674         }
    675     }
    676 
    677     return (mTexStorage && mTexStorage->isRenderTarget());
    678 }
    679 
    680 TextureStorage *TextureD3D_2D::getBaseLevelStorage()
    681 {
    682     return mTexStorage;
    683 }
    684 
    685 const ImageD3D *TextureD3D_2D::getBaseLevelImage() const
    686 {
    687     return mImageArray[0];
    688 }
    689 
    690 void TextureD3D_2D::updateStorageLevel(int level)
    691 {
    692     ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
    693     ASSERT(isLevelComplete(level));
    694 
    695     if (mImageArray[level]->isDirty())
    696     {
    697         commitRect(level, 0, 0, getWidth(level), getHeight(level));
    698     }
    699 }
    700 
    701 void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
    702 {
    703     // If there currently is a corresponding storage texture image, it has these parameters
    704     const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
    705     const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
    706     const GLenum storageFormat = getBaseLevelInternalFormat();
    707 
    708     mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
    709 
    710     if (mTexStorage)
    711     {
    712         const int storageLevels = mTexStorage->getLevelCount();
    713 
    714         if ((level >= storageLevels && storageLevels != 0) ||
    715             width != storageWidth ||
    716             height != storageHeight ||
    717             internalformat != storageFormat)   // Discard mismatched storage
    718         {
    719             for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
    720             {
    721                 mImageArray[i]->markDirty();
    722             }
    723 
    724             SafeDelete(mTexStorage);
    725             mDirtyImages = true;
    726         }
    727     }
    728 }
    729 
    730 void TextureD3D_2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
    731 {
    732     if (isValidLevel(level))
    733     {
    734         ImageD3D *image = mImageArray[level];
    735         if (image->copyToStorage2D(mTexStorage, level, xoffset, yoffset, width, height))
    736         {
    737             image->markClean();
    738         }
    739     }
    740 }
    741 
    742 
    743 TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
    744     : TextureD3D(renderer),
    745       mTexStorage(NULL)
    746 {
    747     for (int i = 0; i < 6; i++)
    748     {
    749         for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
    750         {
    751             mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
    752         }
    753     }
    754 }
    755 
    756 TextureD3D_Cube::~TextureD3D_Cube()
    757 {
    758     // Delete the Images before the TextureStorage.
    759     // Images might be relying on the TextureStorage for some of their data.
    760     // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images.
    761     for (int i = 0; i < 6; i++)
    762     {
    763         for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
    764         {
    765             SafeDelete(mImageArray[i][j]);
    766         }
    767     }
    768 
    769     SafeDelete(mTexStorage);
    770 }
    771 
    772 Image *TextureD3D_Cube::getImage(int level, int layer) const
    773 {
    774     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
    775     ASSERT(layer < 6);
    776     return mImageArray[layer][level];
    777 }
    778 
    779 Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
    780 {
    781     ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
    782     ASSERT(index.layerIndex < 6);
    783     return mImageArray[index.layerIndex][index.mipIndex];
    784 }
    785 
    786 GLsizei TextureD3D_Cube::getLayerCount(int level) const
    787 {
    788     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
    789     return 6;
    790 }
    791 
    792 GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
    793 {
    794     if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
    795         return mImageArray[layer][level]->getInternalFormat();
    796     else
    797         return GL_NONE;
    798 }
    799 
    800 bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
    801 {
    802     return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
    803 }
    804 
    805 void TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
    806 {
    807     ASSERT(depth == 1);
    808 
    809     int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
    810     GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
    811 
    812     redefineImage(faceIndex, level, sizedInternalFormat, width, height);
    813 
    814     TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
    815 }
    816 
    817 void TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
    818 {
    819     ASSERT(depth == 1);
    820 
    821     // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
    822     int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
    823 
    824     redefineImage(faceIndex, level, format, width, height);
    825 
    826     TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
    827 }
    828 
    829 void TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
    830 {
    831     ASSERT(depth == 1 && zoffset == 0);
    832 
    833     int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
    834 
    835     gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
    836     if (TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index))
    837     {
    838         commitRect(faceIndex, level, xoffset, yoffset, width, height);
    839     }
    840 }
    841 
    842 void TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
    843 {
    844     ASSERT(depth == 1 && zoffset == 0);
    845 
    846     int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
    847 
    848     if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
    849     {
    850         commitRect(faceIndex, level, xoffset, yoffset, width, height);
    851     }
    852 }
    853 
    854 void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
    855 {
    856     int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
    857     GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
    858 
    859     redefineImage(faceIndex, level, sizedInternalFormat, width, height);
    860 
    861     if (!mImageArray[faceIndex][level]->isRenderableFormat())
    862     {
    863         mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
    864         mDirtyImages = true;
    865     }
    866     else
    867     {
    868         ensureRenderTarget();
    869         mImageArray[faceIndex][level]->markClean();
    870 
    871         ASSERT(width == height);
    872 
    873         if (width > 0 && isValidFaceLevel(faceIndex, level))
    874         {
    875             gl::Rectangle sourceRect;
    876             sourceRect.x = x;
    877             sourceRect.width = width;
    878             sourceRect.y = y;
    879             sourceRect.height = height;
    880 
    881             mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
    882         }
    883     }
    884 }
    885 
    886 void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
    887 {
    888     int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
    889 
    890     // We can only make our texture storage to a render target if the level we're copying *to* is complete
    891     // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
    892     // rely on the "getBaseLevel*" methods reliably otherwise.
    893     bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
    894 
    895     if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
    896     {
    897         mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
    898         mDirtyImages = true;
    899     }
    900     else
    901     {
    902         ensureRenderTarget();
    903 
    904         if (isValidFaceLevel(faceIndex, level))
    905         {
    906             updateStorageFaceLevel(faceIndex, level);
    907 
    908             gl::Rectangle sourceRect;
    909             sourceRect.x = x;
    910             sourceRect.width = width;
    911             sourceRect.y = y;
    912             sourceRect.height = height;
    913 
    914             mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
    915                                      xoffset, yoffset, mTexStorage, target, level);
    916         }
    917     }
    918 }
    919 
    920 void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
    921 {
    922     ASSERT(width == height);
    923     ASSERT(depth == 1);
    924 
    925     for (int level = 0; level < levels; level++)
    926     {
    927         GLsizei mipSize = std::max(1, width >> level);
    928         for (int faceIndex = 0; faceIndex < 6; faceIndex++)
    929         {
    930             mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
    931         }
    932     }
    933 
    934     for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
    935     {
    936         for (int faceIndex = 0; faceIndex < 6; faceIndex++)
    937         {
    938             mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
    939         }
    940     }
    941 
    942     mImmutable = true;
    943 
    944     bool renderTarget = IsRenderTargetUsage(mUsage);
    945     TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
    946     setCompleteTexStorage(storage);
    947 }
    948 
    949 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
    950 bool TextureD3D_Cube::isCubeComplete() const
    951 {
    952     int    baseWidth  = getBaseLevelWidth();
    953     int    baseHeight = getBaseLevelHeight();
    954     GLenum baseFormat = getBaseLevelInternalFormat();
    955 
    956     if (baseWidth <= 0 || baseWidth != baseHeight)
    957     {
    958         return false;
    959     }
    960 
    961     for (int faceIndex = 1; faceIndex < 6; faceIndex++)
    962     {
    963         const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
    964 
    965         if (faceBaseImage.getWidth()          != baseWidth  ||
    966             faceBaseImage.getHeight()         != baseHeight ||
    967             faceBaseImage.getInternalFormat() != baseFormat )
    968         {
    969             return false;
    970         }
    971     }
    972 
    973     return true;
    974 }
    975 
    976 void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
    977 {
    978     UNREACHABLE();
    979 }
    980 
    981 void TextureD3D_Cube::releaseTexImage()
    982 {
    983     UNREACHABLE();
    984 }
    985 
    986 
    987 void TextureD3D_Cube::generateMipmaps()
    988 {
    989     // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
    990     int levelCount = mipLevels();
    991     for (int faceIndex = 0; faceIndex < 6; faceIndex++)
    992     {
    993         for (int level = 1; level < levelCount; level++)
    994         {
    995             int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
    996             redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
    997         }
    998     }
    999 
   1000     if (mTexStorage && mTexStorage->isRenderTarget())
   1001     {
   1002         mTexStorage->generateMipmaps();
   1003 
   1004         for (int faceIndex = 0; faceIndex < 6; faceIndex++)
   1005         {
   1006             for (int level = 1; level < levelCount; level++)
   1007             {
   1008                 mImageArray[faceIndex][level]->markClean();
   1009             }
   1010         }
   1011     }
   1012     else
   1013     {
   1014         for (int faceIndex = 0; faceIndex < 6; faceIndex++)
   1015         {
   1016             for (int level = 1; level < levelCount; level++)
   1017             {
   1018                 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
   1019             }
   1020         }
   1021     }
   1022 }
   1023 
   1024 unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
   1025 {
   1026     return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
   1027 }
   1028 
   1029 RenderTarget *TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index)
   1030 {
   1031     ASSERT(gl::IsCubemapTextureTarget(index.type));
   1032 
   1033     // ensure the underlying texture is created
   1034     if (!ensureRenderTarget())
   1035     {
   1036         return NULL;
   1037     }
   1038 
   1039     updateStorageFaceLevel(index.layerIndex, index.mipIndex);
   1040     return mTexStorage->getRenderTarget(index);
   1041 }
   1042 
   1043 void TextureD3D_Cube::initializeStorage(bool renderTarget)
   1044 {
   1045     // Only initialize the first time this texture is used as a render target or shader resource
   1046     if (mTexStorage)
   1047     {
   1048         return;
   1049     }
   1050 
   1051     // do not attempt to create storage for nonexistant data
   1052     if (!isFaceLevelComplete(0, 0))
   1053     {
   1054         return;
   1055     }
   1056 
   1057     bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
   1058 
   1059     setCompleteTexStorage(createCompleteStorage(createRenderTarget));
   1060     ASSERT(mTexStorage);
   1061 
   1062     // flush image data to the storage
   1063     updateStorage();
   1064 }
   1065 
   1066 TextureStorage *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const
   1067 {
   1068     GLsizei size = getBaseLevelWidth();
   1069 
   1070     ASSERT(size > 0);
   1071 
   1072     // use existing storage level count, when previously specified by TexStorage*D
   1073     GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
   1074 
   1075     return mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
   1076 }
   1077 
   1078 void TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
   1079 {
   1080     SafeDelete(mTexStorage);
   1081     mTexStorage = newCompleteTexStorage;
   1082 
   1083     if (mTexStorage && mTexStorage->isManaged())
   1084     {
   1085         for (int faceIndex = 0; faceIndex < 6; faceIndex++)
   1086         {
   1087             for (int level = 0; level < mTexStorage->getLevelCount(); level++)
   1088             {
   1089                 mImageArray[faceIndex][level]->setManagedSurfaceCube(mTexStorage, faceIndex, level);
   1090             }
   1091         }
   1092     }
   1093 
   1094     mDirtyImages = true;
   1095 }
   1096 
   1097 void TextureD3D_Cube::updateStorage()
   1098 {
   1099     ASSERT(mTexStorage != NULL);
   1100     GLint storageLevels = mTexStorage->getLevelCount();
   1101     for (int face = 0; face < 6; face++)
   1102     {
   1103         for (int level = 0; level < storageLevels; level++)
   1104         {
   1105             if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
   1106             {
   1107                 updateStorageFaceLevel(face, level);
   1108             }
   1109         }
   1110     }
   1111 }
   1112 
   1113 bool TextureD3D_Cube::ensureRenderTarget()
   1114 {
   1115     initializeStorage(true);
   1116 
   1117     if (getBaseLevelWidth() > 0)
   1118     {
   1119         ASSERT(mTexStorage);
   1120         if (!mTexStorage->isRenderTarget())
   1121         {
   1122             TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
   1123 
   1124             if (!mRenderer->copyToRenderTargetCube(newRenderTargetStorage, mTexStorage))
   1125             {
   1126                 delete newRenderTargetStorage;
   1127                 return gl::error(GL_OUT_OF_MEMORY, false);
   1128             }
   1129 
   1130             setCompleteTexStorage(newRenderTargetStorage);
   1131         }
   1132     }
   1133 
   1134     return (mTexStorage && mTexStorage->isRenderTarget());
   1135 }
   1136 
   1137 TextureStorage *TextureD3D_Cube::getBaseLevelStorage()
   1138 {
   1139     return mTexStorage;
   1140 }
   1141 
   1142 const ImageD3D *TextureD3D_Cube::getBaseLevelImage() const
   1143 {
   1144     // Note: if we are not cube-complete, there is no single base level image that can describe all
   1145     // cube faces, so this method is only well-defined for a cube-complete base level.
   1146     return mImageArray[0][0];
   1147 }
   1148 
   1149 bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
   1150 {
   1151     return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
   1152 }
   1153 
   1154 bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
   1155 {
   1156     ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
   1157 
   1158     if (isImmutable())
   1159     {
   1160         return true;
   1161     }
   1162 
   1163     int baseSize = getBaseLevelWidth();
   1164 
   1165     if (baseSize <= 0)
   1166     {
   1167         return false;
   1168     }
   1169 
   1170     // "isCubeComplete" checks for base level completeness and we must call that
   1171     // to determine if any face at level 0 is complete. We omit that check here
   1172     // to avoid re-checking cube-completeness for every face at level 0.
   1173     if (level == 0)
   1174     {
   1175         return true;
   1176     }
   1177 
   1178     // Check that non-zero levels are consistent with the base level.
   1179     const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
   1180 
   1181     if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
   1182     {
   1183         return false;
   1184     }
   1185 
   1186     if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
   1187     {
   1188         return false;
   1189     }
   1190 
   1191     return true;
   1192 }
   1193 
   1194 void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
   1195 {
   1196     ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
   1197     ImageD3D *image = mImageArray[faceIndex][level];
   1198 
   1199     if (image->isDirty())
   1200     {
   1201         commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
   1202     }
   1203 }
   1204 
   1205 void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
   1206 {
   1207     // If there currently is a corresponding storage texture image, it has these parameters
   1208     const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
   1209     const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
   1210     const GLenum storageFormat = getBaseLevelInternalFormat();
   1211 
   1212     mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
   1213 
   1214     if (mTexStorage)
   1215     {
   1216         const int storageLevels = mTexStorage->getLevelCount();
   1217 
   1218         if ((level >= storageLevels && storageLevels != 0) ||
   1219             width != storageWidth ||
   1220             height != storageHeight ||
   1221             internalformat != storageFormat)   // Discard mismatched storage
   1222         {
   1223             for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
   1224             {
   1225                 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
   1226                 {
   1227                     mImageArray[faceIndex][level]->markDirty();
   1228                 }
   1229             }
   1230 
   1231             SafeDelete(mTexStorage);
   1232 
   1233             mDirtyImages = true;
   1234         }
   1235     }
   1236 }
   1237 
   1238 void TextureD3D_Cube::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
   1239 {
   1240     if (isValidFaceLevel(faceIndex, level))
   1241     {
   1242         ImageD3D *image = mImageArray[faceIndex][level];
   1243         if (image->copyToStorageCube(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
   1244             image->markClean();
   1245     }
   1246 }
   1247 
   1248 
   1249 TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
   1250     : TextureD3D(renderer),
   1251       mTexStorage(NULL)
   1252 {
   1253     for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
   1254     {
   1255         mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
   1256     }
   1257 }
   1258 
   1259 TextureD3D_3D::~TextureD3D_3D()
   1260 {
   1261     // Delete the Images before the TextureStorage.
   1262     // Images might be relying on the TextureStorage for some of their data.
   1263     // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images.
   1264     for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
   1265     {
   1266         delete mImageArray[i];
   1267     }
   1268 
   1269     SafeDelete(mTexStorage);
   1270 }
   1271 
   1272 Image *TextureD3D_3D::getImage(int level, int layer) const
   1273 {
   1274     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
   1275     ASSERT(layer == 0);
   1276     return mImageArray[level];
   1277 }
   1278 
   1279 Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
   1280 {
   1281     ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
   1282     ASSERT(!index.hasLayer());
   1283     ASSERT(index.type == GL_TEXTURE_3D);
   1284     return mImageArray[index.mipIndex];
   1285 }
   1286 
   1287 GLsizei TextureD3D_3D::getLayerCount(int level) const
   1288 {
   1289     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
   1290     return 1;
   1291 }
   1292 
   1293 GLsizei TextureD3D_3D::getWidth(GLint level) const
   1294 {
   1295     if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
   1296         return mImageArray[level]->getWidth();
   1297     else
   1298         return 0;
   1299 }
   1300 
   1301 GLsizei TextureD3D_3D::getHeight(GLint level) const
   1302 {
   1303     if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
   1304         return mImageArray[level]->getHeight();
   1305     else
   1306         return 0;
   1307 }
   1308 
   1309 GLsizei TextureD3D_3D::getDepth(GLint level) const
   1310 {
   1311     if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
   1312         return mImageArray[level]->getDepth();
   1313     else
   1314         return 0;
   1315 }
   1316 
   1317 GLenum TextureD3D_3D::getInternalFormat(GLint level) const
   1318 {
   1319     if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
   1320         return mImageArray[level]->getInternalFormat();
   1321     else
   1322         return GL_NONE;
   1323 }
   1324 
   1325 bool TextureD3D_3D::isDepth(GLint level) const
   1326 {
   1327     return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
   1328 }
   1329 
   1330 void TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
   1331 {
   1332     ASSERT(target == GL_TEXTURE_3D);
   1333     GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
   1334 
   1335     redefineImage(level, sizedInternalFormat, width, height, depth);
   1336 
   1337     bool fastUnpacked = false;
   1338 
   1339     // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
   1340     if (isFastUnpackable(unpack, sizedInternalFormat))
   1341     {
   1342         // Will try to create RT storage if it does not exist
   1343         gl::ImageIndex index = gl::ImageIndex::Make3D(level);
   1344         RenderTarget *destRenderTarget = getRenderTarget(index);
   1345         gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
   1346 
   1347         if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
   1348         {
   1349             // Ensure we don't overwrite our newly initialized data
   1350             mImageArray[level]->markClean();
   1351 
   1352             fastUnpacked = true;
   1353         }
   1354     }
   1355 
   1356     if (!fastUnpacked)
   1357     {
   1358         TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
   1359     }
   1360 }
   1361 
   1362 void TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
   1363 {
   1364     ASSERT(target == GL_TEXTURE_3D);
   1365 
   1366     // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
   1367     redefineImage(level, format, width, height, depth);
   1368 
   1369     TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
   1370 }
   1371 
   1372 void TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
   1373 {
   1374     ASSERT(target == GL_TEXTURE_3D);
   1375 
   1376     bool fastUnpacked = false;
   1377 
   1378     gl::ImageIndex index = gl::ImageIndex::Make3D(level);
   1379 
   1380     // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
   1381     if (isFastUnpackable(unpack, getInternalFormat(level)))
   1382     {
   1383         RenderTarget *destRenderTarget = getRenderTarget(index);
   1384         gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
   1385 
   1386         if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
   1387         {
   1388             // Ensure we don't overwrite our newly initialized data
   1389             mImageArray[level]->markClean();
   1390 
   1391             fastUnpacked = true;
   1392         }
   1393     }
   1394 
   1395     if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, index))
   1396     {
   1397         commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
   1398     }
   1399 }
   1400 
   1401 void TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
   1402 {
   1403     ASSERT(target == GL_TEXTURE_3D);
   1404 
   1405     if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
   1406     {
   1407         commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
   1408     }
   1409 }
   1410 
   1411 void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
   1412 {
   1413     UNIMPLEMENTED();
   1414 }
   1415 
   1416 void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
   1417 {
   1418     ASSERT(target == GL_TEXTURE_3D);
   1419 
   1420     // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
   1421     // the current level we're copying to is defined (with appropriate format, width & height)
   1422     bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
   1423 
   1424     if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
   1425     {
   1426         mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
   1427         mDirtyImages = true;
   1428     }
   1429     else
   1430     {
   1431         ensureRenderTarget();
   1432 
   1433         if (isValidLevel(level))
   1434         {
   1435             updateStorageLevel(level);
   1436 
   1437             gl::Rectangle sourceRect;
   1438             sourceRect.x = x;
   1439             sourceRect.width = width;
   1440             sourceRect.y = y;
   1441             sourceRect.height = height;
   1442 
   1443             mRenderer->copyImage3D(source, sourceRect,
   1444                                    gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
   1445                                    xoffset, yoffset, zoffset, mTexStorage, level);
   1446         }
   1447     }
   1448 }
   1449 
   1450 void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
   1451 {
   1452     ASSERT(target == GL_TEXTURE_3D);
   1453 
   1454     for (int level = 0; level < levels; level++)
   1455     {
   1456         GLsizei levelWidth = std::max(1, width >> level);
   1457         GLsizei levelHeight = std::max(1, height >> level);
   1458         GLsizei levelDepth = std::max(1, depth >> level);
   1459         mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
   1460     }
   1461 
   1462     for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
   1463     {
   1464         mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
   1465     }
   1466 
   1467     mImmutable = true;
   1468 
   1469     bool renderTarget = IsRenderTargetUsage(mUsage);
   1470     TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
   1471     setCompleteTexStorage(storage);
   1472 }
   1473 
   1474 void TextureD3D_3D::bindTexImage(egl::Surface *surface)
   1475 {
   1476     UNREACHABLE();
   1477 }
   1478 
   1479 void TextureD3D_3D::releaseTexImage()
   1480 {
   1481     UNREACHABLE();
   1482 }
   1483 
   1484 
   1485 void TextureD3D_3D::generateMipmaps()
   1486 {
   1487     // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
   1488     int levelCount = mipLevels();
   1489     for (int level = 1; level < levelCount; level++)
   1490     {
   1491         redefineImage(level, getBaseLevelInternalFormat(),
   1492                       std::max(getBaseLevelWidth() >> level, 1),
   1493                       std::max(getBaseLevelHeight() >> level, 1),
   1494                       std::max(getBaseLevelDepth() >> level, 1));
   1495     }
   1496 
   1497     if (mTexStorage && mTexStorage->isRenderTarget())
   1498     {
   1499         mTexStorage->generateMipmaps();
   1500 
   1501         for (int level = 1; level < levelCount; level++)
   1502         {
   1503             mImageArray[level]->markClean();
   1504         }
   1505     }
   1506     else
   1507     {
   1508         for (int level = 1; level < levelCount; level++)
   1509         {
   1510             mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
   1511         }
   1512     }
   1513 }
   1514 
   1515 unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
   1516 {
   1517     return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
   1518 }
   1519 
   1520 RenderTarget *TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index)
   1521 {
   1522     // ensure the underlying texture is created
   1523     if (!ensureRenderTarget())
   1524     {
   1525         return NULL;
   1526     }
   1527 
   1528     if (index.hasLayer())
   1529     {
   1530         updateStorage();
   1531     }
   1532     else
   1533     {
   1534         updateStorageLevel(index.mipIndex);
   1535     }
   1536 
   1537     return mTexStorage->getRenderTarget(index);
   1538 }
   1539 
   1540 void TextureD3D_3D::initializeStorage(bool renderTarget)
   1541 {
   1542     // Only initialize the first time this texture is used as a render target or shader resource
   1543     if (mTexStorage)
   1544     {
   1545         return;
   1546     }
   1547 
   1548     // do not attempt to create storage for nonexistant data
   1549     if (!isLevelComplete(0))
   1550     {
   1551         return;
   1552     }
   1553 
   1554     bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
   1555 
   1556     setCompleteTexStorage(createCompleteStorage(createRenderTarget));
   1557     ASSERT(mTexStorage);
   1558 
   1559     // flush image data to the storage
   1560     updateStorage();
   1561 }
   1562 
   1563 TextureStorage *TextureD3D_3D::createCompleteStorage(bool renderTarget) const
   1564 {
   1565     GLsizei width = getBaseLevelWidth();
   1566     GLsizei height = getBaseLevelHeight();
   1567     GLsizei depth = getBaseLevelDepth();
   1568     GLenum internalFormat = getBaseLevelInternalFormat();
   1569 
   1570     ASSERT(width > 0 && height > 0 && depth > 0);
   1571 
   1572     // use existing storage level count, when previously specified by TexStorage*D
   1573     GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
   1574 
   1575     return mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
   1576 }
   1577 
   1578 void TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
   1579 {
   1580     SafeDelete(mTexStorage);
   1581     mTexStorage = newCompleteTexStorage;
   1582     mDirtyImages = true;
   1583 
   1584     // We do not support managed 3D storage, as that is D3D9/ES2-only
   1585     ASSERT(!mTexStorage->isManaged());
   1586 }
   1587 
   1588 void TextureD3D_3D::updateStorage()
   1589 {
   1590     ASSERT(mTexStorage != NULL);
   1591     GLint storageLevels = mTexStorage->getLevelCount();
   1592     for (int level = 0; level < storageLevels; level++)
   1593     {
   1594         if (mImageArray[level]->isDirty() && isLevelComplete(level))
   1595         {
   1596             updateStorageLevel(level);
   1597         }
   1598     }
   1599 }
   1600 
   1601 bool TextureD3D_3D::ensureRenderTarget()
   1602 {
   1603     initializeStorage(true);
   1604 
   1605     if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
   1606     {
   1607         ASSERT(mTexStorage);
   1608         if (!mTexStorage->isRenderTarget())
   1609         {
   1610             TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
   1611 
   1612             if (!mRenderer->copyToRenderTarget3D(newRenderTargetStorage, mTexStorage))
   1613             {
   1614                 delete newRenderTargetStorage;
   1615                 return gl::error(GL_OUT_OF_MEMORY, false);
   1616             }
   1617 
   1618             setCompleteTexStorage(newRenderTargetStorage);
   1619         }
   1620     }
   1621 
   1622     return (mTexStorage && mTexStorage->isRenderTarget());
   1623 }
   1624 
   1625 TextureStorage *TextureD3D_3D::getBaseLevelStorage()
   1626 {
   1627     return mTexStorage;
   1628 }
   1629 
   1630 const ImageD3D *TextureD3D_3D::getBaseLevelImage() const
   1631 {
   1632     return mImageArray[0];
   1633 }
   1634 
   1635 bool TextureD3D_3D::isValidLevel(int level) const
   1636 {
   1637     return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
   1638 }
   1639 
   1640 bool TextureD3D_3D::isLevelComplete(int level) const
   1641 {
   1642     ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
   1643 
   1644     if (isImmutable())
   1645     {
   1646         return true;
   1647     }
   1648 
   1649     GLsizei width = getBaseLevelWidth();
   1650     GLsizei height = getBaseLevelHeight();
   1651     GLsizei depth = getBaseLevelDepth();
   1652 
   1653     if (width <= 0 || height <= 0 || depth <= 0)
   1654     {
   1655         return false;
   1656     }
   1657 
   1658     if (level == 0)
   1659     {
   1660         return true;
   1661     }
   1662 
   1663     ImageD3D *levelImage = mImageArray[level];
   1664 
   1665     if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
   1666     {
   1667         return false;
   1668     }
   1669 
   1670     if (levelImage->getWidth() != std::max(1, width >> level))
   1671     {
   1672         return false;
   1673     }
   1674 
   1675     if (levelImage->getHeight() != std::max(1, height >> level))
   1676     {
   1677         return false;
   1678     }
   1679 
   1680     if (levelImage->getDepth() != std::max(1, depth >> level))
   1681     {
   1682         return false;
   1683     }
   1684 
   1685     return true;
   1686 }
   1687 
   1688 void TextureD3D_3D::updateStorageLevel(int level)
   1689 {
   1690     ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
   1691     ASSERT(isLevelComplete(level));
   1692 
   1693     if (mImageArray[level]->isDirty())
   1694     {
   1695         commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
   1696     }
   1697 }
   1698 
   1699 void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
   1700 {
   1701     // If there currently is a corresponding storage texture image, it has these parameters
   1702     const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
   1703     const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
   1704     const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
   1705     const GLenum storageFormat = getBaseLevelInternalFormat();
   1706 
   1707     mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
   1708 
   1709     if (mTexStorage)
   1710     {
   1711         const int storageLevels = mTexStorage->getLevelCount();
   1712 
   1713         if ((level >= storageLevels && storageLevels != 0) ||
   1714             width != storageWidth ||
   1715             height != storageHeight ||
   1716             depth != storageDepth ||
   1717             internalformat != storageFormat)   // Discard mismatched storage
   1718         {
   1719             for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
   1720             {
   1721                 mImageArray[i]->markDirty();
   1722             }
   1723 
   1724             SafeDelete(mTexStorage);
   1725             mDirtyImages = true;
   1726         }
   1727     }
   1728 }
   1729 
   1730 void TextureD3D_3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
   1731 {
   1732     if (isValidLevel(level))
   1733     {
   1734         ImageD3D *image = mImageArray[level];
   1735         if (image->copyToStorage3D(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
   1736         {
   1737             image->markClean();
   1738         }
   1739     }
   1740 }
   1741 
   1742 
   1743 TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
   1744     : TextureD3D(renderer),
   1745       mTexStorage(NULL)
   1746 {
   1747     for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
   1748     {
   1749         mLayerCounts[level] = 0;
   1750         mImageArray[level] = NULL;
   1751     }
   1752 }
   1753 
   1754 TextureD3D_2DArray::~TextureD3D_2DArray()
   1755 {
   1756     // Delete the Images before the TextureStorage.
   1757     // Images might be relying on the TextureStorage for some of their data.
   1758     // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images.
   1759     deleteImages();
   1760     SafeDelete(mTexStorage);
   1761 }
   1762 
   1763 Image *TextureD3D_2DArray::getImage(int level, int layer) const
   1764 {
   1765     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
   1766     ASSERT(layer < mLayerCounts[level]);
   1767     return mImageArray[level][layer];
   1768 }
   1769 
   1770 Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
   1771 {
   1772     ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
   1773     ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
   1774     ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
   1775     return mImageArray[index.mipIndex][index.layerIndex];
   1776 }
   1777 
   1778 GLsizei TextureD3D_2DArray::getLayerCount(int level) const
   1779 {
   1780     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
   1781     return mLayerCounts[level];
   1782 }
   1783 
   1784 GLsizei TextureD3D_2DArray::getWidth(GLint level) const
   1785 {
   1786     return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
   1787 }
   1788 
   1789 GLsizei TextureD3D_2DArray::getHeight(GLint level) const
   1790 {
   1791     return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
   1792 }
   1793 
   1794 GLsizei TextureD3D_2DArray::getLayers(GLint level) const
   1795 {
   1796     return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mLayerCounts[level] : 0;
   1797 }
   1798 
   1799 GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
   1800 {
   1801     return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
   1802 }
   1803 
   1804 bool TextureD3D_2DArray::isDepth(GLint level) const
   1805 {
   1806     return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
   1807 }
   1808 
   1809 void TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
   1810 {
   1811     ASSERT(target == GL_TEXTURE_2D_ARRAY);
   1812 
   1813     GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
   1814 
   1815     redefineImage(level, sizedInternalFormat, width, height, depth);
   1816 
   1817     const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
   1818     GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
   1819 
   1820     for (int i = 0; i < depth; i++)
   1821     {
   1822         const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
   1823         TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]);
   1824     }
   1825 }
   1826 
   1827 void TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
   1828 {
   1829     ASSERT(target == GL_TEXTURE_2D_ARRAY);
   1830 
   1831     // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
   1832     redefineImage(level, format, width, height, depth);
   1833 
   1834     const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
   1835     GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
   1836 
   1837     for (int i = 0; i < depth; i++)
   1838     {
   1839         const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
   1840         TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
   1841     }
   1842 }
   1843 
   1844 void TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
   1845 {
   1846     ASSERT(target == GL_TEXTURE_2D_ARRAY);
   1847 
   1848     const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
   1849     GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
   1850 
   1851     for (int i = 0; i < depth; i++)
   1852     {
   1853         int layer = zoffset + i;
   1854         const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
   1855 
   1856         gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
   1857         if (TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack, layerPixels, index))
   1858         {
   1859             commitRect(level, xoffset, yoffset, layer, width, height);
   1860         }
   1861     }
   1862 }
   1863 
   1864 void TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
   1865 {
   1866     ASSERT(target == GL_TEXTURE_2D_ARRAY);
   1867 
   1868     const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
   1869     GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
   1870 
   1871     for (int i = 0; i < depth; i++)
   1872     {
   1873         int layer = zoffset + i;
   1874         const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
   1875 
   1876         if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
   1877         {
   1878             commitRect(level, xoffset, yoffset, layer, width, height);
   1879         }
   1880     }
   1881 }
   1882 
   1883 void TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
   1884 {
   1885     UNIMPLEMENTED();
   1886 }
   1887 
   1888 void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
   1889 {
   1890     ASSERT(target == GL_TEXTURE_2D_ARRAY);
   1891 
   1892     // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
   1893     // the current level we're copying to is defined (with appropriate format, width & height)
   1894     bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
   1895 
   1896     if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
   1897     {
   1898         mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
   1899         mDirtyImages = true;
   1900     }
   1901     else
   1902     {
   1903         ensureRenderTarget();
   1904 
   1905         if (isValidLevel(level))
   1906         {
   1907             updateStorageLevel(level);
   1908 
   1909             gl::Rectangle sourceRect;
   1910             sourceRect.x = x;
   1911             sourceRect.width = width;
   1912             sourceRect.y = y;
   1913             sourceRect.height = height;
   1914 
   1915             mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
   1916                                         xoffset, yoffset, zoffset, mTexStorage, level);
   1917         }
   1918     }
   1919 }
   1920 
   1921 void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
   1922 {
   1923     ASSERT(target == GL_TEXTURE_2D_ARRAY);
   1924 
   1925     deleteImages();
   1926 
   1927     for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
   1928     {
   1929         GLsizei levelWidth = std::max(1, width >> level);
   1930         GLsizei levelHeight = std::max(1, height >> level);
   1931 
   1932         mLayerCounts[level] = (level < levels ? depth : 0);
   1933 
   1934         if (mLayerCounts[level] > 0)
   1935         {
   1936             // Create new images for this level
   1937             mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
   1938 
   1939             for (int layer = 0; layer < mLayerCounts[level]; layer++)
   1940             {
   1941                 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
   1942                 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
   1943                                                     levelHeight, 1, true);
   1944             }
   1945         }
   1946     }
   1947 
   1948     mImmutable = true;
   1949 
   1950     bool renderTarget = IsRenderTargetUsage(mUsage);
   1951     TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
   1952     setCompleteTexStorage(storage);
   1953 }
   1954 
   1955 void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
   1956 {
   1957     UNREACHABLE();
   1958 }
   1959 
   1960 void TextureD3D_2DArray::releaseTexImage()
   1961 {
   1962     UNREACHABLE();
   1963 }
   1964 
   1965 
   1966 void TextureD3D_2DArray::generateMipmaps()
   1967 {
   1968     int baseWidth = getBaseLevelWidth();
   1969     int baseHeight = getBaseLevelHeight();
   1970     int baseDepth = getBaseLevelDepth();
   1971     GLenum baseFormat = getBaseLevelInternalFormat();
   1972 
   1973     // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
   1974     int levelCount = mipLevels();
   1975     for (int level = 1; level < levelCount; level++)
   1976     {
   1977         redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
   1978     }
   1979 
   1980     if (mTexStorage && mTexStorage->isRenderTarget())
   1981     {
   1982         mTexStorage->generateMipmaps();
   1983 
   1984         for (int level = 1; level < levelCount; level++)
   1985         {
   1986             for (int layer = 0; layer < mLayerCounts[level]; layer++)
   1987             {
   1988                 mImageArray[level][layer]->markClean();
   1989             }
   1990         }
   1991     }
   1992     else
   1993     {
   1994         for (int level = 1; level < levelCount; level++)
   1995         {
   1996             for (int layer = 0; layer < mLayerCounts[level]; layer++)
   1997             {
   1998                 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
   1999             }
   2000         }
   2001     }
   2002 }
   2003 
   2004 unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
   2005 {
   2006     return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
   2007 }
   2008 
   2009 RenderTarget *TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index)
   2010 {
   2011     // ensure the underlying texture is created
   2012     if (!ensureRenderTarget())
   2013     {
   2014         return NULL;
   2015     }
   2016 
   2017     updateStorageLevel(index.mipIndex);
   2018     return mTexStorage->getRenderTarget(index);
   2019 }
   2020 
   2021 void TextureD3D_2DArray::initializeStorage(bool renderTarget)
   2022 {
   2023     // Only initialize the first time this texture is used as a render target or shader resource
   2024     if (mTexStorage)
   2025     {
   2026         return;
   2027     }
   2028 
   2029     // do not attempt to create storage for nonexistant data
   2030     if (!isLevelComplete(0))
   2031     {
   2032         return;
   2033     }
   2034 
   2035     bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
   2036 
   2037     setCompleteTexStorage(createCompleteStorage(createRenderTarget));
   2038     ASSERT(mTexStorage);
   2039 
   2040     // flush image data to the storage
   2041     updateStorage();
   2042 }
   2043 
   2044 TextureStorage *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const
   2045 {
   2046     GLsizei width = getBaseLevelWidth();
   2047     GLsizei height = getBaseLevelHeight();
   2048     GLsizei depth = getLayers(0);
   2049     GLenum internalFormat = getBaseLevelInternalFormat();
   2050 
   2051     ASSERT(width > 0 && height > 0 && depth > 0);
   2052 
   2053     // use existing storage level count, when previously specified by TexStorage*D
   2054     GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
   2055 
   2056     return mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
   2057 }
   2058 
   2059 void TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
   2060 {
   2061     SafeDelete(mTexStorage);
   2062     mTexStorage = newCompleteTexStorage;
   2063     mDirtyImages = true;
   2064 
   2065     // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
   2066     ASSERT(!mTexStorage->isManaged());
   2067 }
   2068 
   2069 void TextureD3D_2DArray::updateStorage()
   2070 {
   2071     ASSERT(mTexStorage != NULL);
   2072     GLint storageLevels = mTexStorage->getLevelCount();
   2073     for (int level = 0; level < storageLevels; level++)
   2074     {
   2075         if (isLevelComplete(level))
   2076         {
   2077             updateStorageLevel(level);
   2078         }
   2079     }
   2080 }
   2081 
   2082 bool TextureD3D_2DArray::ensureRenderTarget()
   2083 {
   2084     initializeStorage(true);
   2085 
   2086     if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
   2087     {
   2088         ASSERT(mTexStorage);
   2089         if (!mTexStorage->isRenderTarget())
   2090         {
   2091             TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
   2092 
   2093             if (!mRenderer->copyToRenderTarget2DArray(newRenderTargetStorage, mTexStorage))
   2094             {
   2095                 delete newRenderTargetStorage;
   2096                 return gl::error(GL_OUT_OF_MEMORY, false);
   2097             }
   2098 
   2099             setCompleteTexStorage(newRenderTargetStorage);
   2100         }
   2101     }
   2102 
   2103     return (mTexStorage && mTexStorage->isRenderTarget());
   2104 }
   2105 
   2106 const ImageD3D *TextureD3D_2DArray::getBaseLevelImage() const
   2107 {
   2108     return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
   2109 }
   2110 
   2111 TextureStorage *TextureD3D_2DArray::getBaseLevelStorage()
   2112 {
   2113     return mTexStorage;
   2114 }
   2115 
   2116 bool TextureD3D_2DArray::isValidLevel(int level) const
   2117 {
   2118     return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
   2119 }
   2120 
   2121 bool TextureD3D_2DArray::isLevelComplete(int level) const
   2122 {
   2123     ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
   2124 
   2125     if (isImmutable())
   2126     {
   2127         return true;
   2128     }
   2129 
   2130     GLsizei width = getBaseLevelWidth();
   2131     GLsizei height = getBaseLevelHeight();
   2132     GLsizei layers = getLayers(0);
   2133 
   2134     if (width <= 0 || height <= 0 || layers <= 0)
   2135     {
   2136         return false;
   2137     }
   2138 
   2139     if (level == 0)
   2140     {
   2141         return true;
   2142     }
   2143 
   2144     if (getInternalFormat(level) != getInternalFormat(0))
   2145     {
   2146         return false;
   2147     }
   2148 
   2149     if (getWidth(level) != std::max(1, width >> level))
   2150     {
   2151         return false;
   2152     }
   2153 
   2154     if (getHeight(level) != std::max(1, height >> level))
   2155     {
   2156         return false;
   2157     }
   2158 
   2159     if (getLayers(level) != layers)
   2160     {
   2161         return false;
   2162     }
   2163 
   2164     return true;
   2165 }
   2166 
   2167 void TextureD3D_2DArray::updateStorageLevel(int level)
   2168 {
   2169     ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
   2170     ASSERT(isLevelComplete(level));
   2171 
   2172     for (int layer = 0; layer < mLayerCounts[level]; layer++)
   2173     {
   2174         ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
   2175         if (mImageArray[level][layer]->isDirty())
   2176         {
   2177             commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
   2178         }
   2179     }
   2180 }
   2181 
   2182 void TextureD3D_2DArray::deleteImages()
   2183 {
   2184     for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
   2185     {
   2186         for (int layer = 0; layer < mLayerCounts[level]; ++layer)
   2187         {
   2188             delete mImageArray[level][layer];
   2189         }
   2190         delete[] mImageArray[level];
   2191         mImageArray[level] = NULL;
   2192         mLayerCounts[level] = 0;
   2193     }
   2194 }
   2195 
   2196 void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
   2197 {
   2198     // If there currently is a corresponding storage texture image, it has these parameters
   2199     const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
   2200     const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
   2201     const int storageDepth = getLayers(0);
   2202     const GLenum storageFormat = getBaseLevelInternalFormat();
   2203 
   2204     for (int layer = 0; layer < mLayerCounts[level]; layer++)
   2205     {
   2206         delete mImageArray[level][layer];
   2207     }
   2208     delete[] mImageArray[level];
   2209     mImageArray[level] = NULL;
   2210     mLayerCounts[level] = depth;
   2211 
   2212     if (depth > 0)
   2213     {
   2214         mImageArray[level] = new ImageD3D*[depth]();
   2215 
   2216         for (int layer = 0; layer < mLayerCounts[level]; layer++)
   2217         {
   2218             mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
   2219             mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
   2220         }
   2221     }
   2222 
   2223     if (mTexStorage)
   2224     {
   2225         const int storageLevels = mTexStorage->getLevelCount();
   2226 
   2227         if ((level >= storageLevels && storageLevels != 0) ||
   2228             width != storageWidth ||
   2229             height != storageHeight ||
   2230             depth != storageDepth ||
   2231             internalformat != storageFormat)   // Discard mismatched storage
   2232         {
   2233             for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
   2234             {
   2235                 for (int layer = 0; layer < mLayerCounts[level]; layer++)
   2236                 {
   2237                     mImageArray[level][layer]->markDirty();
   2238                 }
   2239             }
   2240 
   2241             delete mTexStorage;
   2242             mTexStorage = NULL;
   2243             mDirtyImages = true;
   2244         }
   2245     }
   2246 }
   2247 
   2248 void TextureD3D_2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
   2249 {
   2250     if (isValidLevel(level) && layerTarget < getLayers(level))
   2251     {
   2252         ImageD3D *image = mImageArray[level][layerTarget];
   2253         if (image->copyToStorage2DArray(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
   2254         {
   2255             image->markClean();
   2256         }
   2257     }
   2258 }
   2259 
   2260 }
   2261