tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TextureD3D.cpp (178360B)


      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 "libANGLE/renderer/d3d/TextureD3D.h"
     10 
     11 #include "common/mathutil.h"
     12 #include "common/utilities.h"
     13 #include "libANGLE/Buffer.h"
     14 #include "libANGLE/Config.h"
     15 #include "libANGLE/Context.h"
     16 #include "libANGLE/Framebuffer.h"
     17 #include "libANGLE/Image.h"
     18 #include "libANGLE/Surface.h"
     19 #include "libANGLE/Texture.h"
     20 #include "libANGLE/formatutils.h"
     21 #include "libANGLE/renderer/BufferImpl.h"
     22 #include "libANGLE/renderer/d3d/BufferD3D.h"
     23 #include "libANGLE/renderer/d3d/ContextD3D.h"
     24 #include "libANGLE/renderer/d3d/EGLImageD3D.h"
     25 #include "libANGLE/renderer/d3d/ImageD3D.h"
     26 #include "libANGLE/renderer/d3d/RenderTargetD3D.h"
     27 #include "libANGLE/renderer/d3d/SurfaceD3D.h"
     28 #include "libANGLE/renderer/d3d/TextureStorage.h"
     29 
     30 namespace rx
     31 {
     32 
     33 namespace
     34 {
     35 
     36 angle::Result GetUnpackPointer(const gl::Context *context,
     37                               const gl::PixelUnpackState &unpack,
     38                               gl::Buffer *unpackBuffer,
     39                               const uint8_t *pixels,
     40                               ptrdiff_t layerOffset,
     41                               const uint8_t **pointerOut)
     42 {
     43    if (unpackBuffer)
     44    {
     45        // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not
     46        // supported
     47        ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
     48 
     49        // TODO: this is the only place outside of renderer that asks for a buffers raw data.
     50        // This functionality should be moved into renderer and the getData method of BufferImpl
     51        // removed.
     52        BufferD3D *bufferD3D = GetImplAs<BufferD3D>(unpackBuffer);
     53        ASSERT(bufferD3D);
     54        const uint8_t *bufferData = nullptr;
     55        ANGLE_TRY(bufferD3D->getData(context, &bufferData));
     56        *pointerOut = bufferData + offset;
     57    }
     58    else
     59    {
     60        *pointerOut = pixels;
     61    }
     62 
     63    // Offset the pointer for 2D array layer (if it's valid)
     64    if (*pointerOut != nullptr)
     65    {
     66        *pointerOut += layerOffset;
     67    }
     68 
     69    return angle::Result::Continue;
     70 }
     71 
     72 bool IsRenderTargetUsage(GLenum usage)
     73 {
     74    return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
     75 }
     76 }  // namespace
     77 
     78 TextureD3D::TextureD3D(const gl::TextureState &state, RendererD3D *renderer)
     79    : TextureImpl(state),
     80      mRenderer(renderer),
     81      mDirtyImages(true),
     82      mImmutable(false),
     83      mTexStorage(nullptr),
     84      mTexStorageObserverBinding(this, kTextureStorageObserverMessageIndex),
     85      mBaseLevel(0)
     86 {}
     87 
     88 TextureD3D::~TextureD3D()
     89 {
     90    ASSERT(!mTexStorage);
     91 }
     92 
     93 angle::Result TextureD3D::getNativeTexture(const gl::Context *context, TextureStorage **outStorage)
     94 {
     95    // ensure the underlying texture is created
     96    ANGLE_TRY(initializeStorage(context, BindFlags()));
     97 
     98    if (mTexStorage)
     99    {
    100        ANGLE_TRY(updateStorage(context));
    101    }
    102 
    103    ASSERT(outStorage);
    104 
    105    *outStorage = mTexStorage;
    106    return angle::Result::Continue;
    107 }
    108 
    109 angle::Result TextureD3D::getImageAndSyncFromStorage(const gl::Context *context,
    110                                                     const gl::ImageIndex &index,
    111                                                     ImageD3D **outImage)
    112 {
    113    ImageD3D *image = getImage(index);
    114    if (mTexStorage && mTexStorage->isRenderTarget())
    115    {
    116        ANGLE_TRY(image->copyFromTexStorage(context, index, mTexStorage));
    117        mDirtyImages = true;
    118    }
    119    image->markClean();
    120    *outImage = image;
    121    return angle::Result::Continue;
    122 }
    123 
    124 GLint TextureD3D::getLevelZeroWidth() const
    125 {
    126    ASSERT(gl::CountLeadingZeros(static_cast<uint32_t>(getBaseLevelWidth())) > getBaseLevel());
    127    return getBaseLevelWidth() << mBaseLevel;
    128 }
    129 
    130 GLint TextureD3D::getLevelZeroHeight() const
    131 {
    132    ASSERT(gl::CountLeadingZeros(static_cast<uint32_t>(getBaseLevelHeight())) > getBaseLevel());
    133    return getBaseLevelHeight() << mBaseLevel;
    134 }
    135 
    136 GLint TextureD3D::getLevelZeroDepth() const
    137 {
    138    return getBaseLevelDepth();
    139 }
    140 
    141 GLint TextureD3D::getBaseLevelWidth() const
    142 {
    143    const ImageD3D *baseImage = getBaseLevelImage();
    144    return (baseImage ? baseImage->getWidth() : 0);
    145 }
    146 
    147 GLint TextureD3D::getBaseLevelHeight() const
    148 {
    149    const ImageD3D *baseImage = getBaseLevelImage();
    150    return (baseImage ? baseImage->getHeight() : 0);
    151 }
    152 
    153 GLint TextureD3D::getBaseLevelDepth() const
    154 {
    155    const ImageD3D *baseImage = getBaseLevelImage();
    156    return (baseImage ? baseImage->getDepth() : 0);
    157 }
    158 
    159 // Note: "base level image" is loosely defined to be any image from the base level,
    160 // where in the base of 2D array textures and cube maps there are several. Don't use
    161 // the base level image for anything except querying texture format and size.
    162 GLenum TextureD3D::getBaseLevelInternalFormat() const
    163 {
    164    const ImageD3D *baseImage = getBaseLevelImage();
    165    return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
    166 }
    167 
    168 angle::Result TextureD3D::setStorage(const gl::Context *context,
    169                                     gl::TextureType type,
    170                                     size_t levels,
    171                                     GLenum internalFormat,
    172                                     const gl::Extents &size)
    173 {
    174    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
    175    return angle::Result::Continue;
    176 }
    177 
    178 angle::Result TextureD3D::setStorageMultisample(const gl::Context *context,
    179                                                gl::TextureType type,
    180                                                GLsizei samples,
    181                                                GLint internalformat,
    182                                                const gl::Extents &size,
    183                                                bool fixedSampleLocations)
    184 {
    185    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
    186    return angle::Result::Continue;
    187 }
    188 
    189 angle::Result TextureD3D::setBuffer(const gl::Context *context, GLenum internalFormat)
    190 {
    191    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
    192    return angle::Result::Continue;
    193 }
    194 
    195 angle::Result TextureD3D::setStorageExternalMemory(const gl::Context *context,
    196                                                   gl::TextureType type,
    197                                                   size_t levels,
    198                                                   GLenum internalFormat,
    199                                                   const gl::Extents &size,
    200                                                   gl::MemoryObject *memoryObject,
    201                                                   GLuint64 offset,
    202                                                   GLbitfield createFlags,
    203                                                   GLbitfield usageFlags,
    204                                                   const void *imageCreateInfoPNext)
    205 {
    206    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
    207    return angle::Result::Continue;
    208 }
    209 
    210 bool TextureD3D::couldUseSetData() const
    211 {
    212    if (!mRenderer->getFeatures().setDataFasterThanImageUpload.enabled)
    213    {
    214        return false;
    215    }
    216 
    217    if (!mRenderer->getFeatures().setDataFasterThanImageUploadOn128bitFormats.enabled)
    218    {
    219        gl::InternalFormat internalFormat =
    220            gl::GetSizedInternalFormatInfo(getBaseLevelInternalFormat());
    221        return internalFormat.pixelBytes < 16;
    222    }
    223 
    224    return true;
    225 }
    226 
    227 bool TextureD3D::shouldUseSetData(const ImageD3D *image) const
    228 {
    229    if (!couldUseSetData())
    230    {
    231        return false;
    232    }
    233 
    234    if (image->isDirty())
    235    {
    236        return false;
    237    }
    238 
    239    gl::InternalFormat internalFormat = gl::GetSizedInternalFormatInfo(image->getInternalFormat());
    240 
    241    // We can only handle full updates for depth-stencil textures, so to avoid complications
    242    // disable them entirely.
    243    if (internalFormat.depthBits > 0 || internalFormat.stencilBits > 0)
    244    {
    245        return false;
    246    }
    247 
    248    // TODO(jmadill): Handle compressed internal formats
    249    return (mTexStorage && !internalFormat.compressed);
    250 }
    251 
    252 angle::Result TextureD3D::setImageImpl(const gl::Context *context,
    253                                       const gl::ImageIndex &index,
    254                                       GLenum type,
    255                                       const gl::PixelUnpackState &unpack,
    256                                       gl::Buffer *unpackBuffer,
    257                                       const uint8_t *pixels,
    258                                       ptrdiff_t layerOffset)
    259 {
    260    ImageD3D *image = getImage(index);
    261    ASSERT(image);
    262 
    263    // No-op
    264    if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
    265    {
    266        return angle::Result::Continue;
    267    }
    268 
    269    // We no longer need the "GLenum format" parameter to TexImage to determine what data format
    270    // "pixels" contains. From our image internal format we know how many channels to expect, and
    271    // "type" gives the format of pixel's components.
    272    const uint8_t *pixelData = nullptr;
    273    ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData));
    274 
    275    if (pixelData != nullptr)
    276    {
    277        if (shouldUseSetData(image))
    278        {
    279            ANGLE_TRY(
    280                mTexStorage->setData(context, index, image, nullptr, type, unpack, pixelData));
    281        }
    282        else
    283        {
    284            gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(),
    285                                  image->getDepth());
    286            ANGLE_TRY(image->loadData(context, fullImageArea, unpack, type, pixelData,
    287                                      index.usesTex3D()));
    288        }
    289 
    290        mDirtyImages = true;
    291    }
    292 
    293    return angle::Result::Continue;
    294 }
    295 
    296 angle::Result TextureD3D::subImage(const gl::Context *context,
    297                                   const gl::ImageIndex &index,
    298                                   const gl::Box &area,
    299                                   GLenum format,
    300                                   GLenum type,
    301                                   const gl::PixelUnpackState &unpack,
    302                                   gl::Buffer *unpackBuffer,
    303                                   const uint8_t *pixels,
    304                                   ptrdiff_t layerOffset)
    305 {
    306    // CPU readback & copy where direct GPU copy is not supported
    307    const uint8_t *pixelData = nullptr;
    308    ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData));
    309 
    310    if (pixelData != nullptr)
    311    {
    312        ImageD3D *image = getImage(index);
    313        ASSERT(image);
    314 
    315        if (shouldUseSetData(image))
    316        {
    317            return mTexStorage->setData(context, index, image, &area, type, unpack, pixelData);
    318        }
    319 
    320        ANGLE_TRY(image->loadData(context, area, unpack, type, pixelData, index.usesTex3D()));
    321        ANGLE_TRY(commitRegion(context, index, area));
    322        mDirtyImages = true;
    323    }
    324 
    325    return angle::Result::Continue;
    326 }
    327 
    328 angle::Result TextureD3D::setCompressedImageImpl(const gl::Context *context,
    329                                                 const gl::ImageIndex &index,
    330                                                 const gl::PixelUnpackState &unpack,
    331                                                 const uint8_t *pixels,
    332                                                 ptrdiff_t layerOffset)
    333 {
    334    ImageD3D *image = getImage(index);
    335    ASSERT(image);
    336 
    337    if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
    338    {
    339        return angle::Result::Continue;
    340    }
    341 
    342    // We no longer need the "GLenum format" parameter to TexImage to determine what data format
    343    // "pixels" contains. From our image internal format we know how many channels to expect, and
    344    // "type" gives the format of pixel's components.
    345    const uint8_t *pixelData = nullptr;
    346    gl::Buffer *unpackBuffer = context->getState().getTargetBuffer(gl::BufferBinding::PixelUnpack);
    347    ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData));
    348 
    349    if (pixelData != nullptr)
    350    {
    351        gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth());
    352        ANGLE_TRY(image->loadCompressedData(context, fullImageArea, pixelData));
    353 
    354        mDirtyImages = true;
    355    }
    356 
    357    return angle::Result::Continue;
    358 }
    359 
    360 angle::Result TextureD3D::subImageCompressed(const gl::Context *context,
    361                                             const gl::ImageIndex &index,
    362                                             const gl::Box &area,
    363                                             GLenum format,
    364                                             const gl::PixelUnpackState &unpack,
    365                                             const uint8_t *pixels,
    366                                             ptrdiff_t layerOffset)
    367 {
    368    const uint8_t *pixelData = nullptr;
    369    gl::Buffer *unpackBuffer = context->getState().getTargetBuffer(gl::BufferBinding::PixelUnpack);
    370    ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData));
    371 
    372    if (pixelData != nullptr)
    373    {
    374        ImageD3D *image = getImage(index);
    375        ASSERT(image);
    376 
    377        ANGLE_TRY(image->loadCompressedData(context, area, pixelData));
    378 
    379        mDirtyImages = true;
    380    }
    381 
    382    return angle::Result::Continue;
    383 }
    384 
    385 bool TextureD3D::isFastUnpackable(const gl::Buffer *unpackBuffer,
    386                                  const gl::PixelUnpackState &unpack,
    387                                  GLenum sizedInternalFormat)
    388 {
    389    return unpackBuffer != nullptr && unpack.skipRows == 0 && unpack.skipPixels == 0 &&
    390           unpack.imageHeight == 0 && unpack.skipImages == 0 &&
    391           mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
    392 }
    393 
    394 angle::Result TextureD3D::fastUnpackPixels(const gl::Context *context,
    395                                           const gl::PixelUnpackState &unpack,
    396                                           gl::Buffer *unpackBuffer,
    397                                           const uint8_t *pixels,
    398                                           const gl::Box &destArea,
    399                                           GLenum sizedInternalFormat,
    400                                           GLenum type,
    401                                           RenderTargetD3D *destRenderTarget)
    402 {
    403    bool check = (unpack.skipRows != 0 || unpack.skipPixels != 0 || unpack.imageHeight != 0 ||
    404                  unpack.skipImages != 0);
    405    ANGLE_CHECK(GetImplAs<ContextD3D>(context), !check,
    406                "Unimplemented pixel store parameters in fastUnpackPixels", GL_INVALID_OPERATION);
    407 
    408    // No-op
    409    if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
    410    {
    411        return angle::Result::Continue;
    412    }
    413 
    414    // In order to perform the fast copy through the shader, we must have the right format, and be
    415    // able to create a render target.
    416    ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
    417 
    418    uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
    419 
    420    ANGLE_TRY(mRenderer->fastCopyBufferToTexture(
    421        context, unpack, unpackBuffer, static_cast<unsigned int>(offset), destRenderTarget,
    422        sizedInternalFormat, type, destArea));
    423 
    424    return angle::Result::Continue;
    425 }
    426 
    427 GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
    428 {
    429    if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) ||
    430        mRenderer->getNativeExtensions().textureNpotOES)
    431    {
    432        // Maximum number of levels
    433        return gl::log2(std::max(std::max(width, height), depth)) + 1;
    434    }
    435    else
    436    {
    437        // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
    438        return 1;
    439    }
    440 }
    441 
    442 TextureStorage *TextureD3D::getStorage()
    443 {
    444    ASSERT(mTexStorage);
    445    return mTexStorage;
    446 }
    447 
    448 ImageD3D *TextureD3D::getBaseLevelImage() const
    449 {
    450    if (mBaseLevel >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
    451    {
    452        return nullptr;
    453    }
    454    return getImage(getImageIndex(mBaseLevel, 0));
    455 }
    456 
    457 angle::Result TextureD3D::setImageExternal(const gl::Context *context,
    458                                           gl::TextureType type,
    459                                           egl::Stream *stream,
    460                                           const egl::Stream::GLTextureDescription &desc)
    461 {
    462    // Only external images can accept external textures
    463    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
    464    return angle::Result::Continue;
    465 }
    466 
    467 angle::Result TextureD3D::generateMipmap(const gl::Context *context)
    468 {
    469    const GLuint baseLevel = mState.getEffectiveBaseLevel();
    470    const GLuint maxLevel  = mState.getMipmapMaxLevel();
    471    ASSERT(maxLevel > baseLevel);  // Should be checked before calling this.
    472 
    473    if (mTexStorage && mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
    474    {
    475        // Switch to using the mipmapped texture.
    476        TextureStorage *textureStorageEXT = nullptr;
    477        ANGLE_TRY(getNativeTexture(context, &textureStorageEXT));
    478        ANGLE_TRY(textureStorageEXT->useLevelZeroWorkaroundTexture(context, false));
    479    }
    480 
    481    // Set up proper mipmap chain in our Image array.
    482    ANGLE_TRY(initMipmapImages(context));
    483 
    484    if (mTexStorage && mTexStorage->supportsNativeMipmapFunction())
    485    {
    486        ANGLE_TRY(updateStorage(context));
    487 
    488        // Generate the mipmap chain using the ad-hoc DirectX function.
    489        ANGLE_TRY(mRenderer->generateMipmapUsingD3D(context, mTexStorage, mState));
    490    }
    491    else
    492    {
    493        // Generate the mipmap chain, one level at a time.
    494        ANGLE_TRY(generateMipmapUsingImages(context, maxLevel));
    495    }
    496 
    497    return angle::Result::Continue;
    498 }
    499 
    500 angle::Result TextureD3D::generateMipmapUsingImages(const gl::Context *context,
    501                                                    const GLuint maxLevel)
    502 {
    503    // We know that all layers have the same dimension, for the texture to be complete
    504    GLint layerCount = static_cast<GLint>(getLayerCount(mBaseLevel));
    505 
    506    if (mTexStorage && !mTexStorage->isRenderTarget() &&
    507        canCreateRenderTargetForImage(getImageIndex(mBaseLevel, 0)) &&
    508        mRenderer->getRendererClass() == RENDERER_D3D11)
    509    {
    510        if (!mRenderer->getFeatures().setDataFasterThanImageUpload.enabled)
    511        {
    512            ANGLE_TRY(updateStorage(context));
    513        }
    514        ANGLE_TRY(ensureRenderTarget(context));
    515    }
    516    else if (couldUseSetData() && mTexStorage)
    517    {
    518        // When making mipmaps with the setData workaround enabled, the texture storage has
    519        // the image data already. For non-render-target storage, we have to pull it out into
    520        // an image layer.
    521        if (!mTexStorage->isRenderTarget())
    522        {
    523            // Copy from the storage mip 0 to Image mip 0
    524            for (GLint layer = 0; layer < layerCount; ++layer)
    525            {
    526                gl::ImageIndex srcIndex = getImageIndex(mBaseLevel, layer);
    527 
    528                ImageD3D *image = getImage(srcIndex);
    529                ANGLE_TRY(image->copyFromTexStorage(context, srcIndex, mTexStorage));
    530            }
    531        }
    532        else
    533        {
    534            ANGLE_TRY(updateStorage(context));
    535        }
    536    }
    537 
    538    // TODO: Decouple this from zeroMaxLodWorkaround. This is a 9_3 restriction, unrelated to
    539    // zeroMaxLodWorkaround. The restriction is because Feature Level 9_3 can't create SRVs on
    540    // individual levels of the texture. As a result, even if the storage is a rendertarget, we
    541    // can't use the GPU to generate the mipmaps without further work. The D3D9 renderer works
    542    // around this by copying each level of the texture into its own single-layer GPU texture (in
    543    // Blit9::boxFilter). Feature Level 9_3 could do something similar, or it could continue to use
    544    // CPU-side mipmap generation, or something else.
    545    bool renderableStorage = (mTexStorage && mTexStorage->isRenderTarget() &&
    546                              !(mRenderer->getFeatures().zeroMaxLodWorkaround.enabled));
    547    if (renderableStorage)
    548    {
    549        ANGLE_TRY(updateStorage(context));
    550    }
    551 
    552    for (GLint layer = 0; layer < layerCount; ++layer)
    553    {
    554        for (GLuint mip = mBaseLevel + 1; mip <= maxLevel; ++mip)
    555        {
    556            ASSERT(getLayerCount(mip) == layerCount);
    557 
    558            gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
    559            gl::ImageIndex destIndex   = getImageIndex(mip, layer);
    560 
    561            if (renderableStorage)
    562            {
    563                // GPU-side mipmapping
    564                ANGLE_TRY(mTexStorage->generateMipmap(context, sourceIndex, destIndex));
    565            }
    566            else
    567            {
    568                // CPU-side mipmapping
    569                ANGLE_TRY(
    570                    mRenderer->generateMipmap(context, getImage(destIndex), getImage(sourceIndex)));
    571            }
    572        }
    573    }
    574 
    575    mDirtyImages = !renderableStorage;
    576 
    577    if (mTexStorage && mDirtyImages)
    578    {
    579        ANGLE_TRY(updateStorage(context));
    580    }
    581 
    582    return angle::Result::Continue;
    583 }
    584 
    585 bool TextureD3D::isBaseImageZeroSize() const
    586 {
    587    ImageD3D *baseImage = getBaseLevelImage();
    588 
    589    if (!baseImage || baseImage->getWidth() <= 0 || baseImage->getHeight() <= 0)
    590    {
    591        return true;
    592    }
    593 
    594    if (baseImage->getType() == gl::TextureType::_3D && baseImage->getDepth() <= 0)
    595    {
    596        return true;
    597    }
    598 
    599    if (baseImage->getType() == gl::TextureType::_2DArray && getLayerCount(getBaseLevel()) <= 0)
    600    {
    601        return true;
    602    }
    603 
    604    return false;
    605 }
    606 
    607 angle::Result TextureD3D::ensureBindFlags(const gl::Context *context, BindFlags bindFlags)
    608 {
    609    ANGLE_TRY(initializeStorage(context, bindFlags));
    610 
    611    // initializeStorage can fail with NoError if the texture is not complete. This is not
    612    // an error for incomplete sampling, but it is a big problem for rendering.
    613    if (!mTexStorage)
    614    {
    615        ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
    616        return angle::Result::Stop;
    617    }
    618 
    619    if (!isBaseImageZeroSize())
    620    {
    621        ASSERT(mTexStorage);
    622        if ((bindFlags.renderTarget && !mTexStorage->isRenderTarget()) ||
    623            (bindFlags.unorderedAccess && !mTexStorage->isUnorderedAccess()))
    624        {
    625            TexStoragePointer newRenderTargetStorage;
    626            ANGLE_TRY(createCompleteStorage(context, bindFlags, &newRenderTargetStorage));
    627 
    628            ANGLE_TRY(mTexStorage->copyToStorage(context, newRenderTargetStorage.get()));
    629            ANGLE_TRY(setCompleteTexStorage(context, newRenderTargetStorage.get()));
    630            newRenderTargetStorage.release();
    631            // If this texture is used in compute shader, we should invalidate this texture so that
    632            // the UAV/SRV is rebound again with this new texture storage in next dispatch call.
    633            mTexStorage->invalidateTextures();
    634        }
    635    }
    636 
    637    return angle::Result::Continue;
    638 }
    639 
    640 angle::Result TextureD3D::ensureRenderTarget(const gl::Context *context)
    641 {
    642    return ensureBindFlags(context, BindFlags::RenderTarget());
    643 }
    644 
    645 angle::Result TextureD3D::ensureUnorderedAccess(const gl::Context *context)
    646 {
    647    return ensureBindFlags(context, BindFlags::UnorderedAccess());
    648 }
    649 
    650 bool TextureD3D::canCreateRenderTargetForImage(const gl::ImageIndex &index) const
    651 {
    652    if (index.getType() == gl::TextureType::_2DMultisample ||
    653        index.getType() == gl::TextureType::_2DMultisampleArray)
    654    {
    655        ASSERT(index.getType() != gl::TextureType::_2DMultisampleArray || index.hasLayer());
    656        return true;
    657    }
    658 
    659    ImageD3D *image = getImage(index);
    660    ASSERT(image);
    661    bool levelsComplete = (isImageComplete(index) && isImageComplete(getImageIndex(0, 0)));
    662    return (image->isRenderableFormat() && levelsComplete);
    663 }
    664 
    665 angle::Result TextureD3D::commitRegion(const gl::Context *context,
    666                                       const gl::ImageIndex &index,
    667                                       const gl::Box &region)
    668 {
    669    if (mTexStorage)
    670    {
    671        ASSERT(isValidIndex(index));
    672        ImageD3D *image = getImage(index);
    673        ANGLE_TRY(image->copyToStorage(context, mTexStorage, index, region));
    674        image->markClean();
    675    }
    676 
    677    return angle::Result::Continue;
    678 }
    679 
    680 angle::Result TextureD3D::getAttachmentRenderTarget(const gl::Context *context,
    681                                                    GLenum binding,
    682                                                    const gl::ImageIndex &imageIndex,
    683                                                    GLsizei samples,
    684                                                    FramebufferAttachmentRenderTarget **rtOut)
    685 {
    686    RenderTargetD3D *rtD3D = nullptr;
    687    ANGLE_TRY(getRenderTarget(context, imageIndex, samples, &rtD3D));
    688    *rtOut = static_cast<FramebufferAttachmentRenderTarget *>(rtD3D);
    689    return angle::Result::Continue;
    690 }
    691 
    692 angle::Result TextureD3D::setBaseLevel(const gl::Context *context, GLuint baseLevel)
    693 {
    694    const int oldStorageWidth  = std::max(1, getLevelZeroWidth());
    695    const int oldStorageHeight = std::max(1, getLevelZeroHeight());
    696    const int oldStorageDepth  = std::max(1, getLevelZeroDepth());
    697    const int oldStorageFormat = getBaseLevelInternalFormat();
    698    mBaseLevel                 = baseLevel;
    699 
    700    // When the base level changes, the texture storage might not be valid anymore, since it could
    701    // have been created based on the dimensions of the previous specified level range.
    702    const int newStorageWidth  = std::max(1, getLevelZeroWidth());
    703    const int newStorageHeight = std::max(1, getLevelZeroHeight());
    704    const int newStorageDepth  = std::max(1, getLevelZeroDepth());
    705    const int newStorageFormat = getBaseLevelInternalFormat();
    706    if (mTexStorage &&
    707        (newStorageWidth != oldStorageWidth || newStorageHeight != oldStorageHeight ||
    708         newStorageDepth != oldStorageDepth || newStorageFormat != oldStorageFormat))
    709    {
    710        markAllImagesDirty();
    711 
    712        // Iterate over all images, and backup the content if it's been used as a render target. The
    713        // D3D11 backend can automatically restore images on storage destroy, but it only works for
    714        // images that have been associated with the texture storage before, which is insufficient
    715        // here.
    716        if (mTexStorage->isRenderTarget())
    717        {
    718            gl::ImageIndexIterator iterator = imageIterator();
    719            while (iterator.hasNext())
    720            {
    721                const gl::ImageIndex index    = iterator.next();
    722                const GLsizei samples         = getRenderToTextureSamples();
    723                RenderTargetD3D *renderTarget = nullptr;
    724                ANGLE_TRY(mTexStorage->findRenderTarget(context, index, samples, &renderTarget));
    725                if (renderTarget)
    726                {
    727                    ANGLE_TRY(getImage(index)->copyFromTexStorage(context, index, mTexStorage));
    728                }
    729            }
    730        }
    731 
    732        ANGLE_TRY(releaseTexStorage(context, gl::TexLevelMask()));
    733    }
    734 
    735    return angle::Result::Continue;
    736 }
    737 
    738 angle::Result TextureD3D::onLabelUpdate(const gl::Context *context)
    739 {
    740    if (mTexStorage)
    741    {
    742        mTexStorage->setLabel(mState.getLabel());
    743    }
    744    return angle::Result::Continue;
    745 }
    746 
    747 angle::Result TextureD3D::syncState(const gl::Context *context,
    748                                    const gl::Texture::DirtyBits &dirtyBits,
    749                                    gl::Command source)
    750 {
    751    // This could be improved using dirty bits.
    752    return angle::Result::Continue;
    753 }
    754 
    755 angle::Result TextureD3D::releaseTexStorage(const gl::Context *context,
    756                                            const gl::TexLevelMask &copyStorageToImagesMask)
    757 {
    758    if (!mTexStorage)
    759    {
    760        return angle::Result::Continue;
    761    }
    762 
    763    if (mTexStorage->isRenderTarget())
    764    {
    765        const GLenum storageFormat = getBaseLevelInternalFormat();
    766        const size_t storageLevels = mTexStorage->getLevelCount();
    767 
    768        gl::ImageIndexIterator iterator = imageIterator();
    769        while (iterator.hasNext())
    770        {
    771            const gl::ImageIndex index = iterator.next();
    772            ImageD3D *image            = getImage(index);
    773            const int storageWidth     = std::max(1, getLevelZeroWidth() >> index.getLevelIndex());
    774            const int storageHeight    = std::max(1, getLevelZeroHeight() >> index.getLevelIndex());
    775            if (image && isImageComplete(index) && image->getWidth() == storageWidth &&
    776                image->getHeight() == storageHeight &&
    777                image->getInternalFormat() == storageFormat &&
    778                index.getLevelIndex() < static_cast<int>(storageLevels) &&
    779                copyStorageToImagesMask[index.getLevelIndex()])
    780            {
    781                ANGLE_TRY(image->copyFromTexStorage(context, index, mTexStorage));
    782            }
    783        }
    784    }
    785 
    786    onStateChange(angle::SubjectMessage::StorageReleased);
    787 
    788    auto err = mTexStorage->onDestroy(context);
    789    SafeDelete(mTexStorage);
    790    return err;
    791 }
    792 
    793 void TextureD3D::onDestroy(const gl::Context *context)
    794 {
    795    (void)releaseTexStorage(context, gl::TexLevelMask());
    796 }
    797 
    798 angle::Result TextureD3D::initializeContents(const gl::Context *context,
    799                                             GLenum binding,
    800                                             const gl::ImageIndex &imageIndex)
    801 {
    802    ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
    803    gl::ImageIndex index   = imageIndex;
    804 
    805    // Special case for D3D11 3D textures. We can't create render targets for individual layers of a
    806    // 3D texture, so force the clear to the entire mip. There shouldn't ever be a case where we
    807    // would lose existing data.
    808    if (index.getType() == gl::TextureType::_3D)
    809    {
    810        index = gl::ImageIndex::Make3D(index.getLevelIndex(), gl::ImageIndex::kEntireLevel);
    811    }
    812    else if (index.getType() == gl::TextureType::_2DArray && !index.hasLayer())
    813    {
    814        std::array<GLint, gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS> tempLayerCounts;
    815 
    816        GLint levelIndex            = index.getLevelIndex();
    817        tempLayerCounts[levelIndex] = getLayerCount(levelIndex);
    818        gl::ImageIndexIterator iterator =
    819            gl::ImageIndexIterator::Make2DArray(levelIndex, levelIndex + 1, tempLayerCounts.data());
    820        while (iterator.hasNext())
    821        {
    822            ANGLE_TRY(initializeContents(context, GL_NONE, iterator.next()));
    823        }
    824        return angle::Result::Continue;
    825    }
    826    else if (index.getType() == gl::TextureType::_2DMultisampleArray && !index.hasLayer())
    827    {
    828        std::array<GLint, gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS> tempLayerCounts;
    829 
    830        ASSERT(index.getLevelIndex() == 0);
    831        tempLayerCounts[0] = getLayerCount(0);
    832        gl::ImageIndexIterator iterator =
    833            gl::ImageIndexIterator::Make2DMultisampleArray(tempLayerCounts.data());
    834        while (iterator.hasNext())
    835        {
    836            ANGLE_TRY(initializeContents(context, GL_NONE, iterator.next()));
    837        }
    838        return angle::Result::Continue;
    839    }
    840 
    841    // Force image clean.
    842    ImageD3D *image = getImage(index);
    843    if (image)
    844    {
    845        image->markClean();
    846    }
    847 
    848    // Fast path: can use a render target clear.
    849    // We don't use the fast path with the zero max lod workaround because it would introduce a race
    850    // between the rendertarget and the staging images.
    851    const angle::FeaturesD3D &features = mRenderer->getFeatures();
    852    bool shouldUseClear                = (image == nullptr);
    853    if (canCreateRenderTargetForImage(index) && !features.zeroMaxLodWorkaround.enabled &&
    854        (shouldUseClear || features.allowClearForRobustResourceInit.enabled))
    855    {
    856        ANGLE_TRY(ensureRenderTarget(context));
    857        ASSERT(mTexStorage);
    858        RenderTargetD3D *renderTarget = nullptr;
    859        ANGLE_TRY(mTexStorage->getRenderTarget(context, index, 0, &renderTarget));
    860        ANGLE_TRY(mRenderer->initRenderTarget(context, renderTarget));
    861 
    862        // Force image clean again, the texture storage may have been re-created and the image used.
    863        if (image)
    864        {
    865            image->markClean();
    866        }
    867 
    868        return angle::Result::Continue;
    869    }
    870 
    871    ASSERT(image != nullptr);
    872 
    873    // Slow path: non-renderable texture or the texture levels aren't set up.
    874    const auto &formatInfo = gl::GetSizedInternalFormatInfo(image->getInternalFormat());
    875 
    876    GLuint imageBytes = 0;
    877    ANGLE_CHECK_GL_MATH(contextD3D, formatInfo.computeRowPitch(formatInfo.type, image->getWidth(),
    878                                                               1, 0, &imageBytes));
    879    imageBytes *= image->getHeight() * image->getDepth();
    880 
    881    gl::PixelUnpackState zeroDataUnpackState;
    882    zeroDataUnpackState.alignment = 1;
    883 
    884    angle::MemoryBuffer *zeroBuffer = nullptr;
    885    ANGLE_CHECK_GL_ALLOC(contextD3D, context->getZeroFilledBuffer(imageBytes, &zeroBuffer));
    886 
    887    if (shouldUseSetData(image))
    888    {
    889        ANGLE_TRY(mTexStorage->setData(context, index, image, nullptr, formatInfo.type,
    890                                       zeroDataUnpackState, zeroBuffer->data()));
    891    }
    892    else
    893    {
    894        gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth());
    895        ANGLE_TRY(image->loadData(context, fullImageArea, zeroDataUnpackState, formatInfo.type,
    896                                  zeroBuffer->data(), false));
    897 
    898        // Force an update to the tex storage so we avoid problems with subImage and dirty regions.
    899        if (mTexStorage)
    900        {
    901            ANGLE_TRY(commitRegion(context, index, fullImageArea));
    902            image->markClean();
    903        }
    904        else
    905        {
    906            mDirtyImages = true;
    907        }
    908    }
    909    return angle::Result::Continue;
    910 }
    911 
    912 GLsizei TextureD3D::getRenderToTextureSamples()
    913 {
    914    if (mTexStorage)
    915    {
    916        return mTexStorage->getRenderToTextureSamples();
    917    }
    918    return 0;
    919 }
    920 
    921 void TextureD3D::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
    922 {
    923    onStateChange(message);
    924 }
    925 
    926 TextureD3D_2D::TextureD3D_2D(const gl::TextureState &state, RendererD3D *renderer)
    927    : TextureD3D(state, renderer)
    928 {
    929    mEGLImageTarget = false;
    930    for (auto &image : mImageArray)
    931    {
    932        image.reset(renderer->createImage());
    933    }
    934 }
    935 
    936 void TextureD3D_2D::onDestroy(const gl::Context *context)
    937 {
    938    // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage
    939    // for some of their data. If TextureStorage is deleted before the Images, then their data will
    940    // be wastefully copied back from the GPU before we delete the Images.
    941    for (auto &image : mImageArray)
    942    {
    943        image.reset();
    944    }
    945    return TextureD3D::onDestroy(context);
    946 }
    947 
    948 TextureD3D_2D::~TextureD3D_2D() {}
    949 
    950 ImageD3D *TextureD3D_2D::getImage(int level, int layer) const
    951 {
    952    ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
    953    ASSERT(layer == 0);
    954    return mImageArray[level].get();
    955 }
    956 
    957 ImageD3D *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
    958 {
    959    ASSERT(index.getLevelIndex() < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
    960    ASSERT(!index.hasLayer());
    961    ASSERT(index.getType() == gl::TextureType::_2D ||
    962           index.getType() == gl::TextureType::VideoImage);
    963    return mImageArray[index.getLevelIndex()].get();
    964 }
    965 
    966 GLsizei TextureD3D_2D::getLayerCount(int level) const
    967 {
    968    ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
    969    return 1;
    970 }
    971 
    972 GLsizei TextureD3D_2D::getWidth(GLint level) const
    973 {
    974    if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
    975        return mImageArray[level]->getWidth();
    976    else
    977        return 0;
    978 }
    979 
    980 GLsizei TextureD3D_2D::getHeight(GLint level) const
    981 {
    982    if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
    983        return mImageArray[level]->getHeight();
    984    else
    985        return 0;
    986 }
    987 
    988 GLenum TextureD3D_2D::getInternalFormat(GLint level) const
    989 {
    990    if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
    991        return mImageArray[level]->getInternalFormat();
    992    else
    993        return GL_NONE;
    994 }
    995 
    996 bool TextureD3D_2D::isDepth(GLint level) const
    997 {
    998    return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
    999 }
   1000 
   1001 bool TextureD3D_2D::isSRGB(GLint level) const
   1002 {
   1003    return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).colorEncoding == GL_SRGB;
   1004 }
   1005 
   1006 angle::Result TextureD3D_2D::setImage(const gl::Context *context,
   1007                                      const gl::ImageIndex &index,
   1008                                      GLenum internalFormat,
   1009                                      const gl::Extents &size,
   1010                                      GLenum format,
   1011                                      GLenum type,
   1012                                      const gl::PixelUnpackState &unpack,
   1013                                      gl::Buffer *unpackBuffer,
   1014                                      const uint8_t *pixels)
   1015 {
   1016    ASSERT((index.getTarget() == gl::TextureTarget::_2D ||
   1017            index.getTarget() == gl::TextureTarget::VideoImage) &&
   1018           size.depth == 1);
   1019 
   1020    const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
   1021 
   1022    bool fastUnpacked = false;
   1023 
   1024    ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat,
   1025                            size, false));
   1026 
   1027    // Attempt a fast gpu copy of the pixel data to the surface
   1028    if (mTexStorage)
   1029    {
   1030        ANGLE_TRY(mTexStorage->releaseMultisampledTexStorageForLevel(index.getLevelIndex()));
   1031    }
   1032    if (isFastUnpackable(unpackBuffer, unpack, internalFormatInfo.sizedInternalFormat) &&
   1033        isLevelComplete(index.getLevelIndex()))
   1034    {
   1035        // Will try to create RT storage if it does not exist
   1036        RenderTargetD3D *destRenderTarget = nullptr;
   1037        ANGLE_TRY(getRenderTarget(context, index, getRenderToTextureSamples(), &destRenderTarget));
   1038 
   1039        gl::Box destArea(0, 0, 0, getWidth(index.getLevelIndex()), getHeight(index.getLevelIndex()),
   1040                         1);
   1041 
   1042        ANGLE_TRY(fastUnpackPixels(context, unpack, unpackBuffer, pixels, destArea,
   1043                                   internalFormatInfo.sizedInternalFormat, type, destRenderTarget));
   1044 
   1045        // Ensure we don't overwrite our newly initialized data
   1046        mImageArray[index.getLevelIndex()]->markClean();
   1047 
   1048        fastUnpacked = true;
   1049    }
   1050 
   1051    if (!fastUnpacked)
   1052    {
   1053        ANGLE_TRY(setImageImpl(context, index, type, unpack, unpackBuffer, pixels, 0));
   1054    }
   1055 
   1056    return angle::Result::Continue;
   1057 }
   1058 
   1059 angle::Result TextureD3D_2D::setSubImage(const gl::Context *context,
   1060                                         const gl::ImageIndex &index,
   1061                                         const gl::Box &area,
   1062                                         GLenum format,
   1063                                         GLenum type,
   1064                                         const gl::PixelUnpackState &unpack,
   1065                                         gl::Buffer *unpackBuffer,
   1066                                         const uint8_t *pixels)
   1067 {
   1068    ASSERT(index.getTarget() == gl::TextureTarget::_2D && area.depth == 1 && area.z == 0);
   1069 
   1070    GLenum mipFormat = getInternalFormat(index.getLevelIndex());
   1071    if (mTexStorage)
   1072    {
   1073        ANGLE_TRY(mTexStorage->releaseMultisampledTexStorageForLevel(index.getLevelIndex()));
   1074    }
   1075    if (isFastUnpackable(unpackBuffer, unpack, mipFormat) && isLevelComplete(index.getLevelIndex()))
   1076    {
   1077        RenderTargetD3D *renderTarget = nullptr;
   1078        ANGLE_TRY(getRenderTarget(context, index, getRenderToTextureSamples(), &renderTarget));
   1079        ASSERT(!mImageArray[index.getLevelIndex()]->isDirty());
   1080 
   1081        return fastUnpackPixels(context, unpack, unpackBuffer, pixels, area, mipFormat, type,
   1082                                renderTarget);
   1083    }
   1084    else
   1085    {
   1086        return TextureD3D::subImage(context, index, area, format, type, unpack, unpackBuffer,
   1087                                    pixels, 0);
   1088    }
   1089 }
   1090 
   1091 angle::Result TextureD3D_2D::setCompressedImage(const gl::Context *context,
   1092                                                const gl::ImageIndex &index,
   1093                                                GLenum internalFormat,
   1094                                                const gl::Extents &size,
   1095                                                const gl::PixelUnpackState &unpack,
   1096                                                size_t imageSize,
   1097                                                const uint8_t *pixels)
   1098 {
   1099    ASSERT(index.getTarget() == gl::TextureTarget::_2D && size.depth == 1);
   1100 
   1101    // compressed formats don't have separate sized internal formats-- we can just use the
   1102    // compressed format directly
   1103    ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormat, size, false));
   1104 
   1105    return setCompressedImageImpl(context, index, unpack, pixels, 0);
   1106 }
   1107 
   1108 angle::Result TextureD3D_2D::setCompressedSubImage(const gl::Context *context,
   1109                                                   const gl::ImageIndex &index,
   1110                                                   const gl::Box &area,
   1111                                                   GLenum format,
   1112                                                   const gl::PixelUnpackState &unpack,
   1113                                                   size_t imageSize,
   1114                                                   const uint8_t *pixels)
   1115 {
   1116    ASSERT(index.getTarget() == gl::TextureTarget::_2D && area.depth == 1 && area.z == 0);
   1117    ANGLE_TRY(TextureD3D::subImageCompressed(context, index, area, format, unpack, pixels, 0));
   1118 
   1119    return commitRegion(context, index, area);
   1120 }
   1121 
   1122 angle::Result TextureD3D_2D::copyImage(const gl::Context *context,
   1123                                       const gl::ImageIndex &index,
   1124                                       const gl::Rectangle &sourceArea,
   1125                                       GLenum internalFormat,
   1126                                       gl::Framebuffer *source)
   1127 {
   1128    ASSERT(index.getTarget() == gl::TextureTarget::_2D);
   1129 
   1130    const gl::InternalFormat &internalFormatInfo =
   1131        gl::GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE);
   1132    gl::Extents sourceExtents(sourceArea.width, sourceArea.height, 1);
   1133    ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat,
   1134                            sourceExtents, false));
   1135 
   1136    gl::Extents fbSize = source->getReadColorAttachment()->getSize();
   1137 
   1138    // Does the read area extend beyond the framebuffer?
   1139    bool outside = sourceArea.x < 0 || sourceArea.y < 0 ||
   1140                   sourceArea.x + sourceArea.width > fbSize.width ||
   1141                   sourceArea.y + sourceArea.height > fbSize.height;
   1142 
   1143    // WebGL requires that pixels that would be outside the framebuffer are treated as zero values,
   1144    // so clear the mip level to 0 prior to making the copy if any pixel would be sampled outside.
   1145    // Same thing for robust resource init.
   1146    if (outside && (context->isWebGL() || context->isRobustResourceInitEnabled()))
   1147    {
   1148        ANGLE_TRY(initializeContents(context, GL_NONE, index));
   1149    }
   1150 
   1151    gl::Rectangle clippedArea;
   1152    if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
   1153    {
   1154        // Empty source area, nothing to do.
   1155        return angle::Result::Continue;
   1156    }
   1157 
   1158    gl::Offset destOffset(clippedArea.x - sourceArea.x, clippedArea.y - sourceArea.y, 0);
   1159 
   1160    // If the zero max LOD workaround is active, then we can't sample from individual layers of the
   1161    // framebuffer in shaders, so we should use the non-rendering copy path.
   1162    if (!canCreateRenderTargetForImage(index) ||
   1163        mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
   1164    {
   1165        ANGLE_TRY(mImageArray[index.getLevelIndex()]->copyFromFramebuffer(context, destOffset,
   1166                                                                          clippedArea, source));
   1167        mDirtyImages = true;
   1168    }
   1169    else
   1170    {
   1171        ANGLE_TRY(ensureRenderTarget(context));
   1172 
   1173        if (clippedArea.width != 0 && clippedArea.height != 0 &&
   1174            isValidLevel(index.getLevelIndex()))
   1175        {
   1176            ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
   1177            ANGLE_TRY(mRenderer->copyImage2D(context, source, clippedArea, internalFormat,
   1178                                             destOffset, mTexStorage, index.getLevelIndex()));
   1179        }
   1180    }
   1181 
   1182    return angle::Result::Continue;
   1183 }
   1184 
   1185 angle::Result TextureD3D_2D::copySubImage(const gl::Context *context,
   1186                                          const gl::ImageIndex &index,
   1187                                          const gl::Offset &destOffset,
   1188                                          const gl::Rectangle &sourceArea,
   1189                                          gl::Framebuffer *source)
   1190 {
   1191    ASSERT(index.getTarget() == gl::TextureTarget::_2D && destOffset.z == 0);
   1192 
   1193    gl::Extents fbSize = source->getReadColorAttachment()->getSize();
   1194    gl::Rectangle clippedArea;
   1195    if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
   1196    {
   1197        return angle::Result::Continue;
   1198    }
   1199    const gl::Offset clippedOffset(destOffset.x + clippedArea.x - sourceArea.x,
   1200                                   destOffset.y + clippedArea.y - sourceArea.y, 0);
   1201 
   1202    // can only make our texture storage to a render target if level 0 is defined (with a width &
   1203    // height) and the current level we're copying to is defined (with appropriate format, width &
   1204    // height)
   1205 
   1206    // If the zero max LOD workaround is active, then we can't sample from individual layers of the
   1207    // framebuffer in shaders, so we should use the non-rendering copy path.
   1208    if (!canCreateRenderTargetForImage(index) ||
   1209        mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
   1210    {
   1211        ANGLE_TRY(mImageArray[index.getLevelIndex()]->copyFromFramebuffer(context, clippedOffset,
   1212                                                                          clippedArea, source));
   1213        mDirtyImages = true;
   1214        onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
   1215    }
   1216    else
   1217    {
   1218        ANGLE_TRY(ensureRenderTarget(context));
   1219 
   1220        if (isValidLevel(index.getLevelIndex()))
   1221        {
   1222            ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
   1223            ANGLE_TRY(mRenderer->copyImage2D(context, source, clippedArea,
   1224                                             gl::GetUnsizedFormat(getBaseLevelInternalFormat()),
   1225                                             clippedOffset, mTexStorage, index.getLevelIndex()));
   1226        }
   1227    }
   1228 
   1229    return angle::Result::Continue;
   1230 }
   1231 
   1232 angle::Result TextureD3D_2D::copyTexture(const gl::Context *context,
   1233                                         const gl::ImageIndex &index,
   1234                                         GLenum internalFormat,
   1235                                         GLenum type,
   1236                                         GLint sourceLevel,
   1237                                         bool unpackFlipY,
   1238                                         bool unpackPremultiplyAlpha,
   1239                                         bool unpackUnmultiplyAlpha,
   1240                                         const gl::Texture *source)
   1241 {
   1242    ASSERT(index.getTarget() == gl::TextureTarget::_2D);
   1243 
   1244    gl::TextureType sourceType = source->getType();
   1245 
   1246    const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
   1247    gl::Extents size(
   1248        static_cast<int>(source->getWidth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
   1249        static_cast<int>(source->getHeight(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
   1250        1);
   1251    ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat,
   1252                            size, false));
   1253 
   1254    gl::Box sourceBox(0, 0, 0, size.width, size.height, 1);
   1255    gl::Offset destOffset(0, 0, 0);
   1256 
   1257    if (!isSRGB(index.getLevelIndex()) && canCreateRenderTargetForImage(index))
   1258    {
   1259        ANGLE_TRY(ensureRenderTarget(context));
   1260        ASSERT(isValidLevel(index.getLevelIndex()));
   1261        ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
   1262 
   1263        ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2D,
   1264                                         sourceBox, internalFormatInfo.format,
   1265                                         internalFormatInfo.type, destOffset, mTexStorage,
   1266                                         index.getTarget(), index.getLevelIndex(), unpackFlipY,
   1267                                         unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
   1268    }
   1269    else
   1270    {
   1271        gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(sourceLevel);
   1272        TextureD3D *sourceD3D           = GetImplAs<TextureD3D>(source);
   1273        ImageD3D *sourceImage           = nullptr;
   1274        ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage));
   1275 
   1276        ImageD3D *destImage = nullptr;
   1277        ANGLE_TRY(getImageAndSyncFromStorage(context, index, &destImage));
   1278 
   1279        ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
   1280                                       unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
   1281 
   1282        mDirtyImages = true;
   1283 
   1284        gl::Box destRegion(destOffset, size);
   1285        ANGLE_TRY(commitRegion(context, index, destRegion));
   1286    }
   1287 
   1288    return angle::Result::Continue;
   1289 }
   1290 
   1291 angle::Result TextureD3D_2D::copySubTexture(const gl::Context *context,
   1292                                            const gl::ImageIndex &index,
   1293                                            const gl::Offset &destOffset,
   1294                                            GLint sourceLevel,
   1295                                            const gl::Box &sourceBox,
   1296                                            bool unpackFlipY,
   1297                                            bool unpackPremultiplyAlpha,
   1298                                            bool unpackUnmultiplyAlpha,
   1299                                            const gl::Texture *source)
   1300 {
   1301    ASSERT(index.getTarget() == gl::TextureTarget::_2D);
   1302 
   1303    if (!isSRGB(index.getLevelIndex()) && canCreateRenderTargetForImage(index))
   1304    {
   1305        ANGLE_TRY(ensureRenderTarget(context));
   1306        ASSERT(isValidLevel(index.getLevelIndex()));
   1307        ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
   1308 
   1309        const gl::InternalFormat &internalFormatInfo =
   1310            gl::GetSizedInternalFormatInfo(getInternalFormat(index.getLevelIndex()));
   1311        ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2D,
   1312                                         sourceBox, internalFormatInfo.format,
   1313                                         internalFormatInfo.type, destOffset, mTexStorage,
   1314                                         index.getTarget(), index.getLevelIndex(), unpackFlipY,
   1315                                         unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
   1316    }
   1317    else
   1318    {
   1319        gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(sourceLevel);
   1320        TextureD3D *sourceD3D           = GetImplAs<TextureD3D>(source);
   1321        ImageD3D *sourceImage           = nullptr;
   1322        ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage));
   1323 
   1324        ImageD3D *destImage = nullptr;
   1325        ANGLE_TRY(getImageAndSyncFromStorage(context, index, &destImage));
   1326 
   1327        ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
   1328                                       unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
   1329 
   1330        mDirtyImages = true;
   1331 
   1332        gl::Box destRegion(destOffset.x, destOffset.y, 0, sourceBox.width, sourceBox.height, 1);
   1333        ANGLE_TRY(commitRegion(context, index, destRegion));
   1334    }
   1335 
   1336    return angle::Result::Continue;
   1337 }
   1338 
   1339 angle::Result TextureD3D_2D::copyCompressedTexture(const gl::Context *context,
   1340                                                   const gl::Texture *source)
   1341 {
   1342    gl::TextureTarget sourceTarget = NonCubeTextureTypeToTarget(source->getType());
   1343    GLint sourceLevel              = 0;
   1344 
   1345    GLint destLevel = 0;
   1346 
   1347    GLenum sizedInternalFormat =
   1348        source->getFormat(sourceTarget, sourceLevel).info->sizedInternalFormat;
   1349    gl::Extents size(static_cast<int>(source->getWidth(sourceTarget, sourceLevel)),
   1350                     static_cast<int>(source->getHeight(sourceTarget, sourceLevel)), 1);
   1351    ANGLE_TRY(redefineImage(context, destLevel, sizedInternalFormat, size, false));
   1352 
   1353    ANGLE_TRY(initializeStorage(context, BindFlags()));
   1354    ASSERT(mTexStorage);
   1355 
   1356    ANGLE_TRY(
   1357        mRenderer->copyCompressedTexture(context, source, sourceLevel, mTexStorage, destLevel));
   1358 
   1359    return angle::Result::Continue;
   1360 }
   1361 
   1362 angle::Result TextureD3D_2D::setStorage(const gl::Context *context,
   1363                                        gl::TextureType type,
   1364                                        size_t levels,
   1365                                        GLenum internalFormat,
   1366                                        const gl::Extents &size)
   1367 {
   1368    ASSERT(type == gl::TextureType::_2D && size.depth == 1);
   1369 
   1370    for (size_t level = 0; level < levels; level++)
   1371    {
   1372        gl::Extents levelSize(std::max(1, size.width >> level), std::max(1, size.height >> level),
   1373                              1);
   1374        ANGLE_TRY(redefineImage(context, level, internalFormat, levelSize, true));
   1375    }
   1376 
   1377    for (size_t level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
   1378    {
   1379        ANGLE_TRY(redefineImage(context, level, GL_NONE, gl::Extents(0, 0, 1), true));
   1380    }
   1381 
   1382    // TODO(geofflang): Verify storage creation had no errors
   1383    BindFlags flags;
   1384    flags.renderTarget        = IsRenderTargetUsage(mState.getUsage());
   1385    TexStoragePointer storage = {
   1386        mRenderer->createTextureStorage2D(internalFormat, flags, size.width, size.height,
   1387                                          static_cast<int>(levels), mState.getLabel(), false),
   1388        context};
   1389 
   1390    ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
   1391    storage.release();
   1392 
   1393    ANGLE_TRY(updateStorage(context));
   1394 
   1395    mImmutable = true;
   1396 
   1397    return angle::Result::Continue;
   1398 }
   1399 
   1400 angle::Result TextureD3D_2D::bindTexImage(const gl::Context *context, egl::Surface *surface)
   1401 {
   1402    GLenum internalformat = surface->getConfig()->renderTargetFormat;
   1403 
   1404    gl::Extents size(surface->getWidth(), surface->getHeight(), 1);
   1405    ANGLE_TRY(redefineImage(context, 0, internalformat, size, true));
   1406 
   1407    ANGLE_TRY(releaseTexStorage(context, gl::TexLevelMask()));
   1408 
   1409    SurfaceD3D *surfaceD3D = GetImplAs<SurfaceD3D>(surface);
   1410    ASSERT(surfaceD3D);
   1411 
   1412    mTexStorage = mRenderer->createTextureStorage2D(surfaceD3D->getSwapChain(), mState.getLabel());
   1413    mEGLImageTarget = false;
   1414 
   1415    mDirtyImages = false;
   1416    mImageArray[0]->markClean();
   1417 
   1418    return angle::Result::Continue;
   1419 }
   1420 
   1421 angle::Result TextureD3D_2D::releaseTexImage(const gl::Context *context)
   1422 {
   1423    if (mTexStorage)
   1424    {
   1425        ANGLE_TRY(releaseTexStorage(context, gl::TexLevelMask()));
   1426    }
   1427 
   1428    for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
   1429    {
   1430        ANGLE_TRY(redefineImage(context, i, GL_NONE, gl::Extents(0, 0, 1), true));
   1431    }
   1432 
   1433    return angle::Result::Continue;
   1434 }
   1435 
   1436 angle::Result TextureD3D_2D::setEGLImageTarget(const gl::Context *context,
   1437                                               gl::TextureType type,
   1438                                               egl::Image *image)
   1439 {
   1440    EGLImageD3D *eglImaged3d = GetImplAs<EGLImageD3D>(image);
   1441 
   1442    // Set the properties of the base mip level from the EGL image
   1443    const auto &format = image->getFormat();
   1444    gl::Extents size(static_cast<int>(image->getWidth()), static_cast<int>(image->getHeight()), 1);
   1445    ANGLE_TRY(redefineImage(context, 0, format.info->sizedInternalFormat, size, true));
   1446 
   1447    // Clear all other images.
   1448    for (size_t level = 1; level < mImageArray.size(); level++)
   1449    {
   1450        ANGLE_TRY(redefineImage(context, level, GL_NONE, gl::Extents(0, 0, 1), true));
   1451    }
   1452 
   1453    ANGLE_TRY(releaseTexStorage(context, gl::TexLevelMask()));
   1454    mImageArray[0]->markClean();
   1455 
   1456    // Pass in the RenderTargetD3D here: createTextureStorage can't generate an error.
   1457    RenderTargetD3D *renderTargetD3D = nullptr;
   1458    ANGLE_TRY(eglImaged3d->getRenderTarget(context, &renderTargetD3D));
   1459 
   1460    mTexStorage =
   1461        mRenderer->createTextureStorageEGLImage(eglImaged3d, renderTargetD3D, mState.getLabel());
   1462    mEGLImageTarget = true;
   1463 
   1464    return angle::Result::Continue;
   1465 }
   1466 
   1467 angle::Result TextureD3D_2D::initMipmapImages(const gl::Context *context)
   1468 {
   1469    const GLuint baseLevel = mState.getEffectiveBaseLevel();
   1470    const GLuint maxLevel  = mState.getMipmapMaxLevel();
   1471    // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap
   1472    // levels.
   1473    for (GLuint level = baseLevel + 1; level <= maxLevel; level++)
   1474    {
   1475        gl::Extents levelSize(std::max(getLevelZeroWidth() >> level, 1),
   1476                              std::max(getLevelZeroHeight() >> level, 1), 1);
   1477 
   1478        ANGLE_TRY(redefineImage(context, level, getBaseLevelInternalFormat(), levelSize, false));
   1479    }
   1480 
   1481    // We should be mip-complete now so generate the storage.
   1482    ANGLE_TRY(initializeStorage(context, BindFlags::RenderTarget()));
   1483 
   1484    return angle::Result::Continue;
   1485 }
   1486 
   1487 angle::Result TextureD3D_2D::getRenderTarget(const gl::Context *context,
   1488                                             const gl::ImageIndex &index,
   1489                                             GLsizei samples,
   1490                                             RenderTargetD3D **outRT)
   1491 {
   1492    ASSERT(!index.hasLayer());
   1493 
   1494    // ensure the underlying texture is created
   1495    ANGLE_TRY(ensureRenderTarget(context));
   1496    ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
   1497 
   1498    return mTexStorage->getRenderTarget(context, index, samples, outRT);
   1499 }
   1500 
   1501 bool TextureD3D_2D::isValidLevel(int level) const
   1502 {
   1503    return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
   1504 }
   1505 
   1506 bool TextureD3D_2D::isLevelComplete(int level) const
   1507 {
   1508    if (isImmutable())
   1509    {
   1510        return true;
   1511    }
   1512 
   1513    GLsizei width  = getLevelZeroWidth();
   1514    GLsizei height = getLevelZeroHeight();
   1515 
   1516    if (width <= 0 || height <= 0)
   1517    {
   1518        return false;
   1519    }
   1520 
   1521    // The base image level is complete if the width and height are positive
   1522    if (level == static_cast<int>(getBaseLevel()))
   1523    {
   1524        return true;
   1525    }
   1526 
   1527    ASSERT(level >= 0 && level <= static_cast<int>(mImageArray.size()) &&
   1528           mImageArray[level] != nullptr);
   1529    ImageD3D *image = mImageArray[level].get();
   1530 
   1531    if (image->getInternalFormat() != getBaseLevelInternalFormat())
   1532    {
   1533        return false;
   1534    }
   1535 
   1536    if (image->getWidth() != std::max(1, width >> level))
   1537    {
   1538        return false;
   1539    }
   1540 
   1541    if (image->getHeight() != std::max(1, height >> level))
   1542    {
   1543        return false;
   1544    }
   1545 
   1546    return true;
   1547 }
   1548 
   1549 bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const
   1550 {
   1551    return isLevelComplete(index.getLevelIndex());
   1552 }
   1553 
   1554 // Constructs a native texture resource from the texture images
   1555 angle::Result TextureD3D_2D::initializeStorage(const gl::Context *context, BindFlags bindFlags)
   1556 {
   1557    // Only initialize the first time this texture is used as a render target or shader resource
   1558    if (mTexStorage)
   1559    {
   1560        return angle::Result::Continue;
   1561    }
   1562 
   1563    // do not attempt to create storage for nonexistant data
   1564    if (!isLevelComplete(getBaseLevel()))
   1565    {
   1566        return angle::Result::Continue;
   1567    }
   1568 
   1569    bindFlags.renderTarget |= IsRenderTargetUsage(mState.getUsage());
   1570 
   1571    TexStoragePointer storage;
   1572    ANGLE_TRY(createCompleteStorage(context, bindFlags, &storage));
   1573 
   1574    ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
   1575    storage.release();
   1576 
   1577    ASSERT(mTexStorage);
   1578 
   1579    // flush image data to the storage
   1580    ANGLE_TRY(updateStorage(context));
   1581 
   1582    return angle::Result::Continue;
   1583 }
   1584 
   1585 angle::Result TextureD3D_2D::createCompleteStorage(const gl::Context *context,
   1586                                                   BindFlags bindFlags,
   1587                                                   TexStoragePointer *outStorage) const
   1588 {
   1589    GLsizei width         = getLevelZeroWidth();
   1590    GLsizei height        = getLevelZeroHeight();
   1591    GLenum internalFormat = getBaseLevelInternalFormat();
   1592 
   1593    ASSERT(width > 0 && height > 0);
   1594 
   1595    // use existing storage level count, when previously specified by TexStorage*D
   1596    GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
   1597 
   1598    bool hintLevelZeroOnly = false;
   1599    if (mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
   1600    {
   1601        // If any of the CPU images (levels >= 1) are dirty, then the textureStorage2D should use
   1602        // the mipped texture to begin with. Otherwise, it should use the level-zero-only texture.
   1603        hintLevelZeroOnly = true;
   1604        for (int level = 1; level < levels && hintLevelZeroOnly; level++)
   1605        {
   1606            hintLevelZeroOnly = !(mImageArray[level]->isDirty() && isLevelComplete(level));
   1607        }
   1608    }
   1609 
   1610    // TODO(geofflang): Determine if the texture creation succeeded
   1611    *outStorage = {mRenderer->createTextureStorage2D(internalFormat, bindFlags, width, height,
   1612                                                     levels, mState.getLabel(), hintLevelZeroOnly),
   1613                   context};
   1614 
   1615    return angle::Result::Continue;
   1616 }
   1617 
   1618 angle::Result TextureD3D_2D::setCompleteTexStorage(const gl::Context *context,
   1619                                                   TextureStorage *newCompleteTexStorage)
   1620 {
   1621    if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
   1622    {
   1623        for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
   1624        {
   1625            ANGLE_TRY(
   1626                mImageArray[level]->setManagedSurface2D(context, newCompleteTexStorage, level));
   1627        }
   1628    }
   1629 
   1630    gl::TexLevelMask copyImageMask;
   1631    copyImageMask.set();
   1632 
   1633    ANGLE_TRY(releaseTexStorage(context, copyImageMask));
   1634    mTexStorage = newCompleteTexStorage;
   1635    mTexStorageObserverBinding.bind(mTexStorage);
   1636 
   1637    mDirtyImages = true;
   1638 
   1639    return angle::Result::Continue;
   1640 }
   1641 
   1642 angle::Result TextureD3D_2D::updateStorage(const gl::Context *context)
   1643 {
   1644    if (!mDirtyImages)
   1645    {
   1646        return angle::Result::Continue;
   1647    }
   1648 
   1649    ASSERT(mTexStorage != nullptr);
   1650    GLint storageLevels = mTexStorage->getLevelCount();
   1651    for (int level = 0; level < storageLevels; level++)
   1652    {
   1653        if (mImageArray[level]->isDirty() && isLevelComplete(level))
   1654        {
   1655            ANGLE_TRY(updateStorageLevel(context, level));
   1656        }
   1657    }
   1658 
   1659    mDirtyImages = false;
   1660    return angle::Result::Continue;
   1661 }
   1662 
   1663 angle::Result TextureD3D_2D::updateStorageLevel(const gl::Context *context, int level)
   1664 {
   1665    ASSERT(level <= static_cast<int>(mImageArray.size()) && mImageArray[level] != nullptr);
   1666    ASSERT(isLevelComplete(level));
   1667 
   1668    if (mImageArray[level]->isDirty())
   1669    {
   1670        gl::ImageIndex index = gl::ImageIndex::Make2D(level);
   1671        gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
   1672        ANGLE_TRY(commitRegion(context, index, region));
   1673    }
   1674 
   1675    return angle::Result::Continue;
   1676 }
   1677 
   1678 angle::Result TextureD3D_2D::redefineImage(const gl::Context *context,
   1679                                           size_t level,
   1680                                           GLenum internalformat,
   1681                                           const gl::Extents &size,
   1682                                           bool forceRelease)
   1683 {
   1684    ASSERT(size.depth == 1);
   1685 
   1686    // If there currently is a corresponding storage texture image, it has these parameters
   1687    const int storageWidth     = std::max(1, getLevelZeroWidth() >> level);
   1688    const int storageHeight    = std::max(1, getLevelZeroHeight() >> level);
   1689    const GLenum storageFormat = getBaseLevelInternalFormat();
   1690 
   1691    if (mTexStorage)
   1692    {
   1693        const size_t storageLevels = mTexStorage->getLevelCount();
   1694 
   1695        // If the storage was from an EGL image, copy it back into local images to preserve it
   1696        // while orphaning
   1697        if (level != 0 && mEGLImageTarget)
   1698        {
   1699            ANGLE_TRY(mImageArray[0]->copyFromTexStorage(context, gl::ImageIndex::Make2D(0),
   1700                                                         mTexStorage));
   1701        }
   1702 
   1703        if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth ||
   1704            size.height != storageHeight || internalformat != storageFormat ||
   1705            mEGLImageTarget)  // Discard mismatched storage
   1706        {
   1707            gl::TexLevelMask copyImageMask;
   1708            copyImageMask.set();
   1709            copyImageMask.set(level, false);
   1710 
   1711            ANGLE_TRY(releaseTexStorage(context, copyImageMask));
   1712            markAllImagesDirty();
   1713        }
   1714    }
   1715 
   1716    mImageArray[level]->redefine(gl::TextureType::_2D, internalformat, size, forceRelease);
   1717    mDirtyImages = mDirtyImages || mImageArray[level]->isDirty();
   1718 
   1719    // Can't be an EGL image target after being redefined
   1720    mEGLImageTarget = false;
   1721 
   1722    return angle::Result::Continue;
   1723 }
   1724 
   1725 gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
   1726 {
   1727    return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
   1728 }
   1729 
   1730 gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
   1731 {
   1732    // "layer" does not apply to 2D Textures.
   1733    return gl::ImageIndex::Make2D(mip);
   1734 }
   1735 
   1736 bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const
   1737 {
   1738    return (mTexStorage && index.getType() == gl::TextureType::_2D && index.getLevelIndex() >= 0 &&
   1739            index.getLevelIndex() < mTexStorage->getLevelCount());
   1740 }
   1741 
   1742 void TextureD3D_2D::markAllImagesDirty()
   1743 {
   1744    for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
   1745    {
   1746        mImageArray[i]->markDirty();
   1747    }
   1748    mDirtyImages = true;
   1749 }
   1750 
   1751 TextureD3D_Cube::TextureD3D_Cube(const gl::TextureState &state, RendererD3D *renderer)
   1752    : TextureD3D(state, renderer)
   1753 {
   1754    for (auto &face : mImageArray)
   1755    {
   1756        for (auto &image : face)
   1757        {
   1758            image.reset(renderer->createImage());
   1759        }
   1760    }
   1761 }
   1762 
   1763 void TextureD3D_Cube::onDestroy(const gl::Context *context)
   1764 {
   1765    // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage
   1766    // for some of their data. If TextureStorage is deleted before the Images, then their data will
   1767    // be wastefully copied back from the GPU before we delete the Images.
   1768    for (auto &face : mImageArray)
   1769    {
   1770        for (auto &image : face)
   1771        {
   1772            image.reset();
   1773        }
   1774    }
   1775    return TextureD3D::onDestroy(context);
   1776 }
   1777 
   1778 TextureD3D_Cube::~TextureD3D_Cube() {}
   1779 
   1780 ImageD3D *TextureD3D_Cube::getImage(int level, int layer) const
   1781 {
   1782    ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
   1783    ASSERT(layer >= 0 && static_cast<size_t>(layer) < gl::kCubeFaceCount);
   1784    return mImageArray[layer][level].get();
   1785 }
   1786 
   1787 ImageD3D *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
   1788 {
   1789    ASSERT(index.getLevelIndex() < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
   1790    ASSERT(gl::IsCubeMapFaceTarget(index.getTarget()));
   1791    return mImageArray[index.cubeMapFaceIndex()][index.getLevelIndex()].get();
   1792 }
   1793 
   1794 GLsizei TextureD3D_Cube::getLayerCount(int level) const
   1795 {
   1796    ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
   1797    return gl::kCubeFaceCount;
   1798 }
   1799 
   1800 GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
   1801 {
   1802    if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
   1803        return mImageArray[layer][level]->getInternalFormat();
   1804    else
   1805        return GL_NONE;
   1806 }
   1807 
   1808 bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
   1809 {
   1810    return gl::GetSizedInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
   1811 }
   1812 
   1813 bool TextureD3D_Cube::isSRGB(GLint level, GLint layer) const
   1814 {
   1815    return gl::GetSizedInternalFormatInfo(getInternalFormat(level, layer)).colorEncoding == GL_SRGB;
   1816 }
   1817 
   1818 angle::Result TextureD3D_Cube::setEGLImageTarget(const gl::Context *context,
   1819                                                 gl::TextureType type,
   1820                                                 egl::Image *image)
   1821 {
   1822    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   1823    return angle::Result::Continue;
   1824 }
   1825 
   1826 angle::Result TextureD3D_Cube::setImage(const gl::Context *context,
   1827                                        const gl::ImageIndex &index,
   1828                                        GLenum internalFormat,
   1829                                        const gl::Extents &size,
   1830                                        GLenum format,
   1831                                        GLenum type,
   1832                                        const gl::PixelUnpackState &unpack,
   1833                                        gl::Buffer *unpackBuffer,
   1834                                        const uint8_t *pixels)
   1835 {
   1836    ASSERT(size.depth == 1);
   1837 
   1838    const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
   1839    ANGLE_TRY(redefineImage(context, index.cubeMapFaceIndex(), index.getLevelIndex(),
   1840                            internalFormatInfo.sizedInternalFormat, size, false));
   1841 
   1842    return setImageImpl(context, index, type, unpack, unpackBuffer, pixels, 0);
   1843 }
   1844 
   1845 angle::Result TextureD3D_Cube::setSubImage(const gl::Context *context,
   1846                                           const gl::ImageIndex &index,
   1847                                           const gl::Box &area,
   1848                                           GLenum format,
   1849                                           GLenum type,
   1850                                           const gl::PixelUnpackState &unpack,
   1851                                           gl::Buffer *unpackBuffer,
   1852                                           const uint8_t *pixels)
   1853 {
   1854    ASSERT(area.depth == 1 && area.z == 0);
   1855    return TextureD3D::subImage(context, index, area, format, type, unpack, unpackBuffer, pixels,
   1856                                0);
   1857 }
   1858 
   1859 angle::Result TextureD3D_Cube::setCompressedImage(const gl::Context *context,
   1860                                                  const gl::ImageIndex &index,
   1861                                                  GLenum internalFormat,
   1862                                                  const gl::Extents &size,
   1863                                                  const gl::PixelUnpackState &unpack,
   1864                                                  size_t imageSize,
   1865                                                  const uint8_t *pixels)
   1866 {
   1867    ASSERT(size.depth == 1);
   1868 
   1869    // compressed formats don't have separate sized internal formats-- we can just use the
   1870    // compressed format directly
   1871    ANGLE_TRY(redefineImage(context, index.cubeMapFaceIndex(), index.getLevelIndex(),
   1872                            internalFormat, size, false));
   1873 
   1874    return setCompressedImageImpl(context, index, unpack, pixels, 0);
   1875 }
   1876 
   1877 angle::Result TextureD3D_Cube::setCompressedSubImage(const gl::Context *context,
   1878                                                     const gl::ImageIndex &index,
   1879                                                     const gl::Box &area,
   1880                                                     GLenum format,
   1881                                                     const gl::PixelUnpackState &unpack,
   1882                                                     size_t imageSize,
   1883                                                     const uint8_t *pixels)
   1884 {
   1885    ASSERT(area.depth == 1 && area.z == 0);
   1886 
   1887    ANGLE_TRY(TextureD3D::subImageCompressed(context, index, area, format, unpack, pixels, 0));
   1888    return commitRegion(context, index, area);
   1889 }
   1890 
   1891 angle::Result TextureD3D_Cube::copyImage(const gl::Context *context,
   1892                                         const gl::ImageIndex &index,
   1893                                         const gl::Rectangle &sourceArea,
   1894                                         GLenum internalFormat,
   1895                                         gl::Framebuffer *source)
   1896 {
   1897    GLint faceIndex = index.cubeMapFaceIndex();
   1898    const gl::InternalFormat &internalFormatInfo =
   1899        gl::GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE);
   1900 
   1901    gl::Extents size(sourceArea.width, sourceArea.height, 1);
   1902    ANGLE_TRY(redefineImage(context, faceIndex, index.getLevelIndex(),
   1903                            internalFormatInfo.sizedInternalFormat, size, false));
   1904 
   1905    gl::Extents fbSize = source->getReadColorAttachment()->getSize();
   1906 
   1907    // Does the read area extend beyond the framebuffer?
   1908    bool outside = sourceArea.x < 0 || sourceArea.y < 0 ||
   1909                   sourceArea.x + sourceArea.width > fbSize.width ||
   1910                   sourceArea.y + sourceArea.height > fbSize.height;
   1911 
   1912    // WebGL requires that pixels that would be outside the framebuffer are treated as zero values,
   1913    // so clear the mip level to 0 prior to making the copy if any pixel would be sampled outside.
   1914    // Same thing for robust resource init.
   1915    if (outside && (context->isWebGL() || context->isRobustResourceInitEnabled()))
   1916    {
   1917        ANGLE_TRY(initializeContents(context, GL_NONE, index));
   1918    }
   1919 
   1920    gl::Rectangle clippedArea;
   1921    if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
   1922    {
   1923        // Empty source area, nothing to do.
   1924        return angle::Result::Continue;
   1925    }
   1926 
   1927    gl::Offset destOffset(clippedArea.x - sourceArea.x, clippedArea.y - sourceArea.y, 0);
   1928 
   1929    // If the zero max LOD workaround is active, then we can't sample from individual layers of the
   1930    // framebuffer in shaders, so we should use the non-rendering copy path.
   1931    if (!canCreateRenderTargetForImage(index) ||
   1932        mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
   1933    {
   1934        ANGLE_TRY(mImageArray[faceIndex][index.getLevelIndex()]->copyFromFramebuffer(
   1935            context, destOffset, clippedArea, source));
   1936        mDirtyImages = true;
   1937        onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
   1938    }
   1939    else
   1940    {
   1941        ANGLE_TRY(ensureRenderTarget(context));
   1942 
   1943        ASSERT(size.width == size.height);
   1944 
   1945        if (size.width > 0 && isValidFaceLevel(faceIndex, index.getLevelIndex()))
   1946        {
   1947            ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, index.getLevelIndex()));
   1948            ANGLE_TRY(mRenderer->copyImageCube(context, source, clippedArea, internalFormat,
   1949                                               destOffset, mTexStorage, index.getTarget(),
   1950                                               index.getLevelIndex()));
   1951        }
   1952    }
   1953 
   1954    return angle::Result::Continue;
   1955 }
   1956 
   1957 angle::Result TextureD3D_Cube::copySubImage(const gl::Context *context,
   1958                                            const gl::ImageIndex &index,
   1959                                            const gl::Offset &destOffset,
   1960                                            const gl::Rectangle &sourceArea,
   1961                                            gl::Framebuffer *source)
   1962 {
   1963    gl::Extents fbSize = source->getReadColorAttachment()->getSize();
   1964    gl::Rectangle clippedArea;
   1965    if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
   1966    {
   1967        return angle::Result::Continue;
   1968    }
   1969    const gl::Offset clippedOffset(destOffset.x + clippedArea.x - sourceArea.x,
   1970                                   destOffset.y + clippedArea.y - sourceArea.y, 0);
   1971 
   1972    GLint faceIndex = index.cubeMapFaceIndex();
   1973 
   1974    // If the zero max LOD workaround is active, then we can't sample from individual layers of the
   1975    // framebuffer in shaders, so we should use the non-rendering copy path.
   1976    if (!canCreateRenderTargetForImage(index) ||
   1977        mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
   1978    {
   1979        ANGLE_TRY(mImageArray[faceIndex][index.getLevelIndex()]->copyFromFramebuffer(
   1980            context, clippedOffset, clippedArea, source));
   1981        mDirtyImages = true;
   1982        onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
   1983    }
   1984    else
   1985    {
   1986        ANGLE_TRY(ensureRenderTarget(context));
   1987        if (isValidFaceLevel(faceIndex, index.getLevelIndex()))
   1988        {
   1989            ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, index.getLevelIndex()));
   1990            ANGLE_TRY(mRenderer->copyImageCube(
   1991                context, source, clippedArea, gl::GetUnsizedFormat(getBaseLevelInternalFormat()),
   1992                clippedOffset, mTexStorage, index.getTarget(), index.getLevelIndex()));
   1993        }
   1994    }
   1995 
   1996    return angle::Result::Continue;
   1997 }
   1998 
   1999 angle::Result TextureD3D_Cube::copyTexture(const gl::Context *context,
   2000                                           const gl::ImageIndex &index,
   2001                                           GLenum internalFormat,
   2002                                           GLenum type,
   2003                                           GLint sourceLevel,
   2004                                           bool unpackFlipY,
   2005                                           bool unpackPremultiplyAlpha,
   2006                                           bool unpackUnmultiplyAlpha,
   2007                                           const gl::Texture *source)
   2008 {
   2009    ASSERT(gl::IsCubeMapFaceTarget(index.getTarget()));
   2010 
   2011    gl::TextureTarget sourceTarget = NonCubeTextureTypeToTarget(source->getType());
   2012 
   2013    GLint faceIndex = index.cubeMapFaceIndex();
   2014 
   2015    const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
   2016    gl::Extents size(static_cast<int>(source->getWidth(sourceTarget, sourceLevel)),
   2017                     static_cast<int>(source->getHeight(sourceTarget, sourceLevel)), 1);
   2018    ANGLE_TRY(redefineImage(context, faceIndex, index.getLevelIndex(),
   2019                            internalFormatInfo.sizedInternalFormat, size, false));
   2020 
   2021    gl::Box sourceBox(0, 0, 0, size.width, size.height, 1);
   2022    gl::Offset destOffset(0, 0, 0);
   2023 
   2024    if (!isSRGB(index.getLevelIndex(), faceIndex) && canCreateRenderTargetForImage(index))
   2025    {
   2026 
   2027        ANGLE_TRY(ensureRenderTarget(context));
   2028        ASSERT(isValidFaceLevel(faceIndex, index.getLevelIndex()));
   2029        ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, index.getLevelIndex()));
   2030 
   2031        ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2D,
   2032                                         sourceBox, internalFormatInfo.format,
   2033                                         internalFormatInfo.type, destOffset, mTexStorage,
   2034                                         index.getTarget(), index.getLevelIndex(), unpackFlipY,
   2035                                         unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
   2036    }
   2037    else
   2038    {
   2039        gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(sourceLevel);
   2040        TextureD3D *sourceD3D           = GetImplAs<TextureD3D>(source);
   2041        ImageD3D *sourceImage           = nullptr;
   2042        ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage));
   2043 
   2044        ImageD3D *destImage = nullptr;
   2045        ANGLE_TRY(getImageAndSyncFromStorage(context, index, &destImage));
   2046 
   2047        ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
   2048                                       unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
   2049 
   2050        mDirtyImages = true;
   2051 
   2052        gl::Box destRegion(destOffset, size);
   2053        ANGLE_TRY(commitRegion(context, index, destRegion));
   2054    }
   2055 
   2056    return angle::Result::Continue;
   2057 }
   2058 
   2059 angle::Result TextureD3D_Cube::copySubTexture(const gl::Context *context,
   2060                                              const gl::ImageIndex &index,
   2061                                              const gl::Offset &destOffset,
   2062                                              GLint sourceLevel,
   2063                                              const gl::Box &sourceBox,
   2064                                              bool unpackFlipY,
   2065                                              bool unpackPremultiplyAlpha,
   2066                                              bool unpackUnmultiplyAlpha,
   2067                                              const gl::Texture *source)
   2068 {
   2069    ASSERT(gl::IsCubeMapFaceTarget(index.getTarget()));
   2070 
   2071    GLint faceIndex = index.cubeMapFaceIndex();
   2072 
   2073    if (!isSRGB(index.getLevelIndex(), faceIndex) && canCreateRenderTargetForImage(index))
   2074    {
   2075        ANGLE_TRY(ensureRenderTarget(context));
   2076        ASSERT(isValidFaceLevel(faceIndex, index.getLevelIndex()));
   2077        ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, index.getLevelIndex()));
   2078 
   2079        const gl::InternalFormat &internalFormatInfo =
   2080            gl::GetSizedInternalFormatInfo(getInternalFormat(index.getLevelIndex(), faceIndex));
   2081        ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2D,
   2082                                         sourceBox, internalFormatInfo.format,
   2083                                         internalFormatInfo.type, destOffset, mTexStorage,
   2084                                         index.getTarget(), index.getLevelIndex(), unpackFlipY,
   2085                                         unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
   2086    }
   2087    else
   2088    {
   2089        gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(sourceLevel);
   2090        TextureD3D *sourceD3D           = GetImplAs<TextureD3D>(source);
   2091        ImageD3D *sourceImage           = nullptr;
   2092        ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage));
   2093 
   2094        ImageD3D *destImage = nullptr;
   2095        ANGLE_TRY(getImageAndSyncFromStorage(context, index, &destImage));
   2096 
   2097        ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
   2098                                       unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
   2099 
   2100        mDirtyImages = true;
   2101 
   2102        gl::Box destRegion(destOffset.x, destOffset.y, 0, sourceBox.width, sourceBox.height, 1);
   2103        ANGLE_TRY(commitRegion(context, index, destRegion));
   2104    }
   2105 
   2106    return angle::Result::Continue;
   2107 }
   2108 
   2109 angle::Result TextureD3D_Cube::setStorage(const gl::Context *context,
   2110                                          gl::TextureType type,
   2111                                          size_t levels,
   2112                                          GLenum internalFormat,
   2113                                          const gl::Extents &size)
   2114 {
   2115    ASSERT(size.width == size.height);
   2116    ASSERT(size.depth == 1);
   2117 
   2118    for (size_t level = 0; level < levels; level++)
   2119    {
   2120        GLsizei mipSize = std::max(1, size.width >> level);
   2121        for (size_t faceIndex = 0; faceIndex < gl::kCubeFaceCount; faceIndex++)
   2122        {
   2123            mImageArray[faceIndex][level]->redefine(gl::TextureType::CubeMap, internalFormat,
   2124                                                    gl::Extents(mipSize, mipSize, 1), true);
   2125        }
   2126    }
   2127 
   2128    for (size_t level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
   2129    {
   2130        for (size_t faceIndex = 0; faceIndex < gl::kCubeFaceCount; faceIndex++)
   2131        {
   2132            mImageArray[faceIndex][level]->redefine(gl::TextureType::CubeMap, GL_NONE,
   2133                                                    gl::Extents(0, 0, 0), true);
   2134        }
   2135    }
   2136 
   2137    // TODO(geofflang): Verify storage creation had no errors
   2138    BindFlags bindFlags;
   2139    bindFlags.renderTarget = IsRenderTargetUsage(mState.getUsage());
   2140 
   2141    TexStoragePointer storage = {
   2142        mRenderer->createTextureStorageCube(internalFormat, bindFlags, size.width,
   2143                                            static_cast<int>(levels), false, mState.getLabel()),
   2144        context};
   2145 
   2146    ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
   2147    storage.release();
   2148 
   2149    ANGLE_TRY(updateStorage(context));
   2150 
   2151    mImmutable = true;
   2152 
   2153    return angle::Result::Continue;
   2154 }
   2155 
   2156 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
   2157 bool TextureD3D_Cube::isCubeComplete() const
   2158 {
   2159    int baseWidth     = getBaseLevelWidth();
   2160    int baseHeight    = getBaseLevelHeight();
   2161    GLenum baseFormat = getBaseLevelInternalFormat();
   2162 
   2163    if (baseWidth <= 0 || baseWidth != baseHeight)
   2164    {
   2165        return false;
   2166    }
   2167 
   2168    for (size_t faceIndex = 1; faceIndex < gl::kCubeFaceCount; faceIndex++)
   2169    {
   2170        const ImageD3D &faceBaseImage = *mImageArray[faceIndex][getBaseLevel()];
   2171 
   2172        if (faceBaseImage.getWidth() != baseWidth || faceBaseImage.getHeight() != baseHeight ||
   2173            faceBaseImage.getInternalFormat() != baseFormat)
   2174        {
   2175            return false;
   2176        }
   2177    }
   2178 
   2179    return true;
   2180 }
   2181 
   2182 angle::Result TextureD3D_Cube::bindTexImage(const gl::Context *context, egl::Surface *surface)
   2183 {
   2184    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   2185    return angle::Result::Continue;
   2186 }
   2187 
   2188 angle::Result TextureD3D_Cube::releaseTexImage(const gl::Context *context)
   2189 {
   2190    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   2191    return angle::Result::Continue;
   2192 }
   2193 
   2194 angle::Result TextureD3D_Cube::initMipmapImages(const gl::Context *context)
   2195 {
   2196    const GLuint baseLevel = mState.getEffectiveBaseLevel();
   2197    const GLuint maxLevel  = mState.getMipmapMaxLevel();
   2198    // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap
   2199    // levels.
   2200    for (int faceIndex = 0; faceIndex < static_cast<int>(gl::kCubeFaceCount); faceIndex++)
   2201    {
   2202        for (GLuint level = baseLevel + 1; level <= maxLevel; level++)
   2203        {
   2204            int faceLevelSize =
   2205                (std::max(mImageArray[faceIndex][baseLevel]->getWidth() >> (level - baseLevel), 1));
   2206            ANGLE_TRY(redefineImage(context, faceIndex, level,
   2207                                    mImageArray[faceIndex][baseLevel]->getInternalFormat(),
   2208                                    gl::Extents(faceLevelSize, faceLevelSize, 1), false));
   2209        }
   2210    }
   2211 
   2212    // We should be mip-complete now so generate the storage.
   2213    ANGLE_TRY(initializeStorage(context, BindFlags::RenderTarget()));
   2214 
   2215    return angle::Result::Continue;
   2216 }
   2217 
   2218 angle::Result TextureD3D_Cube::getRenderTarget(const gl::Context *context,
   2219                                               const gl::ImageIndex &index,
   2220                                               GLsizei samples,
   2221                                               RenderTargetD3D **outRT)
   2222 {
   2223    ASSERT(gl::IsCubeMapFaceTarget(index.getTarget()));
   2224 
   2225    // ensure the underlying texture is created
   2226    ANGLE_TRY(ensureRenderTarget(context));
   2227    ANGLE_TRY(updateStorageFaceLevel(context, index.cubeMapFaceIndex(), index.getLevelIndex()));
   2228 
   2229    return mTexStorage->getRenderTarget(context, index, samples, outRT);
   2230 }
   2231 
   2232 angle::Result TextureD3D_Cube::initializeStorage(const gl::Context *context, BindFlags bindFlags)
   2233 {
   2234    // Only initialize the first time this texture is used as a render target or shader resource
   2235    if (mTexStorage)
   2236    {
   2237        return angle::Result::Continue;
   2238    }
   2239 
   2240    // do not attempt to create storage for nonexistant data
   2241    if (!isFaceLevelComplete(0, getBaseLevel()))
   2242    {
   2243        return angle::Result::Continue;
   2244    }
   2245 
   2246    bindFlags.renderTarget |= IsRenderTargetUsage(mState.getUsage());
   2247 
   2248    TexStoragePointer storage;
   2249    ANGLE_TRY(createCompleteStorage(context, bindFlags, &storage));
   2250 
   2251    ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
   2252    storage.release();
   2253 
   2254    ASSERT(mTexStorage);
   2255 
   2256    // flush image data to the storage
   2257    ANGLE_TRY(updateStorage(context));
   2258 
   2259    return angle::Result::Continue;
   2260 }
   2261 
   2262 angle::Result TextureD3D_Cube::createCompleteStorage(const gl::Context *context,
   2263                                                     BindFlags bindFlags,
   2264                                                     TexStoragePointer *outStorage) const
   2265 {
   2266    GLsizei size = getLevelZeroWidth();
   2267 
   2268    ASSERT(size > 0);
   2269 
   2270    // use existing storage level count, when previously specified by TexStorage*D
   2271    GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
   2272 
   2273    bool hintLevelZeroOnly = false;
   2274    if (mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
   2275    {
   2276        // If any of the CPU images (levels >= 1) are dirty, then the textureStorageEXT should use
   2277        // the mipped texture to begin with. Otherwise, it should use the level-zero-only texture.
   2278        hintLevelZeroOnly = true;
   2279        for (int faceIndex = 0;
   2280             faceIndex < static_cast<int>(gl::kCubeFaceCount) && hintLevelZeroOnly; faceIndex++)
   2281        {
   2282            for (int level = 1; level < levels && hintLevelZeroOnly; level++)
   2283            {
   2284                hintLevelZeroOnly = !(mImageArray[faceIndex][level]->isDirty() &&
   2285                                      isFaceLevelComplete(faceIndex, level));
   2286            }
   2287        }
   2288    }
   2289 
   2290    // TODO (geofflang): detect if storage creation succeeded
   2291    *outStorage = {
   2292        mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), bindFlags, size, levels,
   2293                                            hintLevelZeroOnly, mState.getLabel()),
   2294        context};
   2295 
   2296    return angle::Result::Continue;
   2297 }
   2298 
   2299 angle::Result TextureD3D_Cube::setCompleteTexStorage(const gl::Context *context,
   2300                                                     TextureStorage *newCompleteTexStorage)
   2301 {
   2302    if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
   2303    {
   2304        for (int faceIndex = 0; faceIndex < static_cast<int>(gl::kCubeFaceCount); faceIndex++)
   2305        {
   2306            for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
   2307            {
   2308                ANGLE_TRY(mImageArray[faceIndex][level]->setManagedSurfaceCube(
   2309                    context, newCompleteTexStorage, faceIndex, level));
   2310            }
   2311        }
   2312    }
   2313 
   2314    gl::TexLevelMask copyImageMask;
   2315    copyImageMask.set();
   2316 
   2317    ANGLE_TRY(releaseTexStorage(context, copyImageMask));
   2318    mTexStorage = newCompleteTexStorage;
   2319    mTexStorageObserverBinding.bind(mTexStorage);
   2320 
   2321    mDirtyImages = true;
   2322    return angle::Result::Continue;
   2323 }
   2324 
   2325 angle::Result TextureD3D_Cube::updateStorage(const gl::Context *context)
   2326 {
   2327    if (!mDirtyImages)
   2328    {
   2329        return angle::Result::Continue;
   2330    }
   2331 
   2332    ASSERT(mTexStorage != nullptr);
   2333    GLint storageLevels = mTexStorage->getLevelCount();
   2334    for (int face = 0; face < static_cast<int>(gl::kCubeFaceCount); face++)
   2335    {
   2336        for (int level = 0; level < storageLevels; level++)
   2337        {
   2338            if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
   2339            {
   2340                ANGLE_TRY(updateStorageFaceLevel(context, face, level));
   2341            }
   2342        }
   2343    }
   2344 
   2345    mDirtyImages = false;
   2346    return angle::Result::Continue;
   2347 }
   2348 
   2349 bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
   2350 {
   2351    return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
   2352 }
   2353 
   2354 bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
   2355 {
   2356    if (getBaseLevel() >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
   2357    {
   2358        return false;
   2359    }
   2360    ASSERT(level >= 0 && static_cast<size_t>(faceIndex) < gl::kCubeFaceCount &&
   2361           level < static_cast<int>(mImageArray[faceIndex].size()) &&
   2362           mImageArray[faceIndex][level] != nullptr);
   2363 
   2364    if (isImmutable())
   2365    {
   2366        return true;
   2367    }
   2368 
   2369    int levelZeroSize = getLevelZeroWidth();
   2370 
   2371    if (levelZeroSize <= 0)
   2372    {
   2373        return false;
   2374    }
   2375 
   2376    // Check that non-zero levels are consistent with the base level.
   2377    const ImageD3D *faceLevelImage = mImageArray[faceIndex][level].get();
   2378 
   2379    if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
   2380    {
   2381        return false;
   2382    }
   2383 
   2384    if (faceLevelImage->getWidth() != std::max(1, levelZeroSize >> level))
   2385    {
   2386        return false;
   2387    }
   2388 
   2389    return true;
   2390 }
   2391 
   2392 bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const
   2393 {
   2394    return isFaceLevelComplete(index.cubeMapFaceIndex(), index.getLevelIndex());
   2395 }
   2396 
   2397 angle::Result TextureD3D_Cube::updateStorageFaceLevel(const gl::Context *context,
   2398                                                      int faceIndex,
   2399                                                      int level)
   2400 {
   2401    ASSERT(level >= 0 && static_cast<size_t>(faceIndex) < gl::kCubeFaceCount &&
   2402           level < static_cast<int>(mImageArray[faceIndex].size()) &&
   2403           mImageArray[faceIndex][level] != nullptr);
   2404    ImageD3D *image = mImageArray[faceIndex][level].get();
   2405 
   2406    if (image->isDirty())
   2407    {
   2408        gl::TextureTarget faceTarget = gl::CubeFaceIndexToTextureTarget(faceIndex);
   2409        gl::ImageIndex index         = gl::ImageIndex::MakeCubeMapFace(faceTarget, level);
   2410        gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
   2411        ANGLE_TRY(commitRegion(context, index, region));
   2412    }
   2413 
   2414    return angle::Result::Continue;
   2415 }
   2416 
   2417 angle::Result TextureD3D_Cube::redefineImage(const gl::Context *context,
   2418                                             int faceIndex,
   2419                                             GLint level,
   2420                                             GLenum internalformat,
   2421                                             const gl::Extents &size,
   2422                                             bool forceRelease)
   2423 {
   2424    // If there currently is a corresponding storage texture image, it has these parameters
   2425    const int storageWidth     = std::max(1, getLevelZeroWidth() >> level);
   2426    const int storageHeight    = std::max(1, getLevelZeroHeight() >> level);
   2427    const GLenum storageFormat = getBaseLevelInternalFormat();
   2428 
   2429    if (mTexStorage)
   2430    {
   2431        const int storageLevels = mTexStorage->getLevelCount();
   2432 
   2433        if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth ||
   2434            size.height != storageHeight ||
   2435            internalformat != storageFormat)  // Discard mismatched storage
   2436        {
   2437            markAllImagesDirty();
   2438 
   2439            gl::TexLevelMask copyImageMask;
   2440            copyImageMask.set();
   2441            copyImageMask.set(level, false);
   2442 
   2443            ANGLE_TRY(releaseTexStorage(context, copyImageMask));
   2444        }
   2445    }
   2446 
   2447    mImageArray[faceIndex][level]->redefine(gl::TextureType::CubeMap, internalformat, size,
   2448                                            forceRelease);
   2449    mDirtyImages = mDirtyImages || mImageArray[faceIndex][level]->isDirty();
   2450 
   2451    return angle::Result::Continue;
   2452 }
   2453 
   2454 gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
   2455 {
   2456    return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
   2457 }
   2458 
   2459 gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
   2460 {
   2461    // The "layer" of the image index corresponds to the cube face
   2462    return gl::ImageIndex::MakeCubeMapFace(gl::CubeFaceIndexToTextureTarget(layer), mip);
   2463 }
   2464 
   2465 bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const
   2466 {
   2467    return (mTexStorage && index.getType() == gl::TextureType::CubeMap &&
   2468            gl::IsCubeMapFaceTarget(index.getTarget()) && index.getLevelIndex() >= 0 &&
   2469            index.getLevelIndex() < mTexStorage->getLevelCount());
   2470 }
   2471 
   2472 void TextureD3D_Cube::markAllImagesDirty()
   2473 {
   2474    for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++)
   2475    {
   2476        for (size_t dirtyFace = 0; dirtyFace < gl::kCubeFaceCount; dirtyFace++)
   2477        {
   2478            mImageArray[dirtyFace][dirtyLevel]->markDirty();
   2479        }
   2480    }
   2481    mDirtyImages = true;
   2482 }
   2483 
   2484 TextureD3D_3D::TextureD3D_3D(const gl::TextureState &state, RendererD3D *renderer)
   2485    : TextureD3D(state, renderer)
   2486 {
   2487    for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
   2488    {
   2489        mImageArray[i].reset(renderer->createImage());
   2490    }
   2491 }
   2492 
   2493 void TextureD3D_3D::onDestroy(const gl::Context *context)
   2494 {
   2495    // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage
   2496    // for some of their data. If TextureStorage is deleted before the Images, then their data will
   2497    // be wastefully copied back from the GPU before we delete the Images.
   2498    for (auto &image : mImageArray)
   2499    {
   2500        image.reset();
   2501    }
   2502    return TextureD3D::onDestroy(context);
   2503 }
   2504 
   2505 TextureD3D_3D::~TextureD3D_3D() {}
   2506 
   2507 ImageD3D *TextureD3D_3D::getImage(int level, int layer) const
   2508 {
   2509    ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
   2510    ASSERT(layer == 0);
   2511    return mImageArray[level].get();
   2512 }
   2513 
   2514 ImageD3D *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
   2515 {
   2516    ASSERT(index.getLevelIndex() < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
   2517    ASSERT(!index.hasLayer());
   2518    ASSERT(index.getType() == gl::TextureType::_3D);
   2519    return mImageArray[index.getLevelIndex()].get();
   2520 }
   2521 
   2522 GLsizei TextureD3D_3D::getLayerCount(int level) const
   2523 {
   2524    ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
   2525    return 1;
   2526 }
   2527 
   2528 GLsizei TextureD3D_3D::getWidth(GLint level) const
   2529 {
   2530    if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
   2531        return mImageArray[level]->getWidth();
   2532    else
   2533        return 0;
   2534 }
   2535 
   2536 GLsizei TextureD3D_3D::getHeight(GLint level) const
   2537 {
   2538    if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
   2539        return mImageArray[level]->getHeight();
   2540    else
   2541        return 0;
   2542 }
   2543 
   2544 GLsizei TextureD3D_3D::getDepth(GLint level) const
   2545 {
   2546    if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
   2547        return mImageArray[level]->getDepth();
   2548    else
   2549        return 0;
   2550 }
   2551 
   2552 GLenum TextureD3D_3D::getInternalFormat(GLint level) const
   2553 {
   2554    if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
   2555        return mImageArray[level]->getInternalFormat();
   2556    else
   2557        return GL_NONE;
   2558 }
   2559 
   2560 bool TextureD3D_3D::isDepth(GLint level) const
   2561 {
   2562    return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
   2563 }
   2564 
   2565 bool TextureD3D_3D::isSRGB(GLint level) const
   2566 {
   2567    return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).colorEncoding == GL_SRGB;
   2568 }
   2569 
   2570 angle::Result TextureD3D_3D::setEGLImageTarget(const gl::Context *context,
   2571                                               gl::TextureType type,
   2572                                               egl::Image *image)
   2573 {
   2574    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   2575    return angle::Result::Continue;
   2576 }
   2577 
   2578 angle::Result TextureD3D_3D::setImage(const gl::Context *context,
   2579                                      const gl::ImageIndex &index,
   2580                                      GLenum internalFormat,
   2581                                      const gl::Extents &size,
   2582                                      GLenum format,
   2583                                      GLenum type,
   2584                                      const gl::PixelUnpackState &unpack,
   2585                                      gl::Buffer *unpackBuffer,
   2586                                      const uint8_t *pixels)
   2587 {
   2588    ASSERT(index.getTarget() == gl::TextureTarget::_3D);
   2589    const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
   2590 
   2591    ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat,
   2592                            size, false));
   2593 
   2594    bool fastUnpacked = false;
   2595 
   2596    // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
   2597    if (isFastUnpackable(unpackBuffer, unpack, internalFormatInfo.sizedInternalFormat) &&
   2598        !size.empty() && isLevelComplete(index.getLevelIndex()))
   2599    {
   2600        // Will try to create RT storage if it does not exist
   2601        RenderTargetD3D *destRenderTarget = nullptr;
   2602        ANGLE_TRY(getRenderTarget(context, index, getRenderToTextureSamples(), &destRenderTarget));
   2603 
   2604        gl::Box destArea(0, 0, 0, getWidth(index.getLevelIndex()), getHeight(index.getLevelIndex()),
   2605                         getDepth(index.getLevelIndex()));
   2606 
   2607        ANGLE_TRY(fastUnpackPixels(context, unpack, unpackBuffer, pixels, destArea,
   2608                                   internalFormatInfo.sizedInternalFormat, type, destRenderTarget));
   2609 
   2610        // Ensure we don't overwrite our newly initialized data
   2611        mImageArray[index.getLevelIndex()]->markClean();
   2612 
   2613        fastUnpacked = true;
   2614    }
   2615 
   2616    if (!fastUnpacked)
   2617    {
   2618        ANGLE_TRY(setImageImpl(context, index, type, unpack, unpackBuffer, pixels, 0));
   2619    }
   2620 
   2621    return angle::Result::Continue;
   2622 }
   2623 
   2624 angle::Result TextureD3D_3D::setSubImage(const gl::Context *context,
   2625                                         const gl::ImageIndex &index,
   2626                                         const gl::Box &area,
   2627                                         GLenum format,
   2628                                         GLenum type,
   2629                                         const gl::PixelUnpackState &unpack,
   2630                                         gl::Buffer *unpackBuffer,
   2631                                         const uint8_t *pixels)
   2632 {
   2633    ASSERT(index.getTarget() == gl::TextureTarget::_3D);
   2634 
   2635    // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
   2636    GLenum mipFormat = getInternalFormat(index.getLevelIndex());
   2637    if (isFastUnpackable(unpackBuffer, unpack, mipFormat) && isLevelComplete(index.getLevelIndex()))
   2638    {
   2639        RenderTargetD3D *destRenderTarget = nullptr;
   2640        ANGLE_TRY(getRenderTarget(context, index, getRenderToTextureSamples(), &destRenderTarget));
   2641        ASSERT(!mImageArray[index.getLevelIndex()]->isDirty());
   2642 
   2643        return fastUnpackPixels(context, unpack, unpackBuffer, pixels, area, mipFormat, type,
   2644                                destRenderTarget);
   2645    }
   2646    else
   2647    {
   2648        return TextureD3D::subImage(context, index, area, format, type, unpack, unpackBuffer,
   2649                                    pixels, 0);
   2650    }
   2651 }
   2652 
   2653 angle::Result TextureD3D_3D::setCompressedImage(const gl::Context *context,
   2654                                                const gl::ImageIndex &index,
   2655                                                GLenum internalFormat,
   2656                                                const gl::Extents &size,
   2657                                                const gl::PixelUnpackState &unpack,
   2658                                                size_t imageSize,
   2659                                                const uint8_t *pixels)
   2660 {
   2661    ASSERT(index.getTarget() == gl::TextureTarget::_3D);
   2662 
   2663    // compressed formats don't have separate sized internal formats-- we can just use the
   2664    // compressed format directly
   2665    ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormat, size, false));
   2666 
   2667    return setCompressedImageImpl(context, index, unpack, pixels, 0);
   2668 }
   2669 
   2670 angle::Result TextureD3D_3D::setCompressedSubImage(const gl::Context *context,
   2671                                                   const gl::ImageIndex &index,
   2672                                                   const gl::Box &area,
   2673                                                   GLenum format,
   2674                                                   const gl::PixelUnpackState &unpack,
   2675                                                   size_t imageSize,
   2676                                                   const uint8_t *pixels)
   2677 {
   2678    ASSERT(index.getTarget() == gl::TextureTarget::_3D);
   2679 
   2680    ANGLE_TRY(TextureD3D::subImageCompressed(context, index, area, format, unpack, pixels, 0));
   2681    return commitRegion(context, index, area);
   2682 }
   2683 
   2684 angle::Result TextureD3D_3D::copyImage(const gl::Context *context,
   2685                                       const gl::ImageIndex &index,
   2686                                       const gl::Rectangle &sourceArea,
   2687                                       GLenum internalFormat,
   2688                                       gl::Framebuffer *source)
   2689 {
   2690    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   2691    return angle::Result::Continue;
   2692 }
   2693 
   2694 angle::Result TextureD3D_3D::copySubImage(const gl::Context *context,
   2695                                          const gl::ImageIndex &index,
   2696                                          const gl::Offset &destOffset,
   2697                                          const gl::Rectangle &sourceArea,
   2698                                          gl::Framebuffer *source)
   2699 {
   2700    ASSERT(index.getTarget() == gl::TextureTarget::_3D);
   2701 
   2702    gl::Extents fbSize = source->getReadColorAttachment()->getSize();
   2703    gl::Rectangle clippedSourceArea;
   2704    if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height),
   2705                       &clippedSourceArea))
   2706    {
   2707        return angle::Result::Continue;
   2708    }
   2709    const gl::Offset clippedDestOffset(destOffset.x + clippedSourceArea.x - sourceArea.x,
   2710                                       destOffset.y + clippedSourceArea.y - sourceArea.y,
   2711                                       destOffset.z);
   2712 
   2713    // Currently, copying directly to the storage is not possible because it's not possible to
   2714    // create an SRV from a single layer of a 3D texture.  Instead, make sure the image is up to
   2715    // date before the copy and then copy back to the storage afterwards if needed.
   2716    // TODO: Investigate 3D blits in D3D11.
   2717 
   2718    bool syncTexStorage = mTexStorage && isLevelComplete(index.getLevelIndex());
   2719    if (syncTexStorage)
   2720    {
   2721        ANGLE_TRY(
   2722            mImageArray[index.getLevelIndex()]->copyFromTexStorage(context, index, mTexStorage));
   2723    }
   2724    ANGLE_TRY(mImageArray[index.getLevelIndex()]->copyFromFramebuffer(context, clippedDestOffset,
   2725                                                                      clippedSourceArea, source));
   2726    mDirtyImages = true;
   2727    onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
   2728 
   2729    if (syncTexStorage)
   2730    {
   2731        ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
   2732    }
   2733 
   2734    return angle::Result::Continue;
   2735 }
   2736 
   2737 angle::Result TextureD3D_3D::copyTexture(const gl::Context *context,
   2738                                         const gl::ImageIndex &index,
   2739                                         GLenum internalFormat,
   2740                                         GLenum type,
   2741                                         GLint sourceLevel,
   2742                                         bool unpackFlipY,
   2743                                         bool unpackPremultiplyAlpha,
   2744                                         bool unpackUnmultiplyAlpha,
   2745                                         const gl::Texture *source)
   2746 {
   2747    ASSERT(index.getTarget() == gl::TextureTarget::_3D);
   2748 
   2749    gl::TextureType sourceType = source->getType();
   2750 
   2751    const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
   2752    gl::Extents size(
   2753        static_cast<int>(source->getWidth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
   2754        static_cast<int>(source->getHeight(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
   2755        static_cast<int>(source->getDepth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)));
   2756 
   2757    ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat,
   2758                            size, false));
   2759 
   2760    gl::Box sourceBox(0, 0, 0, size.width, size.height, size.depth);
   2761    gl::Offset destOffset(0, 0, 0);
   2762    gl::ImageIndex destIndex = gl::ImageIndex::Make3D(static_cast<GLint>(index.getLevelIndex()));
   2763 
   2764    if (!isSRGB(index.getLevelIndex()) && canCreateRenderTargetForImage(destIndex))
   2765    {
   2766        ANGLE_TRY(ensureRenderTarget(context));
   2767        ASSERT(isValidLevel(index.getLevelIndex()));
   2768        ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
   2769 
   2770        ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_3D,
   2771                                         sourceBox, internalFormatInfo.format,
   2772                                         internalFormatInfo.type, destOffset, mTexStorage,
   2773                                         index.getTarget(), index.getLevelIndex(), unpackFlipY,
   2774                                         unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
   2775    }
   2776    else
   2777    {
   2778        gl::ImageIndex sourceIndex = gl::ImageIndex::Make3D(sourceLevel);
   2779        ImageD3D *sourceImage      = nullptr;
   2780        ImageD3D *destImage        = nullptr;
   2781        TextureD3D *sourceD3D      = GetImplAs<TextureD3D>(source);
   2782 
   2783        ANGLE_TRY(getImageAndSyncFromStorage(context, destIndex, &destImage));
   2784        ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceIndex, &sourceImage));
   2785 
   2786        ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
   2787                                       unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
   2788 
   2789        mDirtyImages = true;
   2790 
   2791        gl::Box destRegion(0, 0, 0, sourceBox.width, sourceBox.height, sourceBox.depth);
   2792        ANGLE_TRY(commitRegion(context, destIndex, destRegion));
   2793    }
   2794 
   2795    return angle::Result::Continue;
   2796 }
   2797 angle::Result TextureD3D_3D::copySubTexture(const gl::Context *context,
   2798                                            const gl::ImageIndex &index,
   2799                                            const gl::Offset &destOffset,
   2800                                            GLint sourceLevel,
   2801                                            const gl::Box &sourceBox,
   2802                                            bool unpackFlipY,
   2803                                            bool unpackPremultiplyAlpha,
   2804                                            bool unpackUnmultiplyAlpha,
   2805                                            const gl::Texture *source)
   2806 {
   2807    ASSERT(index.getTarget() == gl::TextureTarget::_3D);
   2808 
   2809    gl::ImageIndex destIndex = gl::ImageIndex::Make3D(static_cast<GLint>(index.getLevelIndex()));
   2810 
   2811    if (!isSRGB(index.getLevelIndex()) && canCreateRenderTargetForImage(destIndex))
   2812    {
   2813        ANGLE_TRY(ensureRenderTarget(context));
   2814        ASSERT(isValidLevel(index.getLevelIndex()));
   2815        ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
   2816 
   2817        const gl::InternalFormat &internalFormatInfo =
   2818            gl::GetSizedInternalFormatInfo(getInternalFormat(index.getLevelIndex()));
   2819        ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_3D,
   2820                                         sourceBox, internalFormatInfo.format,
   2821                                         internalFormatInfo.type, destOffset, mTexStorage,
   2822                                         index.getTarget(), index.getLevelIndex(), unpackFlipY,
   2823                                         unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
   2824    }
   2825    else
   2826    {
   2827        gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make3D(sourceLevel);
   2828        TextureD3D *sourceD3D           = GetImplAs<TextureD3D>(source);
   2829        ImageD3D *sourceImage           = nullptr;
   2830        ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage));
   2831 
   2832        ImageD3D *destImage = nullptr;
   2833        ANGLE_TRY(getImageAndSyncFromStorage(context, destIndex, &destImage));
   2834 
   2835        ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
   2836                                       unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
   2837 
   2838        mDirtyImages = true;
   2839 
   2840        gl::Box destRegion(destOffset.x, destOffset.y, destOffset.z, sourceBox.width,
   2841                           sourceBox.height, sourceBox.depth);
   2842        ANGLE_TRY(commitRegion(context, destIndex, destRegion));
   2843    }
   2844 
   2845    return angle::Result::Continue;
   2846 }
   2847 
   2848 angle::Result TextureD3D_3D::setStorage(const gl::Context *context,
   2849                                        gl::TextureType type,
   2850                                        size_t levels,
   2851                                        GLenum internalFormat,
   2852                                        const gl::Extents &size)
   2853 {
   2854    ASSERT(type == gl::TextureType::_3D);
   2855 
   2856    for (size_t level = 0; level < levels; level++)
   2857    {
   2858        gl::Extents levelSize(std::max(1, size.width >> level), std::max(1, size.height >> level),
   2859                              std::max(1, size.depth >> level));
   2860        mImageArray[level]->redefine(gl::TextureType::_3D, internalFormat, levelSize, true);
   2861    }
   2862 
   2863    for (size_t level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
   2864    {
   2865        mImageArray[level]->redefine(gl::TextureType::_3D, GL_NONE, gl::Extents(0, 0, 0), true);
   2866    }
   2867 
   2868    // TODO(geofflang): Verify storage creation had no errors
   2869    BindFlags bindFlags;
   2870    bindFlags.renderTarget    = IsRenderTargetUsage(mState.getUsage());
   2871    TexStoragePointer storage = {
   2872        mRenderer->createTextureStorage3D(internalFormat, bindFlags, size.width, size.height,
   2873                                          size.depth, static_cast<int>(levels), mState.getLabel()),
   2874        context};
   2875 
   2876    ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
   2877    storage.release();
   2878 
   2879    ANGLE_TRY(updateStorage(context));
   2880 
   2881    mImmutable = true;
   2882 
   2883    return angle::Result::Continue;
   2884 }
   2885 
   2886 angle::Result TextureD3D_3D::bindTexImage(const gl::Context *context, egl::Surface *surface)
   2887 {
   2888    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   2889    return angle::Result::Continue;
   2890 }
   2891 
   2892 angle::Result TextureD3D_3D::releaseTexImage(const gl::Context *context)
   2893 {
   2894    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   2895    return angle::Result::Continue;
   2896 }
   2897 
   2898 angle::Result TextureD3D_3D::initMipmapImages(const gl::Context *context)
   2899 {
   2900    const GLuint baseLevel = mState.getEffectiveBaseLevel();
   2901    const GLuint maxLevel  = mState.getMipmapMaxLevel();
   2902    // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap
   2903    // levels.
   2904    for (GLuint level = baseLevel + 1; level <= maxLevel; level++)
   2905    {
   2906        gl::Extents levelSize(std::max(getLevelZeroWidth() >> level, 1),
   2907                              std::max(getLevelZeroHeight() >> level, 1),
   2908                              std::max(getLevelZeroDepth() >> level, 1));
   2909        ANGLE_TRY(redefineImage(context, level, getBaseLevelInternalFormat(), levelSize, false));
   2910    }
   2911 
   2912    // We should be mip-complete now so generate the storage.
   2913    ANGLE_TRY(initializeStorage(context, BindFlags::RenderTarget()));
   2914 
   2915    return angle::Result::Continue;
   2916 }
   2917 
   2918 angle::Result TextureD3D_3D::getRenderTarget(const gl::Context *context,
   2919                                             const gl::ImageIndex &index,
   2920                                             GLsizei samples,
   2921                                             RenderTargetD3D **outRT)
   2922 {
   2923    // ensure the underlying texture is created
   2924    ANGLE_TRY(ensureRenderTarget(context));
   2925 
   2926    if (index.hasLayer())
   2927    {
   2928        ANGLE_TRY(updateStorage(context));
   2929    }
   2930    else
   2931    {
   2932        ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
   2933    }
   2934 
   2935    return mTexStorage->getRenderTarget(context, index, samples, outRT);
   2936 }
   2937 
   2938 angle::Result TextureD3D_3D::initializeStorage(const gl::Context *context, BindFlags bindFlags)
   2939 {
   2940    // Only initialize the first time this texture is used as a render target or shader resource
   2941    if (mTexStorage)
   2942    {
   2943        return angle::Result::Continue;
   2944    }
   2945 
   2946    // do not attempt to create storage for nonexistant data
   2947    if (!isLevelComplete(getBaseLevel()))
   2948    {
   2949        return angle::Result::Continue;
   2950    }
   2951 
   2952    TexStoragePointer storage;
   2953    ANGLE_TRY(createCompleteStorage(context, bindFlags, &storage));
   2954 
   2955    ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
   2956    storage.release();
   2957 
   2958    ASSERT(mTexStorage);
   2959 
   2960    // flush image data to the storage
   2961    ANGLE_TRY(updateStorage(context));
   2962 
   2963    return angle::Result::Continue;
   2964 }
   2965 
   2966 angle::Result TextureD3D_3D::createCompleteStorage(const gl::Context *context,
   2967                                                   BindFlags bindFlags,
   2968                                                   TexStoragePointer *outStorage) const
   2969 {
   2970    GLsizei width         = getLevelZeroWidth();
   2971    GLsizei height        = getLevelZeroHeight();
   2972    GLsizei depth         = getLevelZeroDepth();
   2973    GLenum internalFormat = getBaseLevelInternalFormat();
   2974 
   2975    ASSERT(width > 0 && height > 0 && depth > 0);
   2976 
   2977    // use existing storage level count, when previously specified by TexStorage*D
   2978    GLint levels =
   2979        (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
   2980 
   2981    // TODO: Verify creation of the storage succeeded
   2982    *outStorage = {mRenderer->createTextureStorage3D(internalFormat, bindFlags, width, height,
   2983                                                     depth, levels, mState.getLabel()),
   2984                   context};
   2985 
   2986    return angle::Result::Continue;
   2987 }
   2988 
   2989 angle::Result TextureD3D_3D::setCompleteTexStorage(const gl::Context *context,
   2990                                                   TextureStorage *newCompleteTexStorage)
   2991 {
   2992    gl::TexLevelMask copyImageMask;
   2993    copyImageMask.set();
   2994 
   2995    ANGLE_TRY(releaseTexStorage(context, copyImageMask));
   2996    mTexStorage = newCompleteTexStorage;
   2997    mTexStorageObserverBinding.bind(mTexStorage);
   2998    mDirtyImages = true;
   2999 
   3000    // We do not support managed 3D storage, as that is D3D9/ES2-only
   3001    ASSERT(!mTexStorage->isManaged());
   3002 
   3003    return angle::Result::Continue;
   3004 }
   3005 
   3006 angle::Result TextureD3D_3D::updateStorage(const gl::Context *context)
   3007 {
   3008    if (!mDirtyImages)
   3009    {
   3010        return angle::Result::Continue;
   3011    }
   3012 
   3013    ASSERT(mTexStorage != nullptr);
   3014    GLint storageLevels = mTexStorage->getLevelCount();
   3015    for (int level = 0; level < storageLevels; level++)
   3016    {
   3017        if (mImageArray[level]->isDirty() && isLevelComplete(level))
   3018        {
   3019            ANGLE_TRY(updateStorageLevel(context, level));
   3020        }
   3021    }
   3022 
   3023    mDirtyImages = false;
   3024    return angle::Result::Continue;
   3025 }
   3026 
   3027 bool TextureD3D_3D::isValidLevel(int level) const
   3028 {
   3029    return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
   3030 }
   3031 
   3032 bool TextureD3D_3D::isLevelComplete(int level) const
   3033 {
   3034    ASSERT(level >= 0 && level < static_cast<int>(mImageArray.size()) &&
   3035           mImageArray[level] != nullptr);
   3036 
   3037    if (isImmutable())
   3038    {
   3039        return true;
   3040    }
   3041 
   3042    GLsizei width  = getLevelZeroWidth();
   3043    GLsizei height = getLevelZeroHeight();
   3044    GLsizei depth  = getLevelZeroDepth();
   3045 
   3046    if (width <= 0 || height <= 0 || depth <= 0)
   3047    {
   3048        return false;
   3049    }
   3050 
   3051    if (level == static_cast<int>(getBaseLevel()))
   3052    {
   3053        return true;
   3054    }
   3055 
   3056    ImageD3D *levelImage = mImageArray[level].get();
   3057 
   3058    if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
   3059    {
   3060        return false;
   3061    }
   3062 
   3063    if (levelImage->getWidth() != std::max(1, width >> level))
   3064    {
   3065        return false;
   3066    }
   3067 
   3068    if (levelImage->getHeight() != std::max(1, height >> level))
   3069    {
   3070        return false;
   3071    }
   3072 
   3073    if (levelImage->getDepth() != std::max(1, depth >> level))
   3074    {
   3075        return false;
   3076    }
   3077 
   3078    return true;
   3079 }
   3080 
   3081 bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const
   3082 {
   3083    return isLevelComplete(index.getLevelIndex());
   3084 }
   3085 
   3086 angle::Result TextureD3D_3D::updateStorageLevel(const gl::Context *context, int level)
   3087 {
   3088    ASSERT(level >= 0 && level < static_cast<int>(mImageArray.size()) &&
   3089           mImageArray[level] != nullptr);
   3090    ASSERT(isLevelComplete(level));
   3091 
   3092    if (mImageArray[level]->isDirty())
   3093    {
   3094        gl::ImageIndex index = gl::ImageIndex::Make3D(level);
   3095        gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
   3096        ANGLE_TRY(commitRegion(context, index, region));
   3097    }
   3098 
   3099    return angle::Result::Continue;
   3100 }
   3101 
   3102 angle::Result TextureD3D_3D::redefineImage(const gl::Context *context,
   3103                                           GLint level,
   3104                                           GLenum internalformat,
   3105                                           const gl::Extents &size,
   3106                                           bool forceRelease)
   3107 {
   3108    // If there currently is a corresponding storage texture image, it has these parameters
   3109    const int storageWidth     = std::max(1, getLevelZeroWidth() >> level);
   3110    const int storageHeight    = std::max(1, getLevelZeroHeight() >> level);
   3111    const int storageDepth     = std::max(1, getLevelZeroDepth() >> level);
   3112    const GLenum storageFormat = getBaseLevelInternalFormat();
   3113 
   3114    if (mTexStorage)
   3115    {
   3116        const int storageLevels = mTexStorage->getLevelCount();
   3117 
   3118        if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth ||
   3119            size.height != storageHeight || size.depth != storageDepth ||
   3120            internalformat != storageFormat)  // Discard mismatched storage
   3121        {
   3122            markAllImagesDirty();
   3123 
   3124            gl::TexLevelMask copyImageMask;
   3125            copyImageMask.set();
   3126            copyImageMask.set(level, false);
   3127 
   3128            ANGLE_TRY(releaseTexStorage(context, copyImageMask));
   3129        }
   3130    }
   3131 
   3132    mImageArray[level]->redefine(gl::TextureType::_3D, internalformat, size, forceRelease);
   3133    mDirtyImages = mDirtyImages || mImageArray[level]->isDirty();
   3134 
   3135    return angle::Result::Continue;
   3136 }
   3137 
   3138 gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
   3139 {
   3140    return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
   3141                                          gl::ImageIndex::kEntireLevel,
   3142                                          gl::ImageIndex::kEntireLevel);
   3143 }
   3144 
   3145 gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
   3146 {
   3147    // The "layer" here does not apply to 3D images. We use one Image per mip.
   3148    return gl::ImageIndex::Make3D(mip);
   3149 }
   3150 
   3151 bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const
   3152 {
   3153    return (mTexStorage && index.getType() == gl::TextureType::_3D && index.getLevelIndex() >= 0 &&
   3154            index.getLevelIndex() < mTexStorage->getLevelCount());
   3155 }
   3156 
   3157 void TextureD3D_3D::markAllImagesDirty()
   3158 {
   3159    for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
   3160    {
   3161        mImageArray[i]->markDirty();
   3162    }
   3163    mDirtyImages = true;
   3164 }
   3165 
   3166 GLint TextureD3D_3D::getLevelZeroDepth() const
   3167 {
   3168    ASSERT(gl::CountLeadingZeros(static_cast<uint32_t>(getBaseLevelDepth())) > getBaseLevel());
   3169    return getBaseLevelDepth() << getBaseLevel();
   3170 }
   3171 
   3172 TextureD3D_2DArray::TextureD3D_2DArray(const gl::TextureState &state, RendererD3D *renderer)
   3173    : TextureD3D(state, renderer)
   3174 {
   3175    for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
   3176    {
   3177        mLayerCounts[level] = 0;
   3178        mImageArray[level]  = nullptr;
   3179    }
   3180 }
   3181 
   3182 void TextureD3D_2DArray::onDestroy(const gl::Context *context)
   3183 {
   3184    // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage
   3185    // for some of their data. If TextureStorage is deleted before the Images, then their data will
   3186    // be wastefully copied back from the GPU before we delete the Images.
   3187    deleteImages();
   3188    return TextureD3D::onDestroy(context);
   3189 }
   3190 
   3191 TextureD3D_2DArray::~TextureD3D_2DArray() {}
   3192 
   3193 ImageD3D *TextureD3D_2DArray::getImage(int level, int layer) const
   3194 {
   3195    ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
   3196    ASSERT((layer == 0 && mLayerCounts[level] == 0) || layer < mLayerCounts[level]);
   3197    return (mImageArray[level] ? mImageArray[level][layer] : nullptr);
   3198 }
   3199 
   3200 ImageD3D *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
   3201 {
   3202    ASSERT(index.getLevelIndex() < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
   3203    ASSERT(index.hasLayer());
   3204    ASSERT((index.getLayerIndex() == 0 && mLayerCounts[index.getLevelIndex()] == 0) ||
   3205           index.getLayerIndex() < mLayerCounts[index.getLevelIndex()]);
   3206    ASSERT(index.getType() == gl::TextureType::_2DArray);
   3207    return (mImageArray[index.getLevelIndex()]
   3208                ? mImageArray[index.getLevelIndex()][index.getLayerIndex()]
   3209                : nullptr);
   3210 }
   3211 
   3212 GLsizei TextureD3D_2DArray::getLayerCount(int level) const
   3213 {
   3214    ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
   3215    return mLayerCounts[level];
   3216 }
   3217 
   3218 GLsizei TextureD3D_2DArray::getWidth(GLint level) const
   3219 {
   3220    return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0)
   3221               ? mImageArray[level][0]->getWidth()
   3222               : 0;
   3223 }
   3224 
   3225 GLsizei TextureD3D_2DArray::getHeight(GLint level) const
   3226 {
   3227    return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0)
   3228               ? mImageArray[level][0]->getHeight()
   3229               : 0;
   3230 }
   3231 
   3232 GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
   3233 {
   3234    return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0)
   3235               ? mImageArray[level][0]->getInternalFormat()
   3236               : GL_NONE;
   3237 }
   3238 
   3239 bool TextureD3D_2DArray::isDepth(GLint level) const
   3240 {
   3241    return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
   3242 }
   3243 
   3244 bool TextureD3D_2DArray::isSRGB(GLint level) const
   3245 {
   3246    return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).colorEncoding == GL_SRGB;
   3247 }
   3248 
   3249 angle::Result TextureD3D_2DArray::setEGLImageTarget(const gl::Context *context,
   3250                                                    gl::TextureType type,
   3251                                                    egl::Image *image)
   3252 {
   3253    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   3254    return angle::Result::Continue;
   3255 }
   3256 
   3257 angle::Result TextureD3D_2DArray::setImage(const gl::Context *context,
   3258                                           const gl::ImageIndex &index,
   3259                                           GLenum internalFormat,
   3260                                           const gl::Extents &size,
   3261                                           GLenum format,
   3262                                           GLenum type,
   3263                                           const gl::PixelUnpackState &unpack,
   3264                                           gl::Buffer *unpackBuffer,
   3265                                           const uint8_t *pixels)
   3266 {
   3267    ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
   3268 
   3269    const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat, type);
   3270 
   3271    ANGLE_TRY(
   3272        redefineImage(context, index.getLevelIndex(), formatInfo.sizedInternalFormat, size, false));
   3273 
   3274    ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
   3275 
   3276    GLuint inputDepthPitch = 0;
   3277    ANGLE_CHECK_GL_MATH(contextD3D, formatInfo.computeDepthPitch(
   3278                                        type, size.width, size.height, unpack.alignment,
   3279                                        unpack.rowLength, unpack.imageHeight, &inputDepthPitch));
   3280 
   3281    for (int i = 0; i < size.depth; i++)
   3282    {
   3283        const ptrdiff_t layerOffset = (inputDepthPitch * i);
   3284        gl::ImageIndex layerIndex   = gl::ImageIndex::Make2DArray(index.getLevelIndex(), i);
   3285        ANGLE_TRY(
   3286            setImageImpl(context, layerIndex, type, unpack, unpackBuffer, pixels, layerOffset));
   3287    }
   3288 
   3289    return angle::Result::Continue;
   3290 }
   3291 
   3292 angle::Result TextureD3D_2DArray::setSubImage(const gl::Context *context,
   3293                                              const gl::ImageIndex &index,
   3294                                              const gl::Box &area,
   3295                                              GLenum format,
   3296                                              GLenum type,
   3297                                              const gl::PixelUnpackState &unpack,
   3298                                              gl::Buffer *unpackBuffer,
   3299                                              const uint8_t *pixels)
   3300 {
   3301    ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
   3302 
   3303    ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
   3304    const gl::InternalFormat &formatInfo =
   3305        gl::GetInternalFormatInfo(getInternalFormat(index.getLevelIndex()), type);
   3306    GLuint inputDepthPitch = 0;
   3307    ANGLE_CHECK_GL_MATH(contextD3D, formatInfo.computeDepthPitch(
   3308                                        type, area.width, area.height, unpack.alignment,
   3309                                        unpack.rowLength, unpack.imageHeight, &inputDepthPitch));
   3310 
   3311    for (int i = 0; i < area.depth; i++)
   3312    {
   3313        int layer                   = area.z + i;
   3314        const ptrdiff_t layerOffset = (inputDepthPitch * i);
   3315 
   3316        gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1);
   3317 
   3318        gl::ImageIndex layerIndex = gl::ImageIndex::Make2DArray(index.getLevelIndex(), layer);
   3319        ANGLE_TRY(TextureD3D::subImage(context, layerIndex, layerArea, format, type, unpack,
   3320                                       unpackBuffer, pixels, layerOffset));
   3321    }
   3322 
   3323    return angle::Result::Continue;
   3324 }
   3325 
   3326 angle::Result TextureD3D_2DArray::setCompressedImage(const gl::Context *context,
   3327                                                     const gl::ImageIndex &index,
   3328                                                     GLenum internalFormat,
   3329                                                     const gl::Extents &size,
   3330                                                     const gl::PixelUnpackState &unpack,
   3331                                                     size_t imageSize,
   3332                                                     const uint8_t *pixels)
   3333 {
   3334    ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
   3335 
   3336    ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
   3337 
   3338    // compressed formats don't have separate sized internal formats-- we can just use the
   3339    // compressed format directly
   3340    ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormat, size, false));
   3341 
   3342    const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
   3343    GLuint inputDepthPitch               = 0;
   3344    ANGLE_CHECK_GL_MATH(
   3345        contextD3D, formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, size.width, size.height, 1, 0, 0,
   3346                                                 &inputDepthPitch));
   3347 
   3348    for (int i = 0; i < size.depth; i++)
   3349    {
   3350        const ptrdiff_t layerOffset = (inputDepthPitch * i);
   3351 
   3352        gl::ImageIndex layerIndex = gl::ImageIndex::Make2DArray(index.getLevelIndex(), i);
   3353        ANGLE_TRY(setCompressedImageImpl(context, layerIndex, unpack, pixels, layerOffset));
   3354    }
   3355 
   3356    return angle::Result::Continue;
   3357 }
   3358 
   3359 angle::Result TextureD3D_2DArray::setCompressedSubImage(const gl::Context *context,
   3360                                                        const gl::ImageIndex &index,
   3361                                                        const gl::Box &area,
   3362                                                        GLenum format,
   3363                                                        const gl::PixelUnpackState &unpack,
   3364                                                        size_t imageSize,
   3365                                                        const uint8_t *pixels)
   3366 {
   3367    ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
   3368 
   3369    ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
   3370 
   3371    const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(format);
   3372    GLuint inputDepthPitch               = 0;
   3373    ANGLE_CHECK_GL_MATH(
   3374        contextD3D, formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1, 0, 0,
   3375                                                 &inputDepthPitch));
   3376 
   3377    for (int i = 0; i < area.depth; i++)
   3378    {
   3379        int layer                   = area.z + i;
   3380        const ptrdiff_t layerOffset = (inputDepthPitch * i);
   3381 
   3382        gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1);
   3383 
   3384        gl::ImageIndex layerIndex = gl::ImageIndex::Make2DArray(index.getLevelIndex(), layer);
   3385        ANGLE_TRY(TextureD3D::subImageCompressed(context, layerIndex, layerArea, format, unpack,
   3386                                                 pixels, layerOffset));
   3387        ANGLE_TRY(commitRegion(context, layerIndex, layerArea));
   3388    }
   3389 
   3390    return angle::Result::Continue;
   3391 }
   3392 
   3393 angle::Result TextureD3D_2DArray::copyImage(const gl::Context *context,
   3394                                            const gl::ImageIndex &index,
   3395                                            const gl::Rectangle &sourceArea,
   3396                                            GLenum internalFormat,
   3397                                            gl::Framebuffer *source)
   3398 {
   3399    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   3400    return angle::Result::Continue;
   3401 }
   3402 
   3403 angle::Result TextureD3D_2DArray::copySubImage(const gl::Context *context,
   3404                                               const gl::ImageIndex &index,
   3405                                               const gl::Offset &destOffset,
   3406                                               const gl::Rectangle &sourceArea,
   3407                                               gl::Framebuffer *source)
   3408 {
   3409    ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
   3410 
   3411    gl::Extents fbSize = source->getReadColorAttachment()->getSize();
   3412    gl::Rectangle clippedSourceArea;
   3413    if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height),
   3414                       &clippedSourceArea))
   3415    {
   3416        return angle::Result::Continue;
   3417    }
   3418    const gl::Offset clippedDestOffset(destOffset.x + clippedSourceArea.x - sourceArea.x,
   3419                                       destOffset.y + clippedSourceArea.y - sourceArea.y,
   3420                                       destOffset.z);
   3421 
   3422    if (!canCreateRenderTargetForImage(index))
   3423    {
   3424        gl::Offset destLayerOffset(clippedDestOffset.x, clippedDestOffset.y, 0);
   3425        ANGLE_TRY(mImageArray[index.getLevelIndex()][clippedDestOffset.z]->copyFromFramebuffer(
   3426            context, destLayerOffset, clippedSourceArea, source));
   3427        mDirtyImages = true;
   3428        onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
   3429    }
   3430    else
   3431    {
   3432        ANGLE_TRY(ensureRenderTarget(context));
   3433 
   3434        if (isValidLevel(index.getLevelIndex()))
   3435        {
   3436            ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
   3437            ANGLE_TRY(
   3438                mRenderer->copyImage2DArray(context, source, clippedSourceArea,
   3439                                            gl::GetUnsizedFormat(getInternalFormat(getBaseLevel())),
   3440                                            clippedDestOffset, mTexStorage, index.getLevelIndex()));
   3441        }
   3442    }
   3443    return angle::Result::Continue;
   3444 }
   3445 
   3446 angle::Result TextureD3D_2DArray::copyTexture(const gl::Context *context,
   3447                                              const gl::ImageIndex &index,
   3448                                              GLenum internalFormat,
   3449                                              GLenum type,
   3450                                              GLint sourceLevel,
   3451                                              bool unpackFlipY,
   3452                                              bool unpackPremultiplyAlpha,
   3453                                              bool unpackUnmultiplyAlpha,
   3454                                              const gl::Texture *source)
   3455 {
   3456    ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
   3457 
   3458    gl::TextureType sourceType = source->getType();
   3459 
   3460    const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
   3461    gl::Extents size(
   3462        static_cast<int>(source->getWidth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
   3463        static_cast<int>(source->getHeight(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
   3464        static_cast<int>(source->getDepth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)));
   3465 
   3466    ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat,
   3467                            size, false));
   3468 
   3469    gl::Box sourceBox(0, 0, 0, size.width, size.height, size.depth);
   3470    gl::Offset destOffset(0, 0, 0);
   3471 
   3472    gl::ImageIndex destIndex =
   3473        gl::ImageIndex::Make2DArrayRange(index.getLevelIndex(), 0, size.depth);
   3474 
   3475    if (!isSRGB(index.getLevelIndex()) &&
   3476        canCreateRenderTargetForImage(
   3477            gl::ImageIndex::Make2DArrayRange(index.getLevelIndex(), 0, size.depth)))
   3478    {
   3479        ANGLE_TRY(ensureRenderTarget(context));
   3480        ASSERT(isValidLevel(index.getLevelIndex()));
   3481        ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
   3482        ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2DArray,
   3483                                         sourceBox, internalFormatInfo.format,
   3484                                         internalFormatInfo.type, destOffset, mTexStorage,
   3485                                         index.getTarget(), index.getLevelIndex(), unpackFlipY,
   3486                                         unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
   3487    }
   3488    else
   3489    {
   3490        for (int i = 0; i < size.depth; i++)
   3491        {
   3492            gl::ImageIndex currentSourceDepthIndex = gl::ImageIndex::Make2DArray(sourceLevel, i);
   3493            gl::ImageIndex currentDestDepthIndex =
   3494                gl::ImageIndex::Make2DArray(index.getLevelIndex(), i);
   3495            ImageD3D *sourceImage = nullptr;
   3496            ImageD3D *destImage   = nullptr;
   3497            TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source);
   3498 
   3499            ANGLE_TRY(getImageAndSyncFromStorage(context, currentDestDepthIndex, &destImage));
   3500            ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, currentSourceDepthIndex,
   3501                                                            &sourceImage));
   3502            gl::Box imageBox(sourceBox.x, sourceBox.y, 0, sourceBox.width, sourceBox.height, 1);
   3503            ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, imageBox, destOffset,
   3504                                           unpackFlipY, unpackPremultiplyAlpha,
   3505                                           unpackUnmultiplyAlpha));
   3506        }
   3507 
   3508        mDirtyImages = true;
   3509 
   3510        gl::Box destRegion(destOffset.x, destOffset.y, destOffset.z, sourceBox.width,
   3511                           sourceBox.height, sourceBox.depth);
   3512        ANGLE_TRY(commitRegion(context, destIndex, destRegion));
   3513    }
   3514 
   3515    return angle::Result::Continue;
   3516 }
   3517 
   3518 angle::Result TextureD3D_2DArray::copySubTexture(const gl::Context *context,
   3519                                                 const gl::ImageIndex &index,
   3520                                                 const gl::Offset &destOffset,
   3521                                                 GLint sourceLevel,
   3522                                                 const gl::Box &sourceBox,
   3523                                                 bool unpackFlipY,
   3524                                                 bool unpackPremultiplyAlpha,
   3525                                                 bool unpackUnmultiplyAlpha,
   3526                                                 const gl::Texture *source)
   3527 {
   3528    ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
   3529 
   3530    gl::ImageIndex destIndex = gl::ImageIndex::Make2DArrayRange(
   3531        static_cast<GLint>(index.getLevelIndex()), destOffset.z, sourceBox.depth - destOffset.z);
   3532 
   3533    if (!isSRGB(destIndex.getLevelIndex()) && canCreateRenderTargetForImage(destIndex))
   3534    {
   3535        ANGLE_TRY(ensureRenderTarget(context));
   3536        ASSERT(isValidLevel(destIndex.getLevelIndex()));
   3537        ANGLE_TRY(updateStorageLevel(context, destIndex.getLevelIndex()));
   3538 
   3539        const gl::InternalFormat &internalFormatInfo =
   3540            gl::GetSizedInternalFormatInfo(getInternalFormat(destIndex.getLevelIndex()));
   3541        ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2DArray,
   3542                                         sourceBox, internalFormatInfo.format,
   3543                                         internalFormatInfo.type, destOffset, mTexStorage,
   3544                                         index.getTarget(), index.getLevelIndex(), unpackFlipY,
   3545                                         unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
   3546    }
   3547    else
   3548    {
   3549        for (int i = 0; i < sourceBox.depth; i++)
   3550        {
   3551            gl::ImageIndex currentSourceIndex =
   3552                gl::ImageIndex::Make2DArray(sourceLevel, i + sourceBox.z);
   3553            gl::ImageIndex currentDestIndex =
   3554                gl::ImageIndex::Make2DArray(index.getLevelIndex(), i + destOffset.z);
   3555 
   3556            gl::Box currentLayerBox(sourceBox.x, sourceBox.y, 0, sourceBox.width, sourceBox.height,
   3557                                    1);
   3558 
   3559            TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source);
   3560            ImageD3D *sourceImage = nullptr;
   3561            ANGLE_TRY(
   3562                sourceD3D->getImageAndSyncFromStorage(context, currentSourceIndex, &sourceImage));
   3563 
   3564            ImageD3D *destImage = nullptr;
   3565            ANGLE_TRY(getImageAndSyncFromStorage(context, currentDestIndex, &destImage));
   3566 
   3567            ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, currentLayerBox,
   3568                                           destOffset, unpackFlipY, unpackPremultiplyAlpha,
   3569                                           unpackUnmultiplyAlpha));
   3570        }
   3571 
   3572        mDirtyImages = true;
   3573 
   3574        gl::Box destRegion(destOffset.x, destOffset.y, destOffset.z, sourceBox.width,
   3575                           sourceBox.height, sourceBox.depth);
   3576        ANGLE_TRY(commitRegion(context, destIndex, destRegion));
   3577    }
   3578 
   3579    return angle::Result::Continue;
   3580 }
   3581 
   3582 angle::Result TextureD3D_2DArray::setStorage(const gl::Context *context,
   3583                                             gl::TextureType type,
   3584                                             size_t levels,
   3585                                             GLenum internalFormat,
   3586                                             const gl::Extents &size)
   3587 {
   3588    ASSERT(type == gl::TextureType::_2DArray);
   3589 
   3590    deleteImages();
   3591 
   3592    for (size_t level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
   3593    {
   3594        gl::Extents levelLayerSize(std::max(1, size.width >> level),
   3595                                   std::max(1, size.height >> level), 1);
   3596 
   3597        mLayerCounts[level] = (level < levels ? size.depth : 0);
   3598 
   3599        if (mLayerCounts[level] > 0)
   3600        {
   3601            // Create new images for this level
   3602            mImageArray[level] = new ImageD3D *[mLayerCounts[level]];
   3603 
   3604            for (int layer = 0; layer < mLayerCounts[level]; layer++)
   3605            {
   3606                mImageArray[level][layer] = mRenderer->createImage();
   3607                mImageArray[level][layer]->redefine(gl::TextureType::_2DArray, internalFormat,
   3608                                                    levelLayerSize, true);
   3609            }
   3610        }
   3611    }
   3612 
   3613    // TODO(geofflang): Verify storage creation had no errors
   3614    BindFlags bindFlags;
   3615    bindFlags.renderTarget    = IsRenderTargetUsage(mState.getUsage());
   3616    TexStoragePointer storage = {mRenderer->createTextureStorage2DArray(
   3617                                     internalFormat, bindFlags, size.width, size.height, size.depth,
   3618                                     static_cast<int>(levels), mState.getLabel()),
   3619                                 context};
   3620 
   3621    ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
   3622    storage.release();
   3623 
   3624    ANGLE_TRY(updateStorage(context));
   3625 
   3626    mImmutable = true;
   3627 
   3628    return angle::Result::Continue;
   3629 }
   3630 
   3631 angle::Result TextureD3D_2DArray::bindTexImage(const gl::Context *context, egl::Surface *surface)
   3632 {
   3633    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   3634    return angle::Result::Continue;
   3635 }
   3636 
   3637 angle::Result TextureD3D_2DArray::releaseTexImage(const gl::Context *context)
   3638 {
   3639    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   3640    return angle::Result::Continue;
   3641 }
   3642 
   3643 angle::Result TextureD3D_2DArray::initMipmapImages(const gl::Context *context)
   3644 {
   3645    const GLuint baseLevel = mState.getEffectiveBaseLevel();
   3646    const GLuint maxLevel  = mState.getMipmapMaxLevel();
   3647    int baseWidth          = getLevelZeroWidth();
   3648    int baseHeight         = getLevelZeroHeight();
   3649    int baseDepth          = getLayerCount(getBaseLevel());
   3650    GLenum baseFormat      = getBaseLevelInternalFormat();
   3651 
   3652    // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap
   3653    // levels.
   3654    for (GLuint level = baseLevel + 1u; level <= maxLevel; level++)
   3655    {
   3656        ASSERT((baseWidth >> level) > 0 || (baseHeight >> level) > 0);
   3657        gl::Extents levelLayerSize(std::max(baseWidth >> level, 1),
   3658                                   std::max(baseHeight >> level, 1), baseDepth);
   3659        ANGLE_TRY(redefineImage(context, level, baseFormat, levelLayerSize, false));
   3660    }
   3661 
   3662    // We should be mip-complete now so generate the storage.
   3663    ANGLE_TRY(initializeStorage(context, BindFlags::RenderTarget()));
   3664 
   3665    return angle::Result::Continue;
   3666 }
   3667 
   3668 angle::Result TextureD3D_2DArray::getRenderTarget(const gl::Context *context,
   3669                                                  const gl::ImageIndex &index,
   3670                                                  GLsizei samples,
   3671                                                  RenderTargetD3D **outRT)
   3672 {
   3673    // ensure the underlying texture is created
   3674    ANGLE_TRY(ensureRenderTarget(context));
   3675    ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
   3676    return mTexStorage->getRenderTarget(context, index, samples, outRT);
   3677 }
   3678 
   3679 angle::Result TextureD3D_2DArray::initializeStorage(const gl::Context *context, BindFlags bindFlags)
   3680 {
   3681    // Only initialize the first time this texture is used as a render target or shader resource
   3682    if (mTexStorage)
   3683    {
   3684        return angle::Result::Continue;
   3685    }
   3686 
   3687    // do not attempt to create storage for nonexistant data
   3688    if (!isLevelComplete(getBaseLevel()))
   3689    {
   3690        return angle::Result::Continue;
   3691    }
   3692 
   3693    bindFlags.renderTarget |= IsRenderTargetUsage(mState.getUsage());
   3694 
   3695    TexStoragePointer storage;
   3696    ANGLE_TRY(createCompleteStorage(context, bindFlags, &storage));
   3697 
   3698    ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
   3699    storage.release();
   3700 
   3701    ASSERT(mTexStorage);
   3702 
   3703    // flush image data to the storage
   3704    ANGLE_TRY(updateStorage(context));
   3705 
   3706    return angle::Result::Continue;
   3707 }
   3708 
   3709 angle::Result TextureD3D_2DArray::createCompleteStorage(const gl::Context *context,
   3710                                                        BindFlags bindFlags,
   3711                                                        TexStoragePointer *outStorage) const
   3712 {
   3713    GLsizei width         = getLevelZeroWidth();
   3714    GLsizei height        = getLevelZeroHeight();
   3715    GLsizei depth         = getLayerCount(getBaseLevel());
   3716    GLenum internalFormat = getBaseLevelInternalFormat();
   3717 
   3718    ASSERT(width > 0 && height > 0 && depth > 0);
   3719 
   3720    // use existing storage level count, when previously specified by TexStorage*D
   3721    GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
   3722 
   3723    // TODO(geofflang): Verify storage creation succeeds
   3724    *outStorage = {mRenderer->createTextureStorage2DArray(internalFormat, bindFlags, width, height,
   3725                                                          depth, levels, mState.getLabel()),
   3726                   context};
   3727 
   3728    return angle::Result::Continue;
   3729 }
   3730 
   3731 angle::Result TextureD3D_2DArray::setCompleteTexStorage(const gl::Context *context,
   3732                                                        TextureStorage *newCompleteTexStorage)
   3733 {
   3734    gl::TexLevelMask copyImageMask;
   3735    copyImageMask.set();
   3736 
   3737    ANGLE_TRY(releaseTexStorage(context, copyImageMask));
   3738    mTexStorage = newCompleteTexStorage;
   3739    mTexStorageObserverBinding.bind(mTexStorage);
   3740    mDirtyImages = true;
   3741 
   3742    // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
   3743    ASSERT(!mTexStorage->isManaged());
   3744 
   3745    return angle::Result::Continue;
   3746 }
   3747 
   3748 angle::Result TextureD3D_2DArray::updateStorage(const gl::Context *context)
   3749 {
   3750    if (!mDirtyImages)
   3751    {
   3752        return angle::Result::Continue;
   3753    }
   3754 
   3755    ASSERT(mTexStorage != nullptr);
   3756    GLint storageLevels = mTexStorage->getLevelCount();
   3757    for (int level = 0; level < storageLevels; level++)
   3758    {
   3759        if (isLevelComplete(level))
   3760        {
   3761            ANGLE_TRY(updateStorageLevel(context, level));
   3762        }
   3763    }
   3764 
   3765    mDirtyImages = false;
   3766    return angle::Result::Continue;
   3767 }
   3768 
   3769 bool TextureD3D_2DArray::isValidLevel(int level) const
   3770 {
   3771    return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
   3772 }
   3773 
   3774 bool TextureD3D_2DArray::isLevelComplete(int level) const
   3775 {
   3776    ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
   3777 
   3778    if (isImmutable())
   3779    {
   3780        return true;
   3781    }
   3782 
   3783    GLsizei width  = getLevelZeroWidth();
   3784    GLsizei height = getLevelZeroHeight();
   3785 
   3786    if (width <= 0 || height <= 0)
   3787    {
   3788        return false;
   3789    }
   3790 
   3791    // Layers check needs to happen after the above checks, otherwise out-of-range base level may be
   3792    // queried.
   3793    GLsizei layers = getLayerCount(getBaseLevel());
   3794 
   3795    if (layers <= 0)
   3796    {
   3797        return false;
   3798    }
   3799 
   3800    if (level == static_cast<int>(getBaseLevel()))
   3801    {
   3802        return true;
   3803    }
   3804 
   3805    if (getInternalFormat(level) != getInternalFormat(getBaseLevel()))
   3806    {
   3807        return false;
   3808    }
   3809 
   3810    if (getWidth(level) != std::max(1, width >> level))
   3811    {
   3812        return false;
   3813    }
   3814 
   3815    if (getHeight(level) != std::max(1, height >> level))
   3816    {
   3817        return false;
   3818    }
   3819 
   3820    if (getLayerCount(level) != layers)
   3821    {
   3822        return false;
   3823    }
   3824 
   3825    return true;
   3826 }
   3827 
   3828 bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const
   3829 {
   3830    return isLevelComplete(index.getLevelIndex());
   3831 }
   3832 
   3833 angle::Result TextureD3D_2DArray::updateStorageLevel(const gl::Context *context, int level)
   3834 {
   3835    ASSERT(level >= 0 && level < static_cast<int>(ArraySize(mLayerCounts)));
   3836    ASSERT(isLevelComplete(level));
   3837 
   3838    for (int layer = 0; layer < mLayerCounts[level]; layer++)
   3839    {
   3840        ASSERT(mImageArray[level] != nullptr && mImageArray[level][layer] != nullptr);
   3841        if (mImageArray[level][layer]->isDirty())
   3842        {
   3843            gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
   3844            gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
   3845            ANGLE_TRY(commitRegion(context, index, region));
   3846        }
   3847    }
   3848 
   3849    return angle::Result::Continue;
   3850 }
   3851 
   3852 void TextureD3D_2DArray::deleteImages()
   3853 {
   3854    for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
   3855    {
   3856        for (int layer = 0; layer < mLayerCounts[level]; ++layer)
   3857        {
   3858            delete mImageArray[level][layer];
   3859        }
   3860        delete[] mImageArray[level];
   3861        mImageArray[level]  = nullptr;
   3862        mLayerCounts[level] = 0;
   3863    }
   3864 }
   3865 
   3866 angle::Result TextureD3D_2DArray::redefineImage(const gl::Context *context,
   3867                                                GLint level,
   3868                                                GLenum internalformat,
   3869                                                const gl::Extents &size,
   3870                                                bool forceRelease)
   3871 {
   3872    // If there currently is a corresponding storage texture image, it has these parameters
   3873    const int storageWidth     = std::max(1, getLevelZeroWidth() >> level);
   3874    const int storageHeight    = std::max(1, getLevelZeroHeight() >> level);
   3875    const GLuint baseLevel     = getBaseLevel();
   3876    const GLenum storageFormat = getBaseLevelInternalFormat();
   3877 
   3878    int storageDepth = 0;
   3879    if (baseLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
   3880    {
   3881        storageDepth = getLayerCount(baseLevel);
   3882    }
   3883 
   3884    // Only reallocate the layers if the size doesn't match
   3885    if (size.depth != mLayerCounts[level])
   3886    {
   3887        for (int layer = 0; layer < mLayerCounts[level]; layer++)
   3888        {
   3889            SafeDelete(mImageArray[level][layer]);
   3890        }
   3891        SafeDeleteArray(mImageArray[level]);
   3892        mLayerCounts[level] = size.depth;
   3893 
   3894        if (size.depth > 0)
   3895        {
   3896            mImageArray[level] = new ImageD3D *[size.depth];
   3897            for (int layer = 0; layer < mLayerCounts[level]; layer++)
   3898            {
   3899                mImageArray[level][layer] = mRenderer->createImage();
   3900            }
   3901        }
   3902    }
   3903 
   3904    if (mTexStorage)
   3905    {
   3906        const int storageLevels = mTexStorage->getLevelCount();
   3907 
   3908        if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth ||
   3909            size.height != storageHeight || size.depth != storageDepth ||
   3910            internalformat != storageFormat)  // Discard mismatched storage
   3911        {
   3912            markAllImagesDirty();
   3913 
   3914            gl::TexLevelMask copyImageMask;
   3915            copyImageMask.set();
   3916            copyImageMask.set(level, false);
   3917 
   3918            ANGLE_TRY(releaseTexStorage(context, copyImageMask));
   3919        }
   3920    }
   3921 
   3922    if (size.depth > 0)
   3923    {
   3924        for (int layer = 0; layer < mLayerCounts[level]; layer++)
   3925        {
   3926            mImageArray[level][layer]->redefine(gl::TextureType::_2DArray, internalformat,
   3927                                                gl::Extents(size.width, size.height, 1),
   3928                                                forceRelease);
   3929            mDirtyImages = mDirtyImages || mImageArray[level][layer]->isDirty();
   3930        }
   3931    }
   3932 
   3933    return angle::Result::Continue;
   3934 }
   3935 
   3936 gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
   3937 {
   3938    return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
   3939 }
   3940 
   3941 gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
   3942 {
   3943    return gl::ImageIndex::Make2DArray(mip, layer);
   3944 }
   3945 
   3946 bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const
   3947 {
   3948    // Check for having a storage and the right type of index
   3949    if (!mTexStorage || index.getType() != gl::TextureType::_2DArray)
   3950    {
   3951        return false;
   3952    }
   3953 
   3954    // Check the mip index
   3955    if (index.getLevelIndex() < 0 || index.getLevelIndex() >= mTexStorage->getLevelCount())
   3956    {
   3957        return false;
   3958    }
   3959 
   3960    // Check the layer index
   3961    return (!index.hasLayer() || (index.getLayerIndex() >= 0 &&
   3962                                  index.getLayerIndex() < mLayerCounts[index.getLevelIndex()]));
   3963 }
   3964 
   3965 void TextureD3D_2DArray::markAllImagesDirty()
   3966 {
   3967    for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++)
   3968    {
   3969        for (int dirtyLayer = 0; dirtyLayer < mLayerCounts[dirtyLevel]; dirtyLayer++)
   3970        {
   3971            mImageArray[dirtyLevel][dirtyLayer]->markDirty();
   3972        }
   3973    }
   3974    mDirtyImages = true;
   3975 }
   3976 
   3977 TextureD3DImmutableBase::TextureD3DImmutableBase(const gl::TextureState &state,
   3978                                                 RendererD3D *renderer)
   3979    : TextureD3D(state, renderer)
   3980 {}
   3981 
   3982 TextureD3DImmutableBase::~TextureD3DImmutableBase() {}
   3983 
   3984 ImageD3D *TextureD3DImmutableBase::getImage(const gl::ImageIndex &index) const
   3985 {
   3986    return nullptr;
   3987 }
   3988 
   3989 angle::Result TextureD3DImmutableBase::setImage(const gl::Context *context,
   3990                                                const gl::ImageIndex &index,
   3991                                                GLenum internalFormat,
   3992                                                const gl::Extents &size,
   3993                                                GLenum format,
   3994                                                GLenum type,
   3995                                                const gl::PixelUnpackState &unpack,
   3996                                                gl::Buffer *unpackBuffer,
   3997                                                const uint8_t *pixels)
   3998 {
   3999    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   4000    return angle::Result::Continue;
   4001 }
   4002 
   4003 angle::Result TextureD3DImmutableBase::setSubImage(const gl::Context *context,
   4004                                                   const gl::ImageIndex &index,
   4005                                                   const gl::Box &area,
   4006                                                   GLenum format,
   4007                                                   GLenum type,
   4008                                                   const gl::PixelUnpackState &unpack,
   4009                                                   gl::Buffer *unpackBuffer,
   4010                                                   const uint8_t *pixels)
   4011 {
   4012    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   4013    return angle::Result::Continue;
   4014 }
   4015 
   4016 angle::Result TextureD3DImmutableBase::setCompressedImage(const gl::Context *context,
   4017                                                          const gl::ImageIndex &index,
   4018                                                          GLenum internalFormat,
   4019                                                          const gl::Extents &size,
   4020                                                          const gl::PixelUnpackState &unpack,
   4021                                                          size_t imageSize,
   4022                                                          const uint8_t *pixels)
   4023 {
   4024    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   4025    return angle::Result::Continue;
   4026 }
   4027 
   4028 angle::Result TextureD3DImmutableBase::setCompressedSubImage(const gl::Context *context,
   4029                                                             const gl::ImageIndex &index,
   4030                                                             const gl::Box &area,
   4031                                                             GLenum format,
   4032                                                             const gl::PixelUnpackState &unpack,
   4033                                                             size_t imageSize,
   4034                                                             const uint8_t *pixels)
   4035 {
   4036    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   4037    return angle::Result::Continue;
   4038 }
   4039 
   4040 angle::Result TextureD3DImmutableBase::copyImage(const gl::Context *context,
   4041                                                 const gl::ImageIndex &index,
   4042                                                 const gl::Rectangle &sourceArea,
   4043                                                 GLenum internalFormat,
   4044                                                 gl::Framebuffer *source)
   4045 {
   4046    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   4047    return angle::Result::Continue;
   4048 }
   4049 
   4050 angle::Result TextureD3DImmutableBase::copySubImage(const gl::Context *context,
   4051                                                    const gl::ImageIndex &index,
   4052                                                    const gl::Offset &destOffset,
   4053                                                    const gl::Rectangle &sourceArea,
   4054                                                    gl::Framebuffer *source)
   4055 {
   4056    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   4057    return angle::Result::Continue;
   4058 }
   4059 
   4060 angle::Result TextureD3DImmutableBase::bindTexImage(const gl::Context *context,
   4061                                                    egl::Surface *surface)
   4062 {
   4063    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   4064    return angle::Result::Continue;
   4065 }
   4066 
   4067 angle::Result TextureD3DImmutableBase::releaseTexImage(const gl::Context *context)
   4068 {
   4069    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   4070    return angle::Result::Continue;
   4071 }
   4072 
   4073 TextureD3D_External::TextureD3D_External(const gl::TextureState &state, RendererD3D *renderer)
   4074    : TextureD3DImmutableBase(state, renderer)
   4075 {}
   4076 
   4077 TextureD3D_External::~TextureD3D_External() {}
   4078 
   4079 GLsizei TextureD3D_External::getLayerCount(int level) const
   4080 {
   4081    return 1;
   4082 }
   4083 
   4084 angle::Result TextureD3D_External::setImageExternal(const gl::Context *context,
   4085                                                    gl::TextureType type,
   4086                                                    egl::Stream *stream,
   4087                                                    const egl::Stream::GLTextureDescription &desc)
   4088 {
   4089    ASSERT(type == gl::TextureType::External);
   4090 
   4091    ANGLE_TRY(releaseTexStorage(context, gl::TexLevelMask()));
   4092 
   4093    // If the stream is null, the external image is unbound and we release the storage
   4094    if (stream != nullptr)
   4095    {
   4096        mTexStorage = mRenderer->createTextureStorageExternal(stream, desc, mState.getLabel());
   4097    }
   4098 
   4099    return angle::Result::Continue;
   4100 }
   4101 
   4102 angle::Result TextureD3D_External::setEGLImageTarget(const gl::Context *context,
   4103                                                     gl::TextureType type,
   4104                                                     egl::Image *image)
   4105 {
   4106    EGLImageD3D *eglImaged3d = GetImplAs<EGLImageD3D>(image);
   4107 
   4108    // Pass in the RenderTargetD3D here: createTextureStorage can't generate an error.
   4109    RenderTargetD3D *renderTargetD3D = nullptr;
   4110    ANGLE_TRY(eglImaged3d->getRenderTarget(context, &renderTargetD3D));
   4111 
   4112    ANGLE_TRY(releaseTexStorage(context, gl::TexLevelMask()));
   4113    mTexStorage =
   4114        mRenderer->createTextureStorageEGLImage(eglImaged3d, renderTargetD3D, mState.getLabel());
   4115 
   4116    return angle::Result::Continue;
   4117 }
   4118 
   4119 angle::Result TextureD3D_External::initMipmapImages(const gl::Context *context)
   4120 {
   4121    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   4122    return angle::Result::Stop;
   4123 }
   4124 
   4125 angle::Result TextureD3D_External::getRenderTarget(const gl::Context *context,
   4126                                                   const gl::ImageIndex &index,
   4127                                                   GLsizei samples,
   4128                                                   RenderTargetD3D **outRT)
   4129 {
   4130    UNREACHABLE();
   4131    return angle::Result::Stop;
   4132 }
   4133 
   4134 bool TextureD3D_External::isImageComplete(const gl::ImageIndex &index) const
   4135 {
   4136    return (index.getLevelIndex() == 0) ? (mTexStorage != nullptr) : false;
   4137 }
   4138 
   4139 angle::Result TextureD3D_External::initializeStorage(const gl::Context *context,
   4140                                                     BindFlags bindFlags)
   4141 {
   4142    // Texture storage is created when an external image is bound
   4143    ASSERT(mTexStorage);
   4144    return angle::Result::Continue;
   4145 }
   4146 
   4147 angle::Result TextureD3D_External::createCompleteStorage(const gl::Context *context,
   4148                                                         BindFlags bindFlags,
   4149                                                         TexStoragePointer *outStorage) const
   4150 {
   4151    UNREACHABLE();
   4152    return angle::Result::Continue;
   4153 }
   4154 
   4155 angle::Result TextureD3D_External::setCompleteTexStorage(const gl::Context *context,
   4156                                                         TextureStorage *newCompleteTexStorage)
   4157 {
   4158    UNREACHABLE();
   4159    return angle::Result::Continue;
   4160 }
   4161 
   4162 angle::Result TextureD3D_External::updateStorage(const gl::Context *context)
   4163 {
   4164    // Texture storage does not need to be updated since it is already loaded with the latest
   4165    // external image
   4166    ASSERT(mTexStorage);
   4167    return angle::Result::Continue;
   4168 }
   4169 
   4170 gl::ImageIndexIterator TextureD3D_External::imageIterator() const
   4171 {
   4172    return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
   4173 }
   4174 
   4175 gl::ImageIndex TextureD3D_External::getImageIndex(GLint mip, GLint /*layer*/) const
   4176 {
   4177    // "layer" does not apply to 2D Textures.
   4178    return gl::ImageIndex::Make2D(mip);
   4179 }
   4180 
   4181 bool TextureD3D_External::isValidIndex(const gl::ImageIndex &index) const
   4182 {
   4183    return (mTexStorage && index.getType() == gl::TextureType::External &&
   4184            index.getLevelIndex() == 0);
   4185 }
   4186 
   4187 void TextureD3D_External::markAllImagesDirty()
   4188 {
   4189    UNREACHABLE();
   4190 }
   4191 
   4192 TextureD3D_2DMultisample::TextureD3D_2DMultisample(const gl::TextureState &state,
   4193                                                   RendererD3D *renderer)
   4194    : TextureD3DImmutableBase(state, renderer)
   4195 {}
   4196 
   4197 TextureD3D_2DMultisample::~TextureD3D_2DMultisample() {}
   4198 
   4199 angle::Result TextureD3D_2DMultisample::setStorageMultisample(const gl::Context *context,
   4200                                                              gl::TextureType type,
   4201                                                              GLsizei samples,
   4202                                                              GLint internalformat,
   4203                                                              const gl::Extents &size,
   4204                                                              bool fixedSampleLocations)
   4205 {
   4206    ASSERT(type == gl::TextureType::_2DMultisample && size.depth == 1);
   4207 
   4208    // We allocate storage immediately instead of doing it lazily like other TextureD3D classes do.
   4209    // This requires less state in this class.
   4210    TexStoragePointer storage = {mRenderer->createTextureStorage2DMultisample(
   4211                                     internalformat, size.width, size.height, static_cast<int>(0),
   4212                                     samples, fixedSampleLocations, mState.getLabel()),
   4213                                 context};
   4214 
   4215    ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
   4216    storage.release();
   4217 
   4218    mImmutable = true;
   4219 
   4220    return angle::Result::Continue;
   4221 }
   4222 
   4223 angle::Result TextureD3D_2DMultisample::setEGLImageTarget(const gl::Context *context,
   4224                                                          gl::TextureType type,
   4225                                                          egl::Image *image)
   4226 {
   4227    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   4228    return angle::Result::Continue;
   4229 }
   4230 
   4231 angle::Result TextureD3D_2DMultisample::getRenderTarget(const gl::Context *context,
   4232                                                        const gl::ImageIndex &index,
   4233                                                        GLsizei samples,
   4234                                                        RenderTargetD3D **outRT)
   4235 {
   4236    ASSERT(!index.hasLayer());
   4237 
   4238    // ensure the underlying texture is created
   4239    ANGLE_TRY(ensureRenderTarget(context));
   4240 
   4241    return mTexStorage->getRenderTarget(context, index, samples, outRT);
   4242 }
   4243 
   4244 gl::ImageIndexIterator TextureD3D_2DMultisample::imageIterator() const
   4245 {
   4246    return gl::ImageIndexIterator::Make2DMultisample();
   4247 }
   4248 
   4249 gl::ImageIndex TextureD3D_2DMultisample::getImageIndex(GLint mip, GLint layer) const
   4250 {
   4251    return gl::ImageIndex::Make2DMultisample();
   4252 }
   4253 
   4254 bool TextureD3D_2DMultisample::isValidIndex(const gl::ImageIndex &index) const
   4255 {
   4256    return (mTexStorage && index.getType() == gl::TextureType::_2DMultisample &&
   4257            index.getLevelIndex() == 0);
   4258 }
   4259 
   4260 GLsizei TextureD3D_2DMultisample::getLayerCount(int level) const
   4261 {
   4262    return 1;
   4263 }
   4264 
   4265 void TextureD3D_2DMultisample::markAllImagesDirty() {}
   4266 
   4267 angle::Result TextureD3D_2DMultisample::initializeStorage(const gl::Context *context,
   4268                                                          BindFlags bindFlags)
   4269 {
   4270    // initializeStorage should only be called in a situation where the texture already has storage
   4271    // associated with it (storage is created in setStorageMultisample).
   4272    ASSERT(mTexStorage);
   4273    return angle::Result::Continue;
   4274 }
   4275 
   4276 angle::Result TextureD3D_2DMultisample::createCompleteStorage(const gl::Context *context,
   4277                                                              BindFlags bindFlags,
   4278                                                              TexStoragePointer *outStorage) const
   4279 {
   4280    UNREACHABLE();
   4281    *outStorage = {mTexStorage, context};
   4282    return angle::Result::Continue;
   4283 }
   4284 
   4285 angle::Result TextureD3D_2DMultisample::setCompleteTexStorage(const gl::Context *context,
   4286                                                              TextureStorage *newCompleteTexStorage)
   4287 {
   4288    // These textures are immutable, so this should only be ever called once.
   4289    ASSERT(!mTexStorage);
   4290    mTexStorage = newCompleteTexStorage;
   4291    mTexStorageObserverBinding.bind(mTexStorage);
   4292    return angle::Result::Continue;
   4293 }
   4294 
   4295 angle::Result TextureD3D_2DMultisample::updateStorage(const gl::Context *context)
   4296 {
   4297    return angle::Result::Continue;
   4298 }
   4299 
   4300 angle::Result TextureD3D_2DMultisample::initMipmapImages(const gl::Context *context)
   4301 {
   4302    UNREACHABLE();
   4303    return angle::Result::Continue;
   4304 }
   4305 
   4306 bool TextureD3D_2DMultisample::isImageComplete(const gl::ImageIndex &index) const
   4307 {
   4308    return true;
   4309 }
   4310 
   4311 TextureD3D_2DMultisampleArray::TextureD3D_2DMultisampleArray(const gl::TextureState &state,
   4312                                                             RendererD3D *renderer)
   4313    : TextureD3DImmutableBase(state, renderer)
   4314 {}
   4315 
   4316 TextureD3D_2DMultisampleArray::~TextureD3D_2DMultisampleArray() {}
   4317 
   4318 angle::Result TextureD3D_2DMultisampleArray::setStorageMultisample(const gl::Context *context,
   4319                                                                   gl::TextureType type,
   4320                                                                   GLsizei samples,
   4321                                                                   GLint internalformat,
   4322                                                                   const gl::Extents &size,
   4323                                                                   bool fixedSampleLocations)
   4324 {
   4325    ASSERT(type == gl::TextureType::_2DMultisampleArray);
   4326 
   4327    mLayerCount = size.depth;
   4328 
   4329    TexStoragePointer storage = {
   4330        mRenderer->createTextureStorage2DMultisampleArray(internalformat, size.width, size.height,
   4331                                                          size.depth, static_cast<int>(0), samples,
   4332                                                          fixedSampleLocations, mState.getLabel()),
   4333        context};
   4334 
   4335    ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
   4336    storage.release();
   4337 
   4338    mImmutable = true;
   4339 
   4340    return angle::Result::Continue;
   4341 }
   4342 
   4343 angle::Result TextureD3D_2DMultisampleArray::setEGLImageTarget(const gl::Context *context,
   4344                                                               gl::TextureType type,
   4345                                                               egl::Image *image)
   4346 {
   4347    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   4348    return angle::Result::Continue;
   4349 }
   4350 
   4351 angle::Result TextureD3D_2DMultisampleArray::getRenderTarget(const gl::Context *context,
   4352                                                             const gl::ImageIndex &index,
   4353                                                             GLsizei samples,
   4354                                                             RenderTargetD3D **outRT)
   4355 {
   4356    // ensure the underlying texture is created
   4357    ANGLE_TRY(ensureRenderTarget(context));
   4358 
   4359    return mTexStorage->getRenderTarget(context, index, samples, outRT);
   4360 }
   4361 
   4362 gl::ImageIndexIterator TextureD3D_2DMultisampleArray::imageIterator() const
   4363 {
   4364    return gl::ImageIndexIterator::Make2DMultisampleArray(&mLayerCount);
   4365 }
   4366 
   4367 gl::ImageIndex TextureD3D_2DMultisampleArray::getImageIndex(GLint mip, GLint layer) const
   4368 {
   4369    return gl::ImageIndex::Make2DMultisampleArray(layer);
   4370 }
   4371 
   4372 bool TextureD3D_2DMultisampleArray::isValidIndex(const gl::ImageIndex &index) const
   4373 {
   4374    return (mTexStorage && index.getType() == gl::TextureType::_2DMultisampleArray &&
   4375            index.getLevelIndex() == 0);
   4376 }
   4377 
   4378 GLsizei TextureD3D_2DMultisampleArray::getLayerCount(int level) const
   4379 {
   4380    return mLayerCount;
   4381 }
   4382 
   4383 void TextureD3D_2DMultisampleArray::markAllImagesDirty() {}
   4384 
   4385 angle::Result TextureD3D_2DMultisampleArray::initializeStorage(const gl::Context *context,
   4386                                                               BindFlags bindFlags)
   4387 {
   4388    // initializeStorage should only be called in a situation where the texture already has storage
   4389    // associated with it (storage is created in setStorageMultisample).
   4390    ASSERT(mTexStorage);
   4391    return angle::Result::Continue;
   4392 }
   4393 
   4394 angle::Result TextureD3D_2DMultisampleArray::createCompleteStorage(
   4395    const gl::Context *context,
   4396    BindFlags bindFlags,
   4397    TexStoragePointer *outStorage) const
   4398 {
   4399    UNREACHABLE();
   4400    *outStorage = {mTexStorage, context};
   4401    return angle::Result::Continue;
   4402 }
   4403 
   4404 angle::Result TextureD3D_2DMultisampleArray::setCompleteTexStorage(
   4405    const gl::Context *context,
   4406    TextureStorage *newCompleteTexStorage)
   4407 {
   4408    // These textures are immutable, so this should only be ever called once.
   4409    ASSERT(!mTexStorage);
   4410    mTexStorage = newCompleteTexStorage;
   4411    mTexStorageObserverBinding.bind(mTexStorage);
   4412    return angle::Result::Continue;
   4413 }
   4414 
   4415 angle::Result TextureD3D_2DMultisampleArray::updateStorage(const gl::Context *context)
   4416 {
   4417    return angle::Result::Continue;
   4418 }
   4419 
   4420 angle::Result TextureD3D_2DMultisampleArray::initMipmapImages(const gl::Context *context)
   4421 {
   4422    UNIMPLEMENTED();
   4423    return angle::Result::Continue;
   4424 }
   4425 
   4426 bool TextureD3D_2DMultisampleArray::isImageComplete(const gl::ImageIndex &index) const
   4427 {
   4428    return true;
   4429 }
   4430 
   4431 TextureD3D_Buffer::TextureD3D_Buffer(const gl::TextureState &state, RendererD3D *renderer)
   4432    : TextureD3D(state, renderer), mInternalFormat(GL_INVALID_ENUM)
   4433 {}
   4434 
   4435 TextureD3D_Buffer::~TextureD3D_Buffer() {}
   4436 
   4437 angle::Result TextureD3D_Buffer::setImage(const gl::Context *context,
   4438                                          const gl::ImageIndex &index,
   4439                                          GLenum internalFormat,
   4440                                          const gl::Extents &size,
   4441                                          GLenum format,
   4442                                          GLenum type,
   4443                                          const gl::PixelUnpackState &unpack,
   4444                                          gl::Buffer *unpackBuffer,
   4445                                          const uint8_t *pixels)
   4446 {
   4447    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   4448    return angle::Result::Continue;
   4449 }
   4450 
   4451 angle::Result TextureD3D_Buffer::setSubImage(const gl::Context *context,
   4452                                             const gl::ImageIndex &index,
   4453                                             const gl::Box &area,
   4454                                             GLenum format,
   4455                                             GLenum type,
   4456                                             const gl::PixelUnpackState &unpack,
   4457                                             gl::Buffer *unpackBuffer,
   4458                                             const uint8_t *pixels)
   4459 {
   4460    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   4461    return angle::Result::Continue;
   4462 }
   4463 
   4464 angle::Result TextureD3D_Buffer::setCompressedImage(const gl::Context *context,
   4465                                                    const gl::ImageIndex &index,
   4466                                                    GLenum internalFormat,
   4467                                                    const gl::Extents &size,
   4468                                                    const gl::PixelUnpackState &unpack,
   4469                                                    size_t imageSize,
   4470                                                    const uint8_t *pixels)
   4471 {
   4472    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   4473    return angle::Result::Continue;
   4474 }
   4475 
   4476 angle::Result TextureD3D_Buffer::setCompressedSubImage(const gl::Context *context,
   4477                                                       const gl::ImageIndex &index,
   4478                                                       const gl::Box &area,
   4479                                                       GLenum format,
   4480                                                       const gl::PixelUnpackState &unpack,
   4481                                                       size_t imageSize,
   4482                                                       const uint8_t *pixels)
   4483 {
   4484    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   4485    return angle::Result::Continue;
   4486 }
   4487 
   4488 angle::Result TextureD3D_Buffer::copyImage(const gl::Context *context,
   4489                                           const gl::ImageIndex &index,
   4490                                           const gl::Rectangle &sourceArea,
   4491                                           GLenum internalFormat,
   4492                                           gl::Framebuffer *source)
   4493 {
   4494    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   4495    return angle::Result::Continue;
   4496 }
   4497 
   4498 angle::Result TextureD3D_Buffer::copySubImage(const gl::Context *context,
   4499                                              const gl::ImageIndex &index,
   4500                                              const gl::Offset &destOffset,
   4501                                              const gl::Rectangle &sourceArea,
   4502                                              gl::Framebuffer *source)
   4503 {
   4504    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   4505    return angle::Result::Continue;
   4506 }
   4507 
   4508 angle::Result TextureD3D_Buffer::bindTexImage(const gl::Context *context, egl::Surface *surface)
   4509 {
   4510    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   4511    return angle::Result::Continue;
   4512 }
   4513 
   4514 angle::Result TextureD3D_Buffer::releaseTexImage(const gl::Context *context)
   4515 {
   4516    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   4517    return angle::Result::Continue;
   4518 }
   4519 
   4520 GLsizei TextureD3D_Buffer::getLayerCount(int level) const
   4521 {
   4522    return 1;
   4523 }
   4524 
   4525 angle::Result TextureD3D_Buffer::initMipmapImages(const gl::Context *context)
   4526 {
   4527    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   4528    return angle::Result::Stop;
   4529 }
   4530 
   4531 bool TextureD3D_Buffer::isImageComplete(const gl::ImageIndex &index) const
   4532 {
   4533    return (index.getLevelIndex() == 0) ? (mTexStorage != nullptr) : false;
   4534 }
   4535 
   4536 angle::Result TextureD3D_Buffer::initializeStorage(const gl::Context *context, BindFlags bindFlags)
   4537 {
   4538    ASSERT(mTexStorage);
   4539    return angle::Result::Continue;
   4540 }
   4541 
   4542 angle::Result TextureD3D_Buffer::createCompleteStorage(const gl::Context *context,
   4543                                                       BindFlags bindFlags,
   4544                                                       TexStoragePointer *outStorage) const
   4545 {
   4546    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   4547    return angle::Result::Continue;
   4548 }
   4549 
   4550 angle::Result TextureD3D_Buffer::setCompleteTexStorage(const gl::Context *context,
   4551                                                       TextureStorage *newCompleteTexStorage)
   4552 {
   4553    ANGLE_TRY(releaseTexStorage(context, gl::TexLevelMask()));
   4554    mTexStorage = newCompleteTexStorage;
   4555    mTexStorageObserverBinding.bind(mTexStorage);
   4556 
   4557    mDirtyImages = true;
   4558 
   4559    return angle::Result::Continue;
   4560 }
   4561 
   4562 angle::Result TextureD3D_Buffer::updateStorage(const gl::Context *context)
   4563 {
   4564    ASSERT(mTexStorage);
   4565    return angle::Result::Continue;
   4566 }
   4567 
   4568 gl::ImageIndexIterator TextureD3D_Buffer::imageIterator() const
   4569 {
   4570    return gl::ImageIndexIterator::MakeBuffer();
   4571 }
   4572 
   4573 gl::ImageIndex TextureD3D_Buffer::getImageIndex(GLint mip, GLint layer) const
   4574 {
   4575    return gl::ImageIndex::MakeBuffer();
   4576 }
   4577 
   4578 bool TextureD3D_Buffer::isValidIndex(const gl::ImageIndex &index) const
   4579 {
   4580    return (mTexStorage && index.getType() == gl::TextureType::Buffer &&
   4581            index.getLevelIndex() == 0);
   4582 }
   4583 
   4584 void TextureD3D_Buffer::markAllImagesDirty()
   4585 {
   4586    UNREACHABLE();
   4587 }
   4588 
   4589 angle::Result TextureD3D_Buffer::setEGLImageTarget(const gl::Context *context,
   4590                                                   gl::TextureType type,
   4591                                                   egl::Image *image)
   4592 {
   4593    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   4594    return angle::Result::Continue;
   4595 }
   4596 
   4597 angle::Result TextureD3D_Buffer::getRenderTarget(const gl::Context *context,
   4598                                                 const gl::ImageIndex &index,
   4599                                                 GLsizei samples,
   4600                                                 RenderTargetD3D **outRT)
   4601 {
   4602    ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
   4603    return angle::Result::Continue;
   4604 }
   4605 
   4606 ImageD3D *TextureD3D_Buffer::getImage(const gl::ImageIndex &index) const
   4607 {
   4608    return nullptr;
   4609 }
   4610 
   4611 angle::Result TextureD3D_Buffer::setBuffer(const gl::Context *context, GLenum internalFormat)
   4612 {
   4613    ASSERT(mState.getType() == gl::TextureType::Buffer);
   4614    TexStoragePointer storage;
   4615    storage.reset(mRenderer->createTextureStorageBuffer(mState.getBuffer(), internalFormat,
   4616                                                        mState.getLabel()));
   4617    ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
   4618    storage.release();
   4619    mInternalFormat = internalFormat;
   4620    mImmutable      = false;
   4621    return angle::Result::Continue;
   4622 }
   4623 
   4624 angle::Result TextureD3D_Buffer::syncState(const gl::Context *context,
   4625                                           const gl::Texture::DirtyBits &dirtyBits,
   4626                                           gl::Command source)
   4627 {
   4628    ASSERT(mState.getType() == gl::TextureType::Buffer);
   4629    if (dirtyBits.test(gl::Texture::DirtyBitType::DIRTY_BIT_IMPLEMENTATION) &&
   4630        mState.getBuffer().get() != nullptr)
   4631    {
   4632        // buffer data have been changed. Buffer data may out of sync
   4633        // give up the old TexStorage, create a new one.
   4634        // this may not efficient, since staging buffer may be patially updated.
   4635        ANGLE_TRY(setBuffer(context, mInternalFormat));
   4636    }
   4637    return angle::Result::Continue;
   4638 }
   4639 
   4640 }  // namespace rx