tor-browser

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

Image9.cpp (36302B)


      1 //
      2 // Copyright 2002 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 // Image9.cpp: Implements the rx::Image9 class, which acts as the interface to
      8 // the actual underlying surfaces of a Texture.
      9 
     10 #include "libANGLE/renderer/d3d/d3d9/Image9.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/Renderbuffer.h"
     17 #include "libANGLE/formatutils.h"
     18 #include "libANGLE/renderer/copyvertex.h"
     19 #include "libANGLE/renderer/d3d/d3d9/Context9.h"
     20 #include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h"
     21 #include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
     22 #include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h"
     23 #include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
     24 #include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
     25 
     26 namespace rx
     27 {
     28 
     29 Image9::Image9(Renderer9 *renderer)
     30 {
     31    mSurface  = nullptr;
     32    mRenderer = nullptr;
     33 
     34    mD3DPool   = D3DPOOL_SYSTEMMEM;
     35    mD3DFormat = D3DFMT_UNKNOWN;
     36 
     37    mRenderer = renderer;
     38 }
     39 
     40 Image9::~Image9()
     41 {
     42    SafeRelease(mSurface);
     43 }
     44 
     45 // static
     46 angle::Result Image9::GenerateMip(Context9 *context9,
     47                                  IDirect3DSurface9 *destSurface,
     48                                  IDirect3DSurface9 *sourceSurface)
     49 {
     50    D3DSURFACE_DESC destDesc;
     51    HRESULT result = destSurface->GetDesc(&destDesc);
     52    ASSERT(SUCCEEDED(result));
     53    ANGLE_TRY_HR(context9, result,
     54                 "Failed to query the source surface description for mipmap generation");
     55 
     56    D3DSURFACE_DESC sourceDesc;
     57    result = sourceSurface->GetDesc(&sourceDesc);
     58    ASSERT(SUCCEEDED(result));
     59    ANGLE_TRY_HR(context9, result,
     60                 "Failed to query the destination surface description for mipmap generation");
     61 
     62    ASSERT(sourceDesc.Format == destDesc.Format);
     63    ASSERT(sourceDesc.Width == 1 || sourceDesc.Width / 2 == destDesc.Width);
     64    ASSERT(sourceDesc.Height == 1 || sourceDesc.Height / 2 == destDesc.Height);
     65 
     66    const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(sourceDesc.Format);
     67    ASSERT(d3dFormatInfo.info().mipGenerationFunction != nullptr);
     68 
     69    D3DLOCKED_RECT sourceLocked = {};
     70    result                      = sourceSurface->LockRect(&sourceLocked, nullptr, D3DLOCK_READONLY);
     71    ASSERT(SUCCEEDED(result));
     72    ANGLE_TRY_HR(context9, result, "Failed to lock the source surface for mipmap generation");
     73 
     74    D3DLOCKED_RECT destLocked = {};
     75    result                    = destSurface->LockRect(&destLocked, nullptr, 0);
     76    ASSERT(SUCCEEDED(result));
     77    ANGLE_TRY_HR(context9, result, "Failed to lock the destination surface for mipmap generation");
     78 
     79    const uint8_t *sourceData = static_cast<const uint8_t *>(sourceLocked.pBits);
     80    uint8_t *destData         = static_cast<uint8_t *>(destLocked.pBits);
     81 
     82    ASSERT(sourceData && destData);
     83 
     84    d3dFormatInfo.info().mipGenerationFunction(sourceDesc.Width, sourceDesc.Height, 1, sourceData,
     85                                               sourceLocked.Pitch, 0, destData, destLocked.Pitch,
     86                                               0);
     87 
     88    destSurface->UnlockRect();
     89    sourceSurface->UnlockRect();
     90 
     91    return angle::Result::Continue;
     92 }
     93 
     94 // static
     95 angle::Result Image9::GenerateMipmap(Context9 *context9, Image9 *dest, Image9 *source)
     96 {
     97    IDirect3DSurface9 *sourceSurface = nullptr;
     98    ANGLE_TRY(source->getSurface(context9, &sourceSurface));
     99 
    100    IDirect3DSurface9 *destSurface = nullptr;
    101    ANGLE_TRY(dest->getSurface(context9, &destSurface));
    102 
    103    ANGLE_TRY(GenerateMip(context9, destSurface, sourceSurface));
    104 
    105    dest->markDirty();
    106 
    107    return angle::Result::Continue;
    108 }
    109 
    110 // static
    111 angle::Result Image9::CopyLockableSurfaces(Context9 *context9,
    112                                           IDirect3DSurface9 *dest,
    113                                           IDirect3DSurface9 *source)
    114 {
    115    D3DLOCKED_RECT sourceLock = {};
    116    D3DLOCKED_RECT destLock   = {};
    117 
    118    HRESULT result;
    119 
    120    result = source->LockRect(&sourceLock, nullptr, 0);
    121    ANGLE_TRY_HR(context9, result, "Failed to lock source surface for copy");
    122 
    123    result = dest->LockRect(&destLock, nullptr, 0);
    124    if (FAILED(result))
    125    {
    126        source->UnlockRect();
    127    }
    128    ANGLE_TRY_HR(context9, result, "Failed to lock destination surface for copy");
    129 
    130    ASSERT(sourceLock.pBits && destLock.pBits);
    131 
    132    D3DSURFACE_DESC desc;
    133    source->GetDesc(&desc);
    134 
    135    const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format);
    136    unsigned int rows                    = desc.Height / d3dFormatInfo.blockHeight;
    137 
    138    unsigned int bytes = d3d9::ComputeBlockSize(desc.Format, desc.Width, d3dFormatInfo.blockHeight);
    139    ASSERT(bytes <= static_cast<unsigned int>(sourceLock.Pitch) &&
    140           bytes <= static_cast<unsigned int>(destLock.Pitch));
    141 
    142    for (unsigned int i = 0; i < rows; i++)
    143    {
    144        memcpy((char *)destLock.pBits + destLock.Pitch * i,
    145               (char *)sourceLock.pBits + sourceLock.Pitch * i, bytes);
    146    }
    147 
    148    source->UnlockRect();
    149    dest->UnlockRect();
    150 
    151    return angle::Result::Continue;
    152 }
    153 
    154 // static
    155 angle::Result Image9::CopyImage(const gl::Context *context,
    156                                Image9 *dest,
    157                                Image9 *source,
    158                                const gl::Rectangle &sourceRect,
    159                                const gl::Offset &destOffset,
    160                                bool unpackFlipY,
    161                                bool unpackPremultiplyAlpha,
    162                                bool unpackUnmultiplyAlpha)
    163 {
    164    Context9 *context9 = GetImplAs<Context9>(context);
    165 
    166    IDirect3DSurface9 *sourceSurface = nullptr;
    167    ANGLE_TRY(source->getSurface(context9, &sourceSurface));
    168 
    169    IDirect3DSurface9 *destSurface = nullptr;
    170    ANGLE_TRY(dest->getSurface(context9, &destSurface));
    171 
    172    D3DSURFACE_DESC destDesc;
    173    HRESULT result = destSurface->GetDesc(&destDesc);
    174    ASSERT(SUCCEEDED(result));
    175    ANGLE_TRY_HR(context9, result, "Failed to query the source surface description for CopyImage");
    176    const d3d9::D3DFormat &destD3DFormatInfo = d3d9::GetD3DFormatInfo(destDesc.Format);
    177 
    178    D3DSURFACE_DESC sourceDesc;
    179    result = sourceSurface->GetDesc(&sourceDesc);
    180    ASSERT(SUCCEEDED(result));
    181    ANGLE_TRY_HR(context9, result,
    182                 "Failed to query the destination surface description for CopyImage");
    183    const d3d9::D3DFormat &sourceD3DFormatInfo = d3d9::GetD3DFormatInfo(sourceDesc.Format);
    184 
    185    D3DLOCKED_RECT sourceLocked = {};
    186    result                      = sourceSurface->LockRect(&sourceLocked, nullptr, D3DLOCK_READONLY);
    187    ASSERT(SUCCEEDED(result));
    188    ANGLE_TRY_HR(context9, result, "Failed to lock the source surface for CopyImage");
    189 
    190    D3DLOCKED_RECT destLocked = {};
    191    result                    = destSurface->LockRect(&destLocked, nullptr, 0);
    192    ASSERT(SUCCEEDED(result));
    193    if (FAILED(result))
    194    {
    195        sourceSurface->UnlockRect();
    196    }
    197    ANGLE_TRY_HR(context9, result, "Failed to lock the destination surface for CopyImage");
    198 
    199    const uint8_t *sourceData = static_cast<const uint8_t *>(sourceLocked.pBits) +
    200                                sourceRect.x * sourceD3DFormatInfo.pixelBytes +
    201                                sourceRect.y * sourceLocked.Pitch;
    202    uint8_t *destData = static_cast<uint8_t *>(destLocked.pBits) +
    203                        destOffset.x * destD3DFormatInfo.pixelBytes +
    204                        destOffset.y * destLocked.Pitch;
    205    ASSERT(sourceData && destData);
    206 
    207    CopyImageCHROMIUM(sourceData, sourceLocked.Pitch, sourceD3DFormatInfo.pixelBytes, 0,
    208                      sourceD3DFormatInfo.info().pixelReadFunction, destData, destLocked.Pitch,
    209                      destD3DFormatInfo.pixelBytes, 0, destD3DFormatInfo.info().pixelWriteFunction,
    210                      gl::GetUnsizedFormat(dest->getInternalFormat()),
    211                      destD3DFormatInfo.info().componentType, sourceRect.width, sourceRect.height,
    212                      1, unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha);
    213 
    214    dest->markDirty();
    215 
    216    destSurface->UnlockRect();
    217    sourceSurface->UnlockRect();
    218 
    219    return angle::Result::Continue;
    220 }
    221 
    222 bool Image9::redefine(gl::TextureType type,
    223                      GLenum internalformat,
    224                      const gl::Extents &size,
    225                      bool forceRelease)
    226 {
    227    // 3D textures are not supported by the D3D9 backend.
    228    ASSERT(size.depth <= 1);
    229 
    230    // Only 2D and cube texture are supported by the D3D9 backend.
    231    ASSERT(type == gl::TextureType::_2D || type == gl::TextureType::CubeMap);
    232 
    233    if (mWidth != size.width || mHeight != size.height || mDepth != size.depth ||
    234        mInternalFormat != internalformat || forceRelease)
    235    {
    236        mWidth          = size.width;
    237        mHeight         = size.height;
    238        mDepth          = size.depth;
    239        mType           = type;
    240        mInternalFormat = internalformat;
    241 
    242        // compute the d3d format that will be used
    243        const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(internalformat);
    244        mD3DFormat                                = d3d9FormatInfo.texFormat;
    245        mRenderable                               = (d3d9FormatInfo.renderFormat != D3DFMT_UNKNOWN);
    246 
    247        SafeRelease(mSurface);
    248        mDirty = (d3d9FormatInfo.dataInitializerFunction != nullptr);
    249 
    250        return true;
    251    }
    252 
    253    return false;
    254 }
    255 
    256 angle::Result Image9::createSurface(Context9 *context9)
    257 {
    258    if (mSurface)
    259    {
    260        return angle::Result::Continue;
    261    }
    262 
    263    IDirect3DTexture9 *newTexture = nullptr;
    264    IDirect3DSurface9 *newSurface = nullptr;
    265    const D3DPOOL poolToUse       = D3DPOOL_SYSTEMMEM;
    266    const D3DFORMAT d3dFormat     = getD3DFormat();
    267 
    268    if (mWidth != 0 && mHeight != 0)
    269    {
    270        int levelToFetch      = 0;
    271        GLsizei requestWidth  = mWidth;
    272        GLsizei requestHeight = mHeight;
    273        d3d9::MakeValidSize(true, d3dFormat, &requestWidth, &requestHeight, &levelToFetch);
    274 
    275        IDirect3DDevice9 *device = mRenderer->getDevice();
    276 
    277        HRESULT result = device->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, 0,
    278                                               d3dFormat, poolToUse, &newTexture, nullptr);
    279 
    280        ANGLE_TRY_HR(context9, result, "Failed to create image surface");
    281 
    282        newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
    283        SafeRelease(newTexture);
    284 
    285        const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat);
    286        if (d3dFormatInfo.dataInitializerFunction != nullptr)
    287        {
    288            RECT entireRect;
    289            entireRect.left   = 0;
    290            entireRect.right  = mWidth;
    291            entireRect.top    = 0;
    292            entireRect.bottom = mHeight;
    293 
    294            D3DLOCKED_RECT lockedRect;
    295            result = newSurface->LockRect(&lockedRect, &entireRect, 0);
    296            ASSERT(SUCCEEDED(result));
    297            ANGLE_TRY_HR(context9, result, "Failed to lock image surface");
    298 
    299            d3dFormatInfo.dataInitializerFunction(
    300                mWidth, mHeight, 1, static_cast<uint8_t *>(lockedRect.pBits), lockedRect.Pitch, 0);
    301 
    302            result = newSurface->UnlockRect();
    303            ASSERT(SUCCEEDED(result));
    304            ANGLE_TRY_HR(context9, result, "Failed to unlock image surface");
    305        }
    306    }
    307 
    308    mSurface = newSurface;
    309    mDirty   = false;
    310    mD3DPool = poolToUse;
    311 
    312    return angle::Result::Continue;
    313 }
    314 
    315 angle::Result Image9::lock(Context9 *context9, D3DLOCKED_RECT *lockedRect, const RECT &rect)
    316 {
    317    ANGLE_TRY(createSurface(context9));
    318 
    319    if (mSurface)
    320    {
    321        HRESULT result = mSurface->LockRect(lockedRect, &rect, 0);
    322        ASSERT(SUCCEEDED(result));
    323        ANGLE_TRY_HR(context9, result, "Failed to lock image surface");
    324        mDirty = true;
    325    }
    326 
    327    return angle::Result::Continue;
    328 }
    329 
    330 void Image9::unlock()
    331 {
    332    if (mSurface)
    333    {
    334        HRESULT result = mSurface->UnlockRect();
    335        ASSERT(SUCCEEDED(result));
    336    }
    337 }
    338 
    339 D3DFORMAT Image9::getD3DFormat() const
    340 {
    341    // this should only happen if the image hasn't been redefined first
    342    // which would be a bug by the caller
    343    ASSERT(mD3DFormat != D3DFMT_UNKNOWN);
    344 
    345    return mD3DFormat;
    346 }
    347 
    348 bool Image9::isDirty() const
    349 {
    350    // Make sure to that this image is marked as dirty even if the staging texture hasn't been
    351    // created yet if initialization is required before use.
    352    return (mSurface ||
    353            d3d9::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != nullptr) &&
    354           mDirty;
    355 }
    356 
    357 angle::Result Image9::getSurface(Context9 *context9, IDirect3DSurface9 **outSurface)
    358 {
    359    ANGLE_TRY(createSurface(context9));
    360    *outSurface = mSurface;
    361    return angle::Result::Continue;
    362 }
    363 
    364 angle::Result Image9::setManagedSurface2D(const gl::Context *context,
    365                                          TextureStorage *storage,
    366                                          int level)
    367 {
    368    IDirect3DSurface9 *surface = nullptr;
    369    TextureStorage9 *storage9  = GetAs<TextureStorage9>(storage);
    370    ANGLE_TRY(storage9->getSurfaceLevel(context, gl::TextureTarget::_2D, level, false, &surface));
    371    return setManagedSurface(GetImplAs<Context9>(context), surface);
    372 }
    373 
    374 angle::Result Image9::setManagedSurfaceCube(const gl::Context *context,
    375                                            TextureStorage *storage,
    376                                            int face,
    377                                            int level)
    378 {
    379    IDirect3DSurface9 *surface = nullptr;
    380    TextureStorage9 *storage9  = GetAs<TextureStorage9>(storage);
    381    ANGLE_TRY(storage9->getSurfaceLevel(context, gl::CubeFaceIndexToTextureTarget(face), level,
    382                                        false, &surface));
    383    return setManagedSurface(GetImplAs<Context9>(context), surface);
    384 }
    385 
    386 angle::Result Image9::setManagedSurface(Context9 *context9, IDirect3DSurface9 *surface)
    387 {
    388    D3DSURFACE_DESC desc;
    389    surface->GetDesc(&desc);
    390    ASSERT(desc.Pool == D3DPOOL_MANAGED);
    391 
    392    if ((GLsizei)desc.Width == mWidth && (GLsizei)desc.Height == mHeight)
    393    {
    394        if (mSurface)
    395        {
    396            angle::Result result = CopyLockableSurfaces(context9, surface, mSurface);
    397            SafeRelease(mSurface);
    398            ANGLE_TRY(result);
    399        }
    400 
    401        mSurface = surface;
    402        mD3DPool = desc.Pool;
    403    }
    404 
    405    return angle::Result::Continue;
    406 }
    407 
    408 angle::Result Image9::copyToStorage(const gl::Context *context,
    409                                    TextureStorage *storage,
    410                                    const gl::ImageIndex &index,
    411                                    const gl::Box &region)
    412 {
    413    ANGLE_TRY(createSurface(GetImplAs<Context9>(context)));
    414 
    415    TextureStorage9 *storage9      = GetAs<TextureStorage9>(storage);
    416    IDirect3DSurface9 *destSurface = nullptr;
    417    ANGLE_TRY(storage9->getSurfaceLevel(context, index.getTarget(), index.getLevelIndex(), true,
    418                                        &destSurface));
    419 
    420    angle::Result result = copyToSurface(GetImplAs<Context9>(context), destSurface, region);
    421    SafeRelease(destSurface);
    422    return result;
    423 }
    424 
    425 angle::Result Image9::copyToSurface(Context9 *context9,
    426                                    IDirect3DSurface9 *destSurface,
    427                                    const gl::Box &area)
    428 {
    429    ASSERT(area.width > 0 && area.height > 0 && area.depth == 1);
    430    ASSERT(destSurface);
    431 
    432    IDirect3DSurface9 *sourceSurface = nullptr;
    433    ANGLE_TRY(getSurface(context9, &sourceSurface));
    434 
    435    ASSERT(sourceSurface && sourceSurface != destSurface);
    436 
    437    RECT rect;
    438    rect.left   = area.x;
    439    rect.top    = area.y;
    440    rect.right  = area.x + area.width;
    441    rect.bottom = area.y + area.height;
    442 
    443    POINT point = {rect.left, rect.top};
    444 
    445    IDirect3DDevice9 *device = mRenderer->getDevice();
    446 
    447    if (mD3DPool == D3DPOOL_MANAGED)
    448    {
    449        D3DSURFACE_DESC desc;
    450        sourceSurface->GetDesc(&desc);
    451 
    452        IDirect3DSurface9 *surf = 0;
    453        HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format,
    454                                                             D3DPOOL_SYSTEMMEM, &surf, nullptr);
    455        ANGLE_TRY_HR(context9, result, "Internal CreateOffscreenPlainSurface call failed");
    456 
    457        auto err = CopyLockableSurfaces(context9, surf, sourceSurface);
    458        result   = device->UpdateSurface(surf, &rect, destSurface, &point);
    459        SafeRelease(surf);
    460        ANGLE_TRY(err);
    461        ASSERT(SUCCEEDED(result));
    462        ANGLE_TRY_HR(context9, result, "Internal UpdateSurface call failed");
    463    }
    464    else
    465    {
    466        // UpdateSurface: source must be SYSTEMMEM, dest must be DEFAULT pools
    467        HRESULT result = device->UpdateSurface(sourceSurface, &rect, destSurface, &point);
    468        ASSERT(SUCCEEDED(result));
    469        ANGLE_TRY_HR(context9, result, "Internal UpdateSurface call failed");
    470    }
    471 
    472    return angle::Result::Continue;
    473 }
    474 
    475 // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as
    476 // format/type at input into the target pixel rectangle.
    477 angle::Result Image9::loadData(const gl::Context *context,
    478                               const gl::Box &area,
    479                               const gl::PixelUnpackState &unpack,
    480                               GLenum type,
    481                               const void *input,
    482                               bool applySkipImages)
    483 {
    484    // 3D textures are not supported by the D3D9 backend.
    485    ASSERT(area.z == 0 && area.depth == 1);
    486 
    487    Context9 *context9 = GetImplAs<Context9>(context);
    488 
    489    const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat);
    490    GLuint inputRowPitch                 = 0;
    491    ANGLE_CHECK_GL_MATH(context9, formatInfo.computeRowPitch(type, area.width, unpack.alignment,
    492                                                             unpack.rowLength, &inputRowPitch));
    493    ASSERT(!applySkipImages);
    494    ASSERT(unpack.skipPixels == 0);
    495    ASSERT(unpack.skipRows == 0);
    496 
    497    const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat);
    498    ASSERT(d3dFormatInfo.loadFunction != nullptr);
    499 
    500    RECT lockRect = {area.x, area.y, area.x + area.width, area.y + area.height};
    501 
    502    D3DLOCKED_RECT locked;
    503    ANGLE_TRY(lock(GetImplAs<Context9>(context), &locked, lockRect));
    504 
    505    d3dFormatInfo.loadFunction(area.width, area.height, area.depth,
    506                               static_cast<const uint8_t *>(input), inputRowPitch, 0,
    507                               static_cast<uint8_t *>(locked.pBits), locked.Pitch, 0);
    508 
    509    unlock();
    510 
    511    return angle::Result::Continue;
    512 }
    513 
    514 angle::Result Image9::loadCompressedData(const gl::Context *context,
    515                                         const gl::Box &area,
    516                                         const void *input)
    517 {
    518    // 3D textures are not supported by the D3D9 backend.
    519    ASSERT(area.z == 0 && area.depth == 1);
    520 
    521    Context9 *context9 = GetImplAs<Context9>(context);
    522 
    523    const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat);
    524    GLuint inputRowPitch                 = 0;
    525    ANGLE_CHECK_GL_MATH(
    526        context9, formatInfo.computeRowPitch(GL_UNSIGNED_BYTE, area.width, 1, 0, &inputRowPitch));
    527 
    528    GLuint inputDepthPitch = 0;
    529    ANGLE_CHECK_GL_MATH(
    530        context9, formatInfo.computeDepthPitch(area.height, 0, inputRowPitch, &inputDepthPitch));
    531 
    532    const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat);
    533 
    534    ASSERT(area.x % d3d9::GetD3DFormatInfo(d3d9FormatInfo.texFormat).blockWidth == 0);
    535    ASSERT(area.y % d3d9::GetD3DFormatInfo(d3d9FormatInfo.texFormat).blockHeight == 0);
    536 
    537    ASSERT(d3d9FormatInfo.loadFunction != nullptr);
    538 
    539    RECT lockRect = {area.x, area.y, area.x + area.width, area.y + area.height};
    540 
    541    D3DLOCKED_RECT locked;
    542    ANGLE_TRY(lock(GetImplAs<Context9>(context), &locked, lockRect));
    543 
    544    d3d9FormatInfo.loadFunction(area.width, area.height, area.depth,
    545                                static_cast<const uint8_t *>(input), inputRowPitch, inputDepthPitch,
    546                                static_cast<uint8_t *>(locked.pBits), locked.Pitch, 0);
    547 
    548    unlock();
    549 
    550    return angle::Result::Continue;
    551 }
    552 
    553 // This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete
    554 // textures
    555 angle::Result Image9::copyFromRTInternal(Context9 *context9,
    556                                         const gl::Offset &destOffset,
    557                                         const gl::Rectangle &sourceArea,
    558                                         RenderTargetD3D *source)
    559 {
    560    ASSERT(source);
    561 
    562    // ES3.0 only behaviour to copy into a 3d texture
    563    ASSERT(destOffset.z == 0);
    564 
    565    RenderTarget9 *renderTarget = GetAs<RenderTarget9>(source);
    566 
    567    angle::ComPtr<IDirect3DSurface9> surface = renderTarget->getSurface();
    568    ASSERT(surface);
    569 
    570    IDirect3DDevice9 *device = mRenderer->getDevice();
    571 
    572    angle::ComPtr<IDirect3DSurface9> renderTargetData = nullptr;
    573    D3DSURFACE_DESC description;
    574    surface->GetDesc(&description);
    575 
    576    HRESULT hr = device->CreateOffscreenPlainSurface(description.Width, description.Height,
    577                                                     description.Format, D3DPOOL_SYSTEMMEM,
    578                                                     &renderTargetData, nullptr);
    579 
    580    ANGLE_TRY_HR(context9, hr, "Could not create matching destination surface");
    581 
    582    hr = device->GetRenderTargetData(surface.Get(), renderTargetData.Get());
    583 
    584    ANGLE_TRY_HR(context9, hr, "GetRenderTargetData unexpectedly failed");
    585 
    586    int width  = sourceArea.width;
    587    int height = sourceArea.height;
    588 
    589    RECT sourceRect = {sourceArea.x, sourceArea.y, sourceArea.x + width, sourceArea.y + height};
    590    RECT destRect   = {destOffset.x, destOffset.y, destOffset.x + width, destOffset.y + height};
    591 
    592    D3DLOCKED_RECT sourceLock = {};
    593    hr                        = renderTargetData->LockRect(&sourceLock, &sourceRect, 0);
    594 
    595    ANGLE_TRY_HR(context9, hr, "Failed to lock the source surface (rectangle might be invalid)");
    596 
    597    D3DLOCKED_RECT destLock = {};
    598    angle::Result result    = lock(context9, &destLock, destRect);
    599    if (result == angle::Result::Stop)
    600    {
    601        renderTargetData->UnlockRect();
    602    }
    603    ANGLE_TRY(result);
    604 
    605    ASSERT(destLock.pBits && sourceLock.pBits);
    606 
    607    unsigned char *sourcePixels = (unsigned char *)sourceLock.pBits;
    608    unsigned char *destPixels   = (unsigned char *)destLock.pBits;
    609 
    610    switch (description.Format)
    611    {
    612        case D3DFMT_X8R8G8B8:
    613        case D3DFMT_A8R8G8B8:
    614            switch (getD3DFormat())
    615            {
    616                case D3DFMT_X8R8G8B8:
    617                case D3DFMT_A8R8G8B8:
    618                    for (int y = 0; y < height; y++)
    619                    {
    620                        memcpy(destPixels, sourcePixels, 4 * width);
    621                        sourcePixels += sourceLock.Pitch;
    622                        destPixels += destLock.Pitch;
    623                    }
    624                    break;
    625                case D3DFMT_L8:
    626                    for (int y = 0; y < height; y++)
    627                    {
    628                        for (int x = 0; x < width; x++)
    629                        {
    630                            destPixels[x] = sourcePixels[x * 4 + 2];
    631                        }
    632                        sourcePixels += sourceLock.Pitch;
    633                        destPixels += destLock.Pitch;
    634                    }
    635                    break;
    636                case D3DFMT_A8L8:
    637                    for (int y = 0; y < height; y++)
    638                    {
    639                        for (int x = 0; x < width; x++)
    640                        {
    641                            destPixels[x * 2 + 0] = sourcePixels[x * 4 + 2];
    642                            destPixels[x * 2 + 1] = sourcePixels[x * 4 + 3];
    643                        }
    644                        sourcePixels += sourceLock.Pitch;
    645                        destPixels += destLock.Pitch;
    646                    }
    647                    break;
    648                default:
    649                    UNREACHABLE();
    650            }
    651            break;
    652        case D3DFMT_R5G6B5:
    653            switch (getD3DFormat())
    654            {
    655                case D3DFMT_X8R8G8B8:
    656                    for (int y = 0; y < height; y++)
    657                    {
    658                        for (int x = 0; x < width; x++)
    659                        {
    660                            unsigned short rgb  = ((unsigned short *)sourcePixels)[x];
    661                            unsigned char red   = static_cast<unsigned char>((rgb & 0xF800) >> 8);
    662                            unsigned char green = static_cast<unsigned char>((rgb & 0x07E0) >> 3);
    663                            unsigned char blue  = static_cast<unsigned char>((rgb & 0x001F) << 3);
    664                            destPixels[x + 0]   = blue | (blue >> 5);
    665                            destPixels[x + 1]   = green | (green >> 6);
    666                            destPixels[x + 2]   = red | (red >> 5);
    667                            destPixels[x + 3]   = 0xFF;
    668                        }
    669                        sourcePixels += sourceLock.Pitch;
    670                        destPixels += destLock.Pitch;
    671                    }
    672                    break;
    673                case D3DFMT_L8:
    674                    for (int y = 0; y < height; y++)
    675                    {
    676                        for (int x = 0; x < width; x++)
    677                        {
    678                            unsigned char red = sourcePixels[x * 2 + 1] & 0xF8;
    679                            destPixels[x]     = red | (red >> 5);
    680                        }
    681                        sourcePixels += sourceLock.Pitch;
    682                        destPixels += destLock.Pitch;
    683                    }
    684                    break;
    685                default:
    686                    UNREACHABLE();
    687            }
    688            break;
    689        case D3DFMT_A1R5G5B5:
    690            switch (getD3DFormat())
    691            {
    692                case D3DFMT_X8R8G8B8:
    693                    for (int y = 0; y < height; y++)
    694                    {
    695                        for (int x = 0; x < width; x++)
    696                        {
    697                            unsigned short argb = ((unsigned short *)sourcePixels)[x];
    698                            unsigned char red   = static_cast<unsigned char>((argb & 0x7C00) >> 7);
    699                            unsigned char green = static_cast<unsigned char>((argb & 0x03E0) >> 2);
    700                            unsigned char blue  = static_cast<unsigned char>((argb & 0x001F) << 3);
    701                            destPixels[x + 0]   = blue | (blue >> 5);
    702                            destPixels[x + 1]   = green | (green >> 5);
    703                            destPixels[x + 2]   = red | (red >> 5);
    704                            destPixels[x + 3]   = 0xFF;
    705                        }
    706                        sourcePixels += sourceLock.Pitch;
    707                        destPixels += destLock.Pitch;
    708                    }
    709                    break;
    710                case D3DFMT_A8R8G8B8:
    711                    for (int y = 0; y < height; y++)
    712                    {
    713                        for (int x = 0; x < width; x++)
    714                        {
    715                            unsigned short argb = ((unsigned short *)sourcePixels)[x];
    716                            unsigned char red   = static_cast<unsigned char>((argb & 0x7C00) >> 7);
    717                            unsigned char green = static_cast<unsigned char>((argb & 0x03E0) >> 2);
    718                            unsigned char blue  = static_cast<unsigned char>((argb & 0x001F) << 3);
    719                            unsigned char alpha = (signed short)argb >> 15;
    720                            destPixels[x + 0]   = blue | (blue >> 5);
    721                            destPixels[x + 1]   = green | (green >> 5);
    722                            destPixels[x + 2]   = red | (red >> 5);
    723                            destPixels[x + 3]   = alpha;
    724                        }
    725                        sourcePixels += sourceLock.Pitch;
    726                        destPixels += destLock.Pitch;
    727                    }
    728                    break;
    729                case D3DFMT_L8:
    730                    for (int y = 0; y < height; y++)
    731                    {
    732                        for (int x = 0; x < width; x++)
    733                        {
    734                            unsigned char red = sourcePixels[x * 2 + 1] & 0x7C;
    735                            destPixels[x]     = (red << 1) | (red >> 4);
    736                        }
    737                        sourcePixels += sourceLock.Pitch;
    738                        destPixels += destLock.Pitch;
    739                    }
    740                    break;
    741                case D3DFMT_A8L8:
    742                    for (int y = 0; y < height; y++)
    743                    {
    744                        for (int x = 0; x < width; x++)
    745                        {
    746                            unsigned char red     = sourcePixels[x * 2 + 1] & 0x7C;
    747                            destPixels[x * 2 + 0] = (red << 1) | (red >> 4);
    748                            destPixels[x * 2 + 1] = (signed char)sourcePixels[x * 2 + 1] >> 7;
    749                        }
    750                        sourcePixels += sourceLock.Pitch;
    751                        destPixels += destLock.Pitch;
    752                    }
    753                    break;
    754                default:
    755                    UNREACHABLE();
    756            }
    757            break;
    758        case D3DFMT_A16B16G16R16F:
    759            switch (getD3DFormat())
    760            {
    761                case D3DFMT_X8R8G8B8:
    762                case D3DFMT_A8R8G8B8:
    763                    for (int y = 0; y < height; y++)
    764                    {
    765                        const uint16_t *sourcePixels16F =
    766                            reinterpret_cast<uint16_t *>(sourcePixels);
    767                        for (int x = 0; x < width; x++)
    768                        {
    769                            float r = gl::float16ToFloat32(sourcePixels16F[x * 4 + 0]);
    770                            float g = gl::float16ToFloat32(sourcePixels16F[x * 4 + 1]);
    771                            float b = gl::float16ToFloat32(sourcePixels16F[x * 4 + 2]);
    772                            float a = gl::float16ToFloat32(sourcePixels16F[x * 4 + 3]);
    773                            destPixels[x * 4 + 0] = gl::floatToNormalized<uint8_t>(b);
    774                            destPixels[x * 4 + 1] = gl::floatToNormalized<uint8_t>(g);
    775                            destPixels[x * 4 + 2] = gl::floatToNormalized<uint8_t>(r);
    776                            destPixels[x * 4 + 3] = gl::floatToNormalized<uint8_t>(a);
    777                        }
    778                        sourcePixels += sourceLock.Pitch;
    779                        destPixels += destLock.Pitch;
    780                    }
    781                    break;
    782                case D3DFMT_L8:
    783                    for (int y = 0; y < height; y++)
    784                    {
    785                        const uint16_t *sourcePixels16F =
    786                            reinterpret_cast<uint16_t *>(sourcePixels);
    787                        for (int x = 0; x < width; x++)
    788                        {
    789                            float r       = gl::float16ToFloat32(sourcePixels16F[x * 4]);
    790                            destPixels[x] = gl::floatToNormalized<uint8_t>(r);
    791                        }
    792                        sourcePixels += sourceLock.Pitch;
    793                        destPixels += destLock.Pitch;
    794                    }
    795                    break;
    796                case D3DFMT_A8L8:
    797                    for (int y = 0; y < height; y++)
    798                    {
    799                        const uint16_t *sourcePixels16F =
    800                            reinterpret_cast<uint16_t *>(sourcePixels);
    801                        for (int x = 0; x < width; x++)
    802                        {
    803                            float r = gl::float16ToFloat32(sourcePixels16F[x * 4 + 0]);
    804                            float a = gl::float16ToFloat32(sourcePixels16F[x * 4 + 3]);
    805                            destPixels[x * 2 + 0] = gl::floatToNormalized<uint8_t>(r);
    806                            destPixels[x * 2 + 1] = gl::floatToNormalized<uint8_t>(a);
    807                        }
    808                        sourcePixels += sourceLock.Pitch;
    809                        destPixels += destLock.Pitch;
    810                    }
    811                    break;
    812                default:
    813                    UNREACHABLE();
    814            }
    815            break;
    816        case D3DFMT_A32B32G32R32F:
    817            switch (getD3DFormat())
    818            {
    819                case D3DFMT_X8R8G8B8:
    820                case D3DFMT_A8R8G8B8:
    821                    for (int y = 0; y < height; y++)
    822                    {
    823                        const float *sourcePixels32F = reinterpret_cast<float *>(sourcePixels);
    824                        for (int x = 0; x < width; x++)
    825                        {
    826                            float r               = sourcePixels32F[x * 4 + 0];
    827                            float g               = sourcePixels32F[x * 4 + 1];
    828                            float b               = sourcePixels32F[x * 4 + 2];
    829                            float a               = sourcePixels32F[x * 4 + 3];
    830                            destPixels[x * 4 + 0] = gl::floatToNormalized<uint8_t>(b);
    831                            destPixels[x * 4 + 1] = gl::floatToNormalized<uint8_t>(g);
    832                            destPixels[x * 4 + 2] = gl::floatToNormalized<uint8_t>(r);
    833                            destPixels[x * 4 + 3] = gl::floatToNormalized<uint8_t>(a);
    834                        }
    835                        sourcePixels += sourceLock.Pitch;
    836                        destPixels += destLock.Pitch;
    837                    }
    838                    break;
    839                case D3DFMT_L8:
    840                    for (int y = 0; y < height; y++)
    841                    {
    842                        const float *sourcePixels32F = reinterpret_cast<float *>(sourcePixels);
    843                        for (int x = 0; x < width; x++)
    844                        {
    845                            float r       = sourcePixels32F[x * 4];
    846                            destPixels[x] = gl::floatToNormalized<uint8_t>(r);
    847                        }
    848                        sourcePixels += sourceLock.Pitch;
    849                        destPixels += destLock.Pitch;
    850                    }
    851                    break;
    852                case D3DFMT_A8L8:
    853                    for (int y = 0; y < height; y++)
    854                    {
    855                        const float *sourcePixels32F = reinterpret_cast<float *>(sourcePixels);
    856                        for (int x = 0; x < width; x++)
    857                        {
    858                            float r               = sourcePixels32F[x * 4 + 0];
    859                            float a               = sourcePixels32F[x * 4 + 3];
    860                            destPixels[x * 2 + 0] = gl::floatToNormalized<uint8_t>(r);
    861                            destPixels[x * 2 + 1] = gl::floatToNormalized<uint8_t>(a);
    862                        }
    863                        sourcePixels += sourceLock.Pitch;
    864                        destPixels += destLock.Pitch;
    865                    }
    866                    break;
    867                default:
    868                    UNREACHABLE();
    869            }
    870            break;
    871        default:
    872            UNREACHABLE();
    873    }
    874 
    875    unlock();
    876    renderTargetData->UnlockRect();
    877 
    878    mDirty = true;
    879    return angle::Result::Continue;
    880 }
    881 
    882 angle::Result Image9::copyFromTexStorage(const gl::Context *context,
    883                                         const gl::ImageIndex &imageIndex,
    884                                         TextureStorage *source)
    885 {
    886    RenderTargetD3D *renderTarget = nullptr;
    887    ANGLE_TRY(source->getRenderTarget(context, imageIndex, 0, &renderTarget));
    888 
    889    gl::Rectangle sourceArea(0, 0, mWidth, mHeight);
    890    return copyFromRTInternal(GetImplAs<Context9>(context), gl::Offset(), sourceArea, renderTarget);
    891 }
    892 
    893 angle::Result Image9::copyFromFramebuffer(const gl::Context *context,
    894                                          const gl::Offset &destOffset,
    895                                          const gl::Rectangle &sourceArea,
    896                                          const gl::Framebuffer *source)
    897 {
    898    const gl::FramebufferAttachment *srcAttachment = source->getReadColorAttachment();
    899    ASSERT(srcAttachment);
    900 
    901    RenderTargetD3D *renderTarget = nullptr;
    902    ANGLE_TRY(srcAttachment->getRenderTarget(context, 0, &renderTarget));
    903    ASSERT(renderTarget);
    904    return copyFromRTInternal(GetImplAs<Context9>(context), destOffset, sourceArea, renderTarget);
    905 }
    906 
    907 }  // namespace rx