tor-browser

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

Image11.cpp (27636B)


      1 //
      2 // Copyright 2012 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 // Image11.h: Implements the rx::Image11 class, which acts as the interface to
      8 // the actual underlying resources of a Texture
      9 
     10 #include "libANGLE/renderer/d3d/d3d11/Image11.h"
     11 
     12 #include "common/utilities.h"
     13 #include "libANGLE/Context.h"
     14 #include "libANGLE/Framebuffer.h"
     15 #include "libANGLE/FramebufferAttachment.h"
     16 #include "libANGLE/formatutils.h"
     17 #include "libANGLE/renderer/d3d/d3d11/Context11.h"
     18 #include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
     19 #include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
     20 #include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h"
     21 #include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
     22 #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
     23 #include "libANGLE/renderer/d3d/d3d11/texture_format_table.h"
     24 
     25 namespace rx
     26 {
     27 
     28 Image11::Image11(Renderer11 *renderer)
     29    : mRenderer(renderer),
     30      mDXGIFormat(DXGI_FORMAT_UNKNOWN),
     31      mStagingTexture(),
     32      mStagingSubresource(0),
     33      mRecoverFromStorage(false),
     34      mAssociatedStorage(nullptr),
     35      mAssociatedImageIndex(),
     36      mRecoveredFromStorageCount(0)
     37 {}
     38 
     39 Image11::~Image11()
     40 {
     41    disassociateStorage();
     42    releaseStagingTexture();
     43 }
     44 
     45 // static
     46 angle::Result Image11::GenerateMipmap(const gl::Context *context,
     47                                      Image11 *dest,
     48                                      Image11 *src,
     49                                      const Renderer11DeviceCaps &rendererCaps)
     50 {
     51    ASSERT(src->getDXGIFormat() == dest->getDXGIFormat());
     52    ASSERT(src->getWidth() == 1 || src->getWidth() / 2 == dest->getWidth());
     53    ASSERT(src->getHeight() == 1 || src->getHeight() / 2 == dest->getHeight());
     54 
     55    D3D11_MAPPED_SUBRESOURCE destMapped;
     56    ANGLE_TRY(dest->map(context, D3D11_MAP_WRITE, &destMapped));
     57    d3d11::ScopedUnmapper<Image11> destRAII(dest);
     58 
     59    D3D11_MAPPED_SUBRESOURCE srcMapped;
     60    ANGLE_TRY(src->map(context, D3D11_MAP_READ, &srcMapped));
     61    d3d11::ScopedUnmapper<Image11> srcRAII(src);
     62 
     63    const uint8_t *sourceData = static_cast<const uint8_t *>(srcMapped.pData);
     64    uint8_t *destData         = static_cast<uint8_t *>(destMapped.pData);
     65 
     66    auto mipGenerationFunction =
     67        d3d11::Format::Get(src->getInternalFormat(), rendererCaps).format().mipGenerationFunction;
     68    mipGenerationFunction(src->getWidth(), src->getHeight(), src->getDepth(), sourceData,
     69                          srcMapped.RowPitch, srcMapped.DepthPitch, destData, destMapped.RowPitch,
     70                          destMapped.DepthPitch);
     71 
     72    dest->markDirty();
     73 
     74    return angle::Result::Continue;
     75 }
     76 
     77 // static
     78 angle::Result Image11::CopyImage(const gl::Context *context,
     79                                 Image11 *dest,
     80                                 Image11 *source,
     81                                 const gl::Box &sourceBox,
     82                                 const gl::Offset &destOffset,
     83                                 bool unpackFlipY,
     84                                 bool unpackPremultiplyAlpha,
     85                                 bool unpackUnmultiplyAlpha,
     86                                 const Renderer11DeviceCaps &rendererCaps)
     87 {
     88    D3D11_MAPPED_SUBRESOURCE destMapped;
     89    ANGLE_TRY(dest->map(context, D3D11_MAP_WRITE, &destMapped));
     90    d3d11::ScopedUnmapper<Image11> destRAII(dest);
     91 
     92    D3D11_MAPPED_SUBRESOURCE srcMapped;
     93    ANGLE_TRY(source->map(context, D3D11_MAP_READ, &srcMapped));
     94    d3d11::ScopedUnmapper<Image11> sourceRAII(source);
     95 
     96    const auto &sourceFormat =
     97        d3d11::Format::Get(source->getInternalFormat(), rendererCaps).format();
     98    GLuint sourcePixelBytes =
     99        gl::GetSizedInternalFormatInfo(sourceFormat.fboImplementationInternalFormat).pixelBytes;
    100 
    101    GLenum destUnsizedFormat = gl::GetUnsizedFormat(dest->getInternalFormat());
    102    const auto &destFormat   = d3d11::Format::Get(dest->getInternalFormat(), rendererCaps).format();
    103    const auto &destFormatInfo =
    104        gl::GetSizedInternalFormatInfo(destFormat.fboImplementationInternalFormat);
    105    GLuint destPixelBytes = destFormatInfo.pixelBytes;
    106 
    107    const uint8_t *sourceData = static_cast<const uint8_t *>(srcMapped.pData) +
    108                                sourceBox.x * sourcePixelBytes + sourceBox.y * srcMapped.RowPitch +
    109                                sourceBox.z * srcMapped.DepthPitch;
    110    uint8_t *destData = static_cast<uint8_t *>(destMapped.pData) + destOffset.x * destPixelBytes +
    111                        destOffset.y * destMapped.RowPitch + destOffset.z * destMapped.DepthPitch;
    112 
    113    CopyImageCHROMIUM(sourceData, srcMapped.RowPitch, sourcePixelBytes, srcMapped.DepthPitch,
    114                      sourceFormat.pixelReadFunction, destData, destMapped.RowPitch, destPixelBytes,
    115                      destMapped.DepthPitch, destFormat.pixelWriteFunction, destUnsizedFormat,
    116                      destFormatInfo.componentType, sourceBox.width, sourceBox.height,
    117                      sourceBox.depth, unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha);
    118 
    119    dest->markDirty();
    120 
    121    return angle::Result::Continue;
    122 }
    123 
    124 bool Image11::isDirty() const
    125 {
    126    // If mDirty is true AND mStagingTexture doesn't exist AND mStagingTexture doesn't need to be
    127    // recovered from TextureStorage AND the texture doesn't require init data (i.e. a blank new
    128    // texture will suffice) AND robust resource initialization is not enabled then isDirty should
    129    // still return false.
    130    if (mDirty && !mStagingTexture.valid() && !mRecoverFromStorage)
    131    {
    132        const Renderer11DeviceCaps &deviceCaps = mRenderer->getRenderer11DeviceCaps();
    133        const auto &formatInfo                 = d3d11::Format::Get(mInternalFormat, deviceCaps);
    134        if (formatInfo.dataInitializerFunction == nullptr)
    135        {
    136            return false;
    137        }
    138    }
    139 
    140    return mDirty;
    141 }
    142 
    143 angle::Result Image11::copyToStorage(const gl::Context *context,
    144                                     TextureStorage *storage,
    145                                     const gl::ImageIndex &index,
    146                                     const gl::Box &region)
    147 {
    148    TextureStorage11 *storage11 = GetAs<TextureStorage11>(storage);
    149 
    150    // If an app's behavior results in an Image11 copying its data to/from to a TextureStorage
    151    // multiple times, then we should just keep the staging texture around to prevent the copying
    152    // from impacting perf. We allow the Image11 to copy its data to/from TextureStorage once. This
    153    // accounts for an app making a late call to glGenerateMipmap.
    154    bool attemptToReleaseStagingTexture = (mRecoveredFromStorageCount < 2);
    155 
    156    if (attemptToReleaseStagingTexture)
    157    {
    158        // If another image is relying on this Storage for its data, then we must let it recover its
    159        // data before we overwrite it.
    160        ANGLE_TRY(storage11->releaseAssociatedImage(context, index, this));
    161    }
    162 
    163    const TextureHelper11 *stagingTexture = nullptr;
    164    unsigned int stagingSubresourceIndex  = 0;
    165    ANGLE_TRY(getStagingTexture(context, &stagingTexture, &stagingSubresourceIndex));
    166    ANGLE_TRY(storage11->updateSubresourceLevel(context, *stagingTexture, stagingSubresourceIndex,
    167                                                index, region));
    168 
    169    // Once the image data has been copied into the Storage, we can release it locally.
    170    if (attemptToReleaseStagingTexture)
    171    {
    172        storage11->associateImage(this, index);
    173        releaseStagingTexture();
    174        mRecoverFromStorage   = true;
    175        mAssociatedStorage    = storage11;
    176        mAssociatedImageIndex = index;
    177    }
    178 
    179    return angle::Result::Continue;
    180 }
    181 
    182 void Image11::verifyAssociatedStorageValid(TextureStorage11 *textureStorageEXT) const
    183 {
    184    ASSERT(mAssociatedStorage == textureStorageEXT);
    185 }
    186 
    187 angle::Result Image11::recoverFromAssociatedStorage(const gl::Context *context)
    188 {
    189    if (mRecoverFromStorage)
    190    {
    191        ANGLE_TRY(createStagingTexture(context));
    192 
    193        mAssociatedStorage->verifyAssociatedImageValid(mAssociatedImageIndex, this);
    194 
    195        // CopySubResource from the Storage to the Staging texture
    196        gl::Box region(0, 0, 0, mWidth, mHeight, mDepth);
    197        ANGLE_TRY(mAssociatedStorage->copySubresourceLevel(
    198            context, mStagingTexture, mStagingSubresource, mAssociatedImageIndex, region));
    199        mRecoveredFromStorageCount += 1;
    200 
    201        // Reset all the recovery parameters, even if the texture storage association is broken.
    202        disassociateStorage();
    203 
    204        markDirty();
    205    }
    206 
    207    return angle::Result::Continue;
    208 }
    209 
    210 void Image11::disassociateStorage()
    211 {
    212    if (mRecoverFromStorage)
    213    {
    214        // Make the texturestorage release the Image11 too
    215        mAssociatedStorage->disassociateImage(mAssociatedImageIndex, this);
    216 
    217        mRecoverFromStorage   = false;
    218        mAssociatedStorage    = nullptr;
    219        mAssociatedImageIndex = gl::ImageIndex();
    220    }
    221 }
    222 
    223 bool Image11::redefine(gl::TextureType type,
    224                       GLenum internalformat,
    225                       const gl::Extents &size,
    226                       bool forceRelease)
    227 {
    228    if (mWidth != size.width || mHeight != size.height || mDepth != size.depth ||
    229        mInternalFormat != internalformat || forceRelease)
    230    {
    231        // End the association with the TextureStorage, since that data will be out of date.
    232        // Also reset mRecoveredFromStorageCount since this Image is getting completely redefined.
    233        disassociateStorage();
    234        mRecoveredFromStorageCount = 0;
    235 
    236        mWidth          = size.width;
    237        mHeight         = size.height;
    238        mDepth          = size.depth;
    239        mInternalFormat = internalformat;
    240        mType           = type;
    241 
    242        // compute the d3d format that will be used
    243        const d3d11::Format &formatInfo =
    244            d3d11::Format::Get(internalformat, mRenderer->getRenderer11DeviceCaps());
    245        mDXGIFormat = formatInfo.texFormat;
    246        mRenderable = (formatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN);
    247 
    248        releaseStagingTexture();
    249        mDirty = (formatInfo.dataInitializerFunction != nullptr);
    250 
    251        return true;
    252    }
    253 
    254    return false;
    255 }
    256 
    257 DXGI_FORMAT Image11::getDXGIFormat() const
    258 {
    259    // this should only happen if the image hasn't been redefined first
    260    // which would be a bug by the caller
    261    ASSERT(mDXGIFormat != DXGI_FORMAT_UNKNOWN);
    262 
    263    return mDXGIFormat;
    264 }
    265 
    266 // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as
    267 // format/type at input
    268 // into the target pixel rectangle.
    269 angle::Result Image11::loadData(const gl::Context *context,
    270                                const gl::Box &area,
    271                                const gl::PixelUnpackState &unpack,
    272                                GLenum type,
    273                                const void *input,
    274                                bool applySkipImages)
    275 {
    276    Context11 *context11 = GetImplAs<Context11>(context);
    277 
    278    const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat);
    279    GLuint inputRowPitch                 = 0;
    280    ANGLE_CHECK_GL_MATH(context11, formatInfo.computeRowPitch(type, area.width, unpack.alignment,
    281                                                              unpack.rowLength, &inputRowPitch));
    282    GLuint inputDepthPitch = 0;
    283    ANGLE_CHECK_GL_MATH(context11, formatInfo.computeDepthPitch(area.height, unpack.imageHeight,
    284                                                                inputRowPitch, &inputDepthPitch));
    285    GLuint inputSkipBytes = 0;
    286    ANGLE_CHECK_GL_MATH(context11,
    287                        formatInfo.computeSkipBytes(type, inputRowPitch, inputDepthPitch, unpack,
    288                                                    applySkipImages, &inputSkipBytes));
    289 
    290    const d3d11::DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(mDXGIFormat);
    291    GLuint outputPixelSize                      = dxgiFormatInfo.pixelBytes;
    292 
    293    const d3d11::Format &d3dFormatInfo =
    294        d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps());
    295    LoadImageFunction loadFunction = d3dFormatInfo.getLoadFunctions()(type).loadFunction;
    296 
    297    D3D11_MAPPED_SUBRESOURCE mappedImage;
    298    ANGLE_TRY(map(context, D3D11_MAP_WRITE, &mappedImage));
    299 
    300    uint8_t *offsetMappedData = (static_cast<uint8_t *>(mappedImage.pData) +
    301                                 (area.y * mappedImage.RowPitch + area.x * outputPixelSize +
    302                                  area.z * mappedImage.DepthPitch));
    303    loadFunction(area.width, area.height, area.depth,
    304                 static_cast<const uint8_t *>(input) + inputSkipBytes, inputRowPitch,
    305                 inputDepthPitch, offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch);
    306 
    307    unmap();
    308 
    309    return angle::Result::Continue;
    310 }
    311 
    312 angle::Result Image11::loadCompressedData(const gl::Context *context,
    313                                          const gl::Box &area,
    314                                          const void *input)
    315 {
    316    Context11 *context11 = GetImplAs<Context11>(context);
    317 
    318    const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat);
    319    GLuint inputRowPitch                 = 0;
    320    ANGLE_CHECK_GL_MATH(
    321        context11, formatInfo.computeRowPitch(GL_UNSIGNED_BYTE, area.width, 1, 0, &inputRowPitch));
    322    GLuint inputDepthPitch = 0;
    323    ANGLE_CHECK_GL_MATH(
    324        context11, formatInfo.computeDepthPitch(area.height, 0, inputRowPitch, &inputDepthPitch));
    325 
    326    const d3d11::DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(mDXGIFormat);
    327    GLuint outputPixelSize                      = dxgiFormatInfo.pixelBytes;
    328    GLuint outputBlockWidth                     = dxgiFormatInfo.blockWidth;
    329    GLuint outputBlockHeight                    = dxgiFormatInfo.blockHeight;
    330 
    331    ASSERT(area.x % outputBlockWidth == 0);
    332    ASSERT(area.y % outputBlockHeight == 0);
    333 
    334    const d3d11::Format &d3dFormatInfo =
    335        d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps());
    336    LoadImageFunction loadFunction =
    337        d3dFormatInfo.getLoadFunctions()(GL_UNSIGNED_BYTE).loadFunction;
    338 
    339    D3D11_MAPPED_SUBRESOURCE mappedImage;
    340    ANGLE_TRY(map(context, D3D11_MAP_WRITE, &mappedImage));
    341 
    342    uint8_t *offsetMappedData =
    343        static_cast<uint8_t *>(mappedImage.pData) +
    344        ((area.y / outputBlockHeight) * mappedImage.RowPitch +
    345         (area.x / outputBlockWidth) * outputPixelSize + area.z * mappedImage.DepthPitch);
    346 
    347    loadFunction(area.width, area.height, area.depth, static_cast<const uint8_t *>(input),
    348                 inputRowPitch, inputDepthPitch, offsetMappedData, mappedImage.RowPitch,
    349                 mappedImage.DepthPitch);
    350 
    351    unmap();
    352 
    353    return angle::Result::Continue;
    354 }
    355 
    356 angle::Result Image11::copyFromTexStorage(const gl::Context *context,
    357                                          const gl::ImageIndex &imageIndex,
    358                                          TextureStorage *source)
    359 {
    360    TextureStorage11 *storage11 = GetAs<TextureStorage11>(source);
    361 
    362    const TextureHelper11 *textureHelper = nullptr;
    363    ANGLE_TRY(storage11->getResource(context, &textureHelper));
    364 
    365    UINT subresourceIndex = 0;
    366    ANGLE_TRY(storage11->getSubresourceIndex(context, imageIndex, &subresourceIndex));
    367 
    368    gl::Box sourceBox(0, 0, 0, mWidth, mHeight, mDepth);
    369    return copyWithoutConversion(context, gl::Offset(), sourceBox, *textureHelper,
    370                                 subresourceIndex);
    371 }
    372 
    373 angle::Result Image11::copyFromFramebuffer(const gl::Context *context,
    374                                           const gl::Offset &destOffset,
    375                                           const gl::Rectangle &sourceArea,
    376                                           const gl::Framebuffer *sourceFBO)
    377 {
    378    const gl::FramebufferAttachment *srcAttachment = sourceFBO->getReadColorAttachment();
    379    ASSERT(srcAttachment);
    380 
    381    GLenum sourceInternalFormat = srcAttachment->getFormat().info->sizedInternalFormat;
    382    const auto &d3d11Format =
    383        d3d11::Format::Get(sourceInternalFormat, mRenderer->getRenderer11DeviceCaps());
    384 
    385    if (d3d11Format.texFormat == mDXGIFormat && sourceInternalFormat == mInternalFormat)
    386    {
    387        RenderTarget11 *rt11 = nullptr;
    388        ANGLE_TRY(srcAttachment->getRenderTarget(context, 0, &rt11));
    389        ASSERT(rt11->getTexture().get());
    390 
    391        TextureHelper11 textureHelper  = rt11->getTexture();
    392        unsigned int sourceSubResource = rt11->getSubresourceIndex();
    393 
    394        gl::Box sourceBox(sourceArea.x, sourceArea.y, 0, sourceArea.width, sourceArea.height, 1);
    395        return copyWithoutConversion(context, destOffset, sourceBox, textureHelper,
    396                                     sourceSubResource);
    397    }
    398 
    399    // This format requires conversion, so we must copy the texture to staging and manually convert
    400    // via readPixels
    401    D3D11_MAPPED_SUBRESOURCE mappedImage;
    402    ANGLE_TRY(map(context, D3D11_MAP_WRITE, &mappedImage));
    403 
    404    // determine the offset coordinate into the destination buffer
    405    const auto &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(mDXGIFormat);
    406    GLsizei rowOffset          = dxgiFormatInfo.pixelBytes * destOffset.x;
    407 
    408    uint8_t *dataOffset = static_cast<uint8_t *>(mappedImage.pData) +
    409                          mappedImage.RowPitch * destOffset.y + rowOffset +
    410                          destOffset.z * mappedImage.DepthPitch;
    411 
    412    const gl::InternalFormat &destFormatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat);
    413    const auto &destD3D11Format =
    414        d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps());
    415 
    416    auto loadFunction    = destD3D11Format.getLoadFunctions()(destFormatInfo.type);
    417    angle::Result result = angle::Result::Continue;
    418    if (loadFunction.requiresConversion)
    419    {
    420        size_t bufferSize = destFormatInfo.pixelBytes * sourceArea.width * sourceArea.height;
    421        angle::MemoryBuffer *memoryBuffer = nullptr;
    422        result = mRenderer->getScratchMemoryBuffer(GetImplAs<Context11>(context), bufferSize,
    423                                                   &memoryBuffer);
    424 
    425        if (result == angle::Result::Continue)
    426        {
    427            GLuint memoryBufferRowPitch = destFormatInfo.pixelBytes * sourceArea.width;
    428 
    429            result = mRenderer->readFromAttachment(
    430                context, *srcAttachment, sourceArea, destFormatInfo.format, destFormatInfo.type,
    431                memoryBufferRowPitch, gl::PixelPackState(), memoryBuffer->data());
    432 
    433            loadFunction.loadFunction(sourceArea.width, sourceArea.height, 1, memoryBuffer->data(),
    434                                      memoryBufferRowPitch, 0, dataOffset, mappedImage.RowPitch,
    435                                      mappedImage.DepthPitch);
    436        }
    437    }
    438    else
    439    {
    440        result = mRenderer->readFromAttachment(
    441            context, *srcAttachment, sourceArea, destFormatInfo.format, destFormatInfo.type,
    442            mappedImage.RowPitch, gl::PixelPackState(), dataOffset);
    443    }
    444 
    445    unmap();
    446    mDirty = true;
    447 
    448    return result;
    449 }
    450 
    451 angle::Result Image11::copyWithoutConversion(const gl::Context *context,
    452                                             const gl::Offset &destOffset,
    453                                             const gl::Box &sourceArea,
    454                                             const TextureHelper11 &textureHelper,
    455                                             UINT sourceSubResource)
    456 {
    457    // No conversion needed-- use copyback fastpath
    458    const TextureHelper11 *stagingTexture = nullptr;
    459    unsigned int stagingSubresourceIndex  = 0;
    460    ANGLE_TRY(getStagingTexture(context, &stagingTexture, &stagingSubresourceIndex));
    461 
    462    ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
    463 
    464    const gl::Extents &extents = textureHelper.getExtents();
    465 
    466    D3D11_BOX srcBox;
    467    srcBox.left   = sourceArea.x;
    468    srcBox.right  = sourceArea.x + sourceArea.width;
    469    srcBox.top    = sourceArea.y;
    470    srcBox.bottom = sourceArea.y + sourceArea.height;
    471    srcBox.front  = sourceArea.z;
    472    srcBox.back   = sourceArea.z + sourceArea.depth;
    473 
    474    if (textureHelper.is2D() && textureHelper.getSampleCount() > 1)
    475    {
    476        D3D11_TEXTURE2D_DESC resolveDesc;
    477        resolveDesc.Width              = extents.width;
    478        resolveDesc.Height             = extents.height;
    479        resolveDesc.MipLevels          = 1;
    480        resolveDesc.ArraySize          = 1;
    481        resolveDesc.Format             = textureHelper.getFormat();
    482        resolveDesc.SampleDesc.Count   = 1;
    483        resolveDesc.SampleDesc.Quality = 0;
    484        resolveDesc.Usage              = D3D11_USAGE_DEFAULT;
    485        resolveDesc.BindFlags          = 0;
    486        resolveDesc.CPUAccessFlags     = 0;
    487        resolveDesc.MiscFlags          = 0;
    488 
    489        d3d11::Texture2D resolveTex;
    490        ANGLE_TRY(
    491            mRenderer->allocateResource(GetImplAs<Context11>(context), resolveDesc, &resolveTex));
    492 
    493        deviceContext->ResolveSubresource(resolveTex.get(), 0, textureHelper.get(),
    494                                          sourceSubResource, textureHelper.getFormat());
    495 
    496        deviceContext->CopySubresourceRegion(stagingTexture->get(), stagingSubresourceIndex,
    497                                             destOffset.x, destOffset.y, destOffset.z,
    498                                             resolveTex.get(), 0, &srcBox);
    499    }
    500    else
    501    {
    502        deviceContext->CopySubresourceRegion(stagingTexture->get(), stagingSubresourceIndex,
    503                                             destOffset.x, destOffset.y, destOffset.z,
    504                                             textureHelper.get(), sourceSubResource, &srcBox);
    505    }
    506 
    507    mDirty = true;
    508    return angle::Result::Continue;
    509 }
    510 
    511 angle::Result Image11::getStagingTexture(const gl::Context *context,
    512                                         const TextureHelper11 **outStagingTexture,
    513                                         unsigned int *outSubresourceIndex)
    514 {
    515    ANGLE_TRY(createStagingTexture(context));
    516 
    517    *outStagingTexture   = &mStagingTexture;
    518    *outSubresourceIndex = mStagingSubresource;
    519    return angle::Result::Continue;
    520 }
    521 
    522 void Image11::releaseStagingTexture()
    523 {
    524    mStagingTexture.reset();
    525    mStagingTextureSubresourceVerifier.reset();
    526 }
    527 
    528 angle::Result Image11::createStagingTexture(const gl::Context *context)
    529 {
    530    if (mStagingTexture.valid())
    531    {
    532        return angle::Result::Continue;
    533    }
    534 
    535    ASSERT(mWidth > 0 && mHeight > 0 && mDepth > 0);
    536 
    537    const DXGI_FORMAT dxgiFormat = getDXGIFormat();
    538    const auto &formatInfo =
    539        d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps());
    540 
    541    int lodOffset  = 1;
    542    GLsizei width  = mWidth;
    543    GLsizei height = mHeight;
    544 
    545    // adjust size if needed for compressed textures
    546    d3d11::MakeValidSize(false, dxgiFormat, &width, &height, &lodOffset);
    547 
    548    Context11 *context11 = GetImplAs<Context11>(context);
    549 
    550    switch (mType)
    551    {
    552        case gl::TextureType::_3D:
    553        {
    554            D3D11_TEXTURE3D_DESC desc;
    555            desc.Width          = width;
    556            desc.Height         = height;
    557            desc.Depth          = mDepth;
    558            desc.MipLevels      = lodOffset + 1;
    559            desc.Format         = dxgiFormat;
    560            desc.Usage          = D3D11_USAGE_STAGING;
    561            desc.BindFlags      = 0;
    562            desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
    563            desc.MiscFlags      = 0;
    564 
    565            if (formatInfo.dataInitializerFunction != nullptr)
    566            {
    567                gl::TexLevelArray<D3D11_SUBRESOURCE_DATA> initialData;
    568                ANGLE_TRY(d3d11::GenerateInitialTextureData(
    569                    context, mInternalFormat, mRenderer->getRenderer11DeviceCaps(), width, height,
    570                    mDepth, lodOffset + 1, &initialData));
    571 
    572                ANGLE_TRY(mRenderer->allocateTexture(context11, desc, formatInfo,
    573                                                     initialData.data(), &mStagingTexture));
    574            }
    575            else
    576            {
    577                ANGLE_TRY(
    578                    mRenderer->allocateTexture(context11, desc, formatInfo, &mStagingTexture));
    579            }
    580 
    581            mStagingTexture.setInternalName("Image11::StagingTexture3D");
    582            mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1);
    583            mStagingTextureSubresourceVerifier.setDesc(desc);
    584        }
    585        break;
    586 
    587        case gl::TextureType::_2D:
    588        case gl::TextureType::_2DArray:
    589        case gl::TextureType::CubeMap:
    590        {
    591            D3D11_TEXTURE2D_DESC desc;
    592            desc.Width              = width;
    593            desc.Height             = height;
    594            desc.MipLevels          = lodOffset + 1;
    595            desc.ArraySize          = 1;
    596            desc.Format             = dxgiFormat;
    597            desc.SampleDesc.Count   = 1;
    598            desc.SampleDesc.Quality = 0;
    599            desc.Usage              = D3D11_USAGE_STAGING;
    600            desc.BindFlags          = 0;
    601            desc.CPUAccessFlags     = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
    602            desc.MiscFlags          = 0;
    603 
    604            if (formatInfo.dataInitializerFunction != nullptr)
    605            {
    606                gl::TexLevelArray<D3D11_SUBRESOURCE_DATA> initialData;
    607                ANGLE_TRY(d3d11::GenerateInitialTextureData(
    608                    context, mInternalFormat, mRenderer->getRenderer11DeviceCaps(), width, height,
    609                    1, lodOffset + 1, &initialData));
    610 
    611                ANGLE_TRY(mRenderer->allocateTexture(context11, desc, formatInfo,
    612                                                     initialData.data(), &mStagingTexture));
    613            }
    614            else
    615            {
    616                ANGLE_TRY(
    617                    mRenderer->allocateTexture(context11, desc, formatInfo, &mStagingTexture));
    618            }
    619 
    620            mStagingTexture.setInternalName("Image11::StagingTexture2D");
    621            mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1);
    622            mStagingTextureSubresourceVerifier.setDesc(desc);
    623        }
    624        break;
    625 
    626        default:
    627            UNREACHABLE();
    628    }
    629 
    630    mDirty = false;
    631    return angle::Result::Continue;
    632 }
    633 
    634 angle::Result Image11::map(const gl::Context *context,
    635                           D3D11_MAP mapType,
    636                           D3D11_MAPPED_SUBRESOURCE *map)
    637 {
    638    // We must recover from the TextureStorage if necessary, even for D3D11_MAP_WRITE.
    639    ANGLE_TRY(recoverFromAssociatedStorage(context));
    640 
    641    const TextureHelper11 *stagingTexture = nullptr;
    642    unsigned int subresourceIndex         = 0;
    643    ANGLE_TRY(getStagingTexture(context, &stagingTexture, &subresourceIndex));
    644 
    645    ASSERT(stagingTexture && stagingTexture->valid());
    646 
    647    ANGLE_TRY(
    648        mRenderer->mapResource(context, stagingTexture->get(), subresourceIndex, mapType, 0, map));
    649 
    650    if (!mStagingTextureSubresourceVerifier.wrap(mapType, map))
    651    {
    652        ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
    653        deviceContext->Unmap(mStagingTexture.get(), mStagingSubresource);
    654        Context11 *context11 = GetImplAs<Context11>(context);
    655        context11->handleError(GL_OUT_OF_MEMORY,
    656                               "Failed to allocate staging texture mapping verifier buffer.",
    657                               __FILE__, ANGLE_FUNCTION, __LINE__);
    658        return angle::Result::Stop;
    659    }
    660 
    661    mDirty = true;
    662 
    663    return angle::Result::Continue;
    664 }
    665 
    666 void Image11::unmap()
    667 {
    668    if (mStagingTexture.valid())
    669    {
    670        mStagingTextureSubresourceVerifier.unwrap();
    671        ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
    672        deviceContext->Unmap(mStagingTexture.get(), mStagingSubresource);
    673    }
    674 }
    675 
    676 }  // namespace rx