Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / angle / src / libGLESv2 / renderer / d3d / d3d9 / Image9.cpp
index 18383fb..8b1d7a5 100644 (file)
@@ -17,7 +17,7 @@
 #include "libGLESv2/Framebuffer.h"
 #include "libGLESv2/FramebufferAttachment.h"
 #include "libGLESv2/Renderbuffer.h"
-
+#include "common/utilities.h"
 
 namespace rx
 {
@@ -36,15 +36,23 @@ Image9::~Image9()
     SafeRelease(mSurface);
 }
 
-void Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface)
+gl::Error Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface)
 {
     D3DSURFACE_DESC destDesc;
     HRESULT result = destSurface->GetDesc(&destDesc);
     ASSERT(SUCCEEDED(result));
+    if (FAILED(result))
+    {
+        return gl::Error(GL_OUT_OF_MEMORY, "Failed to query the source surface description for mipmap generation, result: 0x%X.", result);
+    }
 
     D3DSURFACE_DESC sourceDesc;
     result = sourceSurface->GetDesc(&sourceDesc);
     ASSERT(SUCCEEDED(result));
+    if (FAILED(result))
+    {
+        return gl::Error(GL_OUT_OF_MEMORY, "Failed to query the destination surface description for mipmap generation, result: 0x%X.", result);
+    }
 
     ASSERT(sourceDesc.Format == destDesc.Format);
     ASSERT(sourceDesc.Width == 1 || sourceDesc.Width / 2 == destDesc.Width);
@@ -56,22 +64,32 @@ void Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sour
     D3DLOCKED_RECT sourceLocked = {0};
     result = sourceSurface->LockRect(&sourceLocked, NULL, D3DLOCK_READONLY);
     ASSERT(SUCCEEDED(result));
+    if (FAILED(result))
+    {
+        return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock the source surface for mipmap generation, result: 0x%X.", result);
+    }
 
     D3DLOCKED_RECT destLocked = {0};
     result = destSurface->LockRect(&destLocked, NULL, 0);
     ASSERT(SUCCEEDED(result));
+    if (FAILED(result))
+    {
+        sourceSurface->UnlockRect();
+        return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock the destination surface for mipmap generation, result: 0x%X.", result);
+    }
 
     const uint8_t *sourceData = reinterpret_cast<const uint8_t*>(sourceLocked.pBits);
     uint8_t *destData = reinterpret_cast<uint8_t*>(destLocked.pBits);
 
-    if (sourceData && destData)
-    {
-        d3dFormatInfo.mipGenerationFunction(sourceDesc.Width, sourceDesc.Height, 1, sourceData, sourceLocked.Pitch, 0,
-                                            destData, destLocked.Pitch, 0);
-    }
+    ASSERT(sourceData && destData);
+
+    d3dFormatInfo.mipGenerationFunction(sourceDesc.Width, sourceDesc.Height, 1, sourceData, sourceLocked.Pitch, 0,
+                                        destData, destLocked.Pitch, 0);
 
     destSurface->UnlockRect();
     sourceSurface->UnlockRect();
+
+    return gl::Error(GL_NO_ERROR);
 }
 
 Image9 *Image9::makeImage9(Image *img)
@@ -80,47 +98,74 @@ Image9 *Image9::makeImage9(Image *img)
     return static_cast<rx::Image9*>(img);
 }
 
-void Image9::generateMipmap(Image9 *dest, Image9 *source)
+gl::Error Image9::generateMipmap(Image9 *dest, Image9 *source)
 {
-    IDirect3DSurface9 *sourceSurface = source->getSurface();
-    if (sourceSurface == NULL)
-        return gl::error(GL_OUT_OF_MEMORY);
+    IDirect3DSurface9 *sourceSurface = NULL;
+    gl::Error error = source->getSurface(&sourceSurface);
+    if (error.isError())
+    {
+        return error;
+    }
 
-    IDirect3DSurface9 *destSurface = dest->getSurface();
-    generateMip(destSurface, sourceSurface);
+    IDirect3DSurface9 *destSurface = NULL;
+    error = dest->getSurface(&destSurface);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    error = generateMip(destSurface, sourceSurface);
+    if (error.isError())
+    {
+        return error;
+    }
 
     dest->markDirty();
+
+    return gl::Error(GL_NO_ERROR);
 }
 
-void Image9::copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source)
+gl::Error Image9::copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source)
 {
     D3DLOCKED_RECT sourceLock = {0};
     D3DLOCKED_RECT destLock = {0};
 
-    source->LockRect(&sourceLock, NULL, 0);
-    dest->LockRect(&destLock, NULL, 0);
+    HRESULT result;
+
+    result = source->LockRect(&sourceLock, NULL, 0);
+    if (FAILED(result))
+    {
+        return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock source surface for copy, result: 0x%X.", result);
+    }
 
-    if (sourceLock.pBits && destLock.pBits)
+    result = dest->LockRect(&destLock, NULL, 0);
+    if (FAILED(result))
     {
-        D3DSURFACE_DESC desc;
-        source->GetDesc(&desc);
+        source->UnlockRect();
+        return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock source surface for copy, result: 0x%X.", result);
+    }
 
-        const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format);
-        unsigned int rows = desc.Height / d3dFormatInfo.blockHeight;
+    ASSERT(sourceLock.pBits && destLock.pBits);
 
-        unsigned int bytes = d3d9::ComputeBlockSize(desc.Format, desc.Width, d3dFormatInfo.blockHeight);
-        ASSERT(bytes <= static_cast<unsigned int>(sourceLock.Pitch) &&
-               bytes <= static_cast<unsigned int>(destLock.Pitch));
+    D3DSURFACE_DESC desc;
+    source->GetDesc(&desc);
 
-        for(unsigned int i = 0; i < rows; i++)
-        {
-            memcpy((char*)destLock.pBits + destLock.Pitch * i, (char*)sourceLock.pBits + sourceLock.Pitch * i, bytes);
-        }
+    const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format);
+    unsigned int rows = desc.Height / d3dFormatInfo.blockHeight;
 
-        source->UnlockRect();
-        dest->UnlockRect();
+    unsigned int bytes = d3d9::ComputeBlockSize(desc.Format, desc.Width, d3dFormatInfo.blockHeight);
+    ASSERT(bytes <= static_cast<unsigned int>(sourceLock.Pitch) &&
+           bytes <= static_cast<unsigned int>(destLock.Pitch));
+
+    for(unsigned int i = 0; i < rows; i++)
+    {
+        memcpy((char*)destLock.pBits + destLock.Pitch * i, (char*)sourceLock.pBits + sourceLock.Pitch * i, bytes);
     }
-    else UNREACHABLE();
+
+    source->UnlockRect();
+    dest->UnlockRect();
+
+    return gl::Error(GL_NO_ERROR);
 }
 
 bool Image9::redefine(rx::Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease)
@@ -160,11 +205,11 @@ bool Image9::redefine(rx::Renderer *renderer, GLenum target, GLenum internalform
     return false;
 }
 
-void Image9::createSurface()
+gl::Error Image9::createSurface()
 {
-    if(mSurface)
+    if (mSurface)
     {
-        return;
+        return gl::Error(GL_NO_ERROR);
     }
 
     IDirect3DTexture9 *newTexture = NULL;
@@ -187,8 +232,7 @@ void Image9::createSurface()
         if (FAILED(result))
         {
             ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
-            ERR("Creating image surface failed.");
-            return gl::error(GL_OUT_OF_MEMORY);
+            return gl::Error(GL_OUT_OF_MEMORY, "Failed to create image surface, result: 0x%X.", result);
         }
 
         newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
@@ -206,35 +250,51 @@ void Image9::createSurface()
             D3DLOCKED_RECT lockedRect;
             result = newSurface->LockRect(&lockedRect, &entireRect, 0);
             ASSERT(SUCCEEDED(result));
+            if (FAILED(result))
+            {
+                return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock image surface, result: 0x%X.", result);
+            }
 
             d3dFormatInfo.dataInitializerFunction(mWidth, mHeight, 1, reinterpret_cast<uint8_t*>(lockedRect.pBits),
                                                   lockedRect.Pitch, 0);
 
             result = newSurface->UnlockRect();
             ASSERT(SUCCEEDED(result));
+            if (FAILED(result))
+            {
+                return gl::Error(GL_OUT_OF_MEMORY, "Failed to unlock image surface, result: 0x%X.", result);
+            }
         }
     }
 
     mSurface = newSurface;
     mDirty = false;
     mD3DPool = poolToUse;
+
+    return gl::Error(GL_NO_ERROR);
 }
 
-HRESULT Image9::lock(D3DLOCKED_RECT *lockedRect, const RECT *rect)
+gl::Error Image9::lock(D3DLOCKED_RECT *lockedRect, const RECT &rect)
 {
-    createSurface();
-
-    HRESULT result = D3DERR_INVALIDCALL;
+    gl::Error error = createSurface();
+    if (error.isError())
+    {
+        return error;
+    }
 
     if (mSurface)
     {
-        result = mSurface->LockRect(lockedRect, rect, 0);
+        HRESULT result = mSurface->LockRect(lockedRect, &rect, 0);
         ASSERT(SUCCEEDED(result));
+        if (FAILED(result))
+        {
+            return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock image surface, result: 0x%X.", result);
+        }
 
         mDirty = true;
     }
 
-    return result;
+    return gl::Error(GL_NO_ERROR);
 }
 
 void Image9::unlock()
@@ -263,26 +323,43 @@ bool Image9::isDirty() const
     return (mSurface || d3d9::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != NULL) && mDirty;
 }
 
-IDirect3DSurface9 *Image9::getSurface()
+gl::Error Image9::getSurface(IDirect3DSurface9 **outSurface)
 {
-    createSurface();
+    gl::Error error = createSurface();
+    if (error.isError())
+    {
+        return error;
+    }
 
-    return mSurface;
+    *outSurface = mSurface;
+    return gl::Error(GL_NO_ERROR);
 }
 
-void Image9::setManagedSurface2D(TextureStorage *storage, int level)
+gl::Error Image9::setManagedSurface2D(TextureStorage *storage, int level)
 {
+    IDirect3DSurface9 *surface = NULL;
     TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage);
-    setManagedSurface(storage9->getSurfaceLevel(level, false));
+    gl::Error error = storage9->getSurfaceLevel(level, false, &surface);
+    if (error.isError())
+    {
+        return error;
+    }
+    return setManagedSurface(surface);
 }
 
-void Image9::setManagedSurfaceCube(TextureStorage *storage, int face, int level)
+gl::Error Image9::setManagedSurfaceCube(TextureStorage *storage, int face, int level)
 {
+    IDirect3DSurface9 *surface = NULL;
     TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage);
-    setManagedSurface(storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false));
+    gl::Error error = storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false, &surface);
+    if (error.isError())
+    {
+        return error;
+    }
+    return setManagedSurface(surface);
 }
 
-void Image9::setManagedSurface(IDirect3DSurface9 *surface)
+gl::Error Image9::setManagedSurface(IDirect3DSurface9 *surface)
 {
     D3DSURFACE_DESC desc;
     surface->GetDesc(&desc);
@@ -292,97 +369,119 @@ void Image9::setManagedSurface(IDirect3DSurface9 *surface)
     {
         if (mSurface)
         {
-            copyLockableSurfaces(surface, mSurface);
+            gl::Error error = copyLockableSurfaces(surface, mSurface);
             SafeRelease(mSurface);
+            if (error.isError())
+            {
+                return error;
+            }
         }
 
         mSurface = surface;
         mD3DPool = desc.Pool;
     }
-}
 
-bool Image9::copyToStorage2D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
-{
-    ASSERT(getSurface() != NULL);
-    TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage);
-    return copyToSurface(storage9->getSurfaceLevel(level, true), xoffset, yoffset, width, height);
+    return gl::Error(GL_NO_ERROR);
 }
 
-bool Image9::copyToStorageCube(TextureStorage *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
+gl::Error Image9::copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region)
 {
-    ASSERT(getSurface() != NULL);
-    TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage);
-    return copyToSurface(storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, true), xoffset, yoffset, width, height);
-}
+    gl::Error error = createSurface();
+    if (error.isError())
+    {
+        return error;
+    }
 
-bool Image9::copyToStorage3D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
-{
-    // 3D textures are not supported by the D3D9 backend.
-    UNREACHABLE();
-    return false;
-}
+    IDirect3DSurface9 *destSurface = NULL;
 
-bool Image9::copyToStorage2DArray(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height)
-{
-    // 2D array textures are not supported by the D3D9 backend.
-    UNREACHABLE();
-    return false;
+    if (index.type == GL_TEXTURE_2D)
+    {
+        TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage);
+        gl::Error error = storage9->getSurfaceLevel(index.mipIndex, true, &destSurface);
+        if (error.isError())
+        {
+            return error;
+        }
+    }
+    else
+    {
+        ASSERT(gl::IsCubemapTextureTarget(index.type));
+        TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage);
+        gl::Error error = storage9->getCubeMapSurface(index.type, index.mipIndex, true, &destSurface);
+        if (error.isError())
+        {
+            return error;
+        }
+    }
+
+    error = copyToSurface(destSurface, region.x, region.y, region.width, region.height);
+    SafeRelease(destSurface);
+    return error;
 }
 
-bool Image9::copyToSurface(IDirect3DSurface9 *destSurface, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
+gl::Error Image9::copyToSurface(IDirect3DSurface9 *destSurface, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
 {
     ASSERT(width > 0 && height > 0);
+    ASSERT(destSurface);
 
-    if (!destSurface)
-        return false;
+    IDirect3DSurface9 *sourceSurface = NULL;
+    gl::Error error = getSurface(&sourceSurface);
+    if (error.isError())
+    {
+        return error;
+    }
 
-    IDirect3DSurface9 *sourceSurface = getSurface();
+    ASSERT(sourceSurface && sourceSurface != destSurface);
 
-    if (sourceSurface && sourceSurface != destSurface)
-    {
-        RECT rect;
-        rect.left = xoffset;
-        rect.top = yoffset;
-        rect.right = xoffset + width;
-        rect.bottom = yoffset + height;
+    RECT rect;
+    rect.left = xoffset;
+    rect.top = yoffset;
+    rect.right = xoffset + width;
+    rect.bottom = yoffset + height;
 
-        POINT point = {rect.left, rect.top};
+    POINT point = {rect.left, rect.top};
 
-        IDirect3DDevice9 *device = mRenderer->getDevice();
+    IDirect3DDevice9 *device = mRenderer->getDevice();
 
-        if (mD3DPool == D3DPOOL_MANAGED)
-        {
-            D3DSURFACE_DESC desc;
-            sourceSurface->GetDesc(&desc);
+    if (mD3DPool == D3DPOOL_MANAGED)
+    {
+        D3DSURFACE_DESC desc;
+        sourceSurface->GetDesc(&desc);
 
-            IDirect3DSurface9 *surf = 0;
-            HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL);
+        IDirect3DSurface9 *surf = 0;
+        HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL);
+        if (FAILED(result))
+        {
+            return gl::Error(GL_OUT_OF_MEMORY, "Internal CreateOffscreenPlainSurface call failed, result: 0x%X.", result);
+        }
 
-            if (SUCCEEDED(result))
-            {
-                copyLockableSurfaces(surf, sourceSurface);
-                result = device->UpdateSurface(surf, &rect, destSurface, &point);
-                ASSERT(SUCCEEDED(result));
-                SafeRelease(surf);
-            }
+        copyLockableSurfaces(surf, sourceSurface);
+        result = device->UpdateSurface(surf, &rect, destSurface, &point);
+        SafeRelease(surf);
+        ASSERT(SUCCEEDED(result));
+        if (FAILED(result))
+        {
+            return gl::Error(GL_OUT_OF_MEMORY, "Internal UpdateSurface call failed, result: 0x%X.", result);
         }
-        else
+    }
+    else
+    {
+        // UpdateSurface: source must be SYSTEMMEM, dest must be DEFAULT pools
+        HRESULT result = device->UpdateSurface(sourceSurface, &rect, destSurface, &point);
+        ASSERT(SUCCEEDED(result));
+        if (FAILED(result))
         {
-            // UpdateSurface: source must be SYSTEMMEM, dest must be DEFAULT pools
-            HRESULT result = device->UpdateSurface(sourceSurface, &rect, destSurface, &point);
-            UNUSED_ASSERTION_VARIABLE(result);
-            ASSERT(SUCCEEDED(result));
+            return gl::Error(GL_OUT_OF_MEMORY, "Internal UpdateSurface call failed, result: 0x%X.", result);
         }
     }
 
-    SafeRelease(destSurface);
-    return true;
+    return gl::Error(GL_NO_ERROR);
 }
 
 // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
 // into the target pixel rectangle.
-void Image9::loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
-                      GLint unpackAlignment, GLenum type, const void *input)
+gl::Error Image9::loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
+                           GLint unpackAlignment, GLenum type, const void *input)
 {
     // 3D textures are not supported by the D3D9 backend.
     ASSERT(zoffset == 0 && depth == 1);
@@ -400,10 +499,10 @@ void Image9::loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width
     };
 
     D3DLOCKED_RECT locked;
-    HRESULT result = lock(&locked, &lockRect);
-    if (FAILED(result))
+    gl::Error error = lock(&locked, lockRect);
+    if (error.isError())
     {
-        return;
+        return error;
     }
 
     d3dFormatInfo.loadFunction(width, height, depth,
@@ -411,10 +510,12 @@ void Image9::loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width
                                reinterpret_cast<uint8_t*>(locked.pBits), locked.Pitch, 0);
 
     unlock();
+
+    return gl::Error(GL_NO_ERROR);
 }
 
-void Image9::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
-                                const void *input)
+gl::Error Image9::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
+                                     const void *input)
 {
     // 3D textures are not supported by the D3D9 backend.
     ASSERT(zoffset == 0 && depth == 1);
@@ -437,10 +538,10 @@ void Image9::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLs
     };
 
     D3DLOCKED_RECT locked;
-    HRESULT result = lock(&locked, &lockRect);
-    if (FAILED(result))
+    gl::Error error = lock(&locked, lockRect);
+    if (error.isError())
     {
-        return;
+        return error;
     }
 
     d3d9FormatInfo.loadFunction(width, height, depth,
@@ -448,33 +549,22 @@ void Image9::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLs
                                 reinterpret_cast<uint8_t*>(locked.pBits), locked.Pitch, 0);
 
     unlock();
+
+    return gl::Error(GL_NO_ERROR);
 }
 
 // This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
-void Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
+gl::Error Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source)
 {
+    ASSERT(source);
+
     // ES3.0 only behaviour to copy into a 3d texture
     ASSERT(zoffset == 0);
 
-    RenderTarget9 *renderTarget = NULL;
-    IDirect3DSurface9 *surface = NULL;
-    gl::FramebufferAttachment *colorbuffer = source->getColorbuffer(0);
-
-    if (colorbuffer)
-    {
-        renderTarget = d3d9::GetAttachmentRenderTarget(colorbuffer);
-    }
-
-    if (renderTarget)
-    {
-        surface = renderTarget->getSurface();
-    }
+    RenderTarget9 *renderTarget = RenderTarget9::makeRenderTarget9(source);
 
-    if (!surface)
-    {
-        ERR("Failed to retrieve the render target.");
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
+    IDirect3DSurface9 *surface = renderTarget->getSurface();
+    ASSERT(surface);
 
     IDirect3DDevice9 *device = mRenderer->getDevice();
 
@@ -486,212 +576,200 @@ void Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y,
 
     if (FAILED(result))
     {
-        ERR("Could not create matching destination surface.");
         SafeRelease(surface);
-        return gl::error(GL_OUT_OF_MEMORY);
+        return gl::Error(GL_OUT_OF_MEMORY, "Could not create matching destination surface, result: 0x%X.", result);
     }
 
     result = device->GetRenderTargetData(surface, renderTargetData);
 
     if (FAILED(result))
     {
-        ERR("GetRenderTargetData unexpectedly failed.");
         SafeRelease(renderTargetData);
         SafeRelease(surface);
-        return gl::error(GL_OUT_OF_MEMORY);
+        return gl::Error(GL_OUT_OF_MEMORY, "GetRenderTargetData unexpectedly failed, result: 0x%X.", result);
     }
 
-    RECT sourceRect = {x, y, x + width, y + height};
-    RECT destRect = {xoffset, yoffset, xoffset + width, yoffset + height};
+    int width = sourceArea.width;
+    int height = sourceArea.height;
+
+    RECT sourceRect = { sourceArea.x, sourceArea.y, sourceArea.x + width, sourceArea.y + height };
+    RECT destRect = { xoffset, yoffset, xoffset + width, yoffset + height };
 
     D3DLOCKED_RECT sourceLock = {0};
     result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0);
 
     if (FAILED(result))
     {
-        ERR("Failed to lock the source surface (rectangle might be invalid).");
         SafeRelease(renderTargetData);
         SafeRelease(surface);
-        return gl::error(GL_OUT_OF_MEMORY);
+        return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock the source surface (rectangle might be invalid), result: 0x%X.", result);
     }
 
     D3DLOCKED_RECT destLock = {0};
-    result = lock(&destLock, &destRect);
-
-    if (FAILED(result))
+    gl::Error error = lock(&destLock, destRect);
+    if (error.isError())
     {
-        ERR("Failed to lock the destination surface (rectangle might be invalid).");
         renderTargetData->UnlockRect();
         SafeRelease(renderTargetData);
         SafeRelease(surface);
-        return gl::error(GL_OUT_OF_MEMORY);
+        return error;
     }
 
-    if (destLock.pBits && sourceLock.pBits)
-    {
-        unsigned char *source = (unsigned char*)sourceLock.pBits;
-        unsigned char *dest = (unsigned char*)destLock.pBits;
+    ASSERT(destLock.pBits && sourceLock.pBits);
 
-        switch (description.Format)
+    unsigned char *sourcePixels = (unsigned char*)sourceLock.pBits;
+    unsigned char *destPixels = (unsigned char*)destLock.pBits;
+
+    switch (description.Format)
+    {
+      case D3DFMT_X8R8G8B8:
+      case D3DFMT_A8R8G8B8:
+        switch (getD3DFormat())
         {
           case D3DFMT_X8R8G8B8:
           case D3DFMT_A8R8G8B8:
-            switch(getD3DFormat())
+            for (int y = 0; y < height; y++)
             {
-              case D3DFMT_X8R8G8B8:
-              case D3DFMT_A8R8G8B8:
-                for(int y = 0; y < height; y++)
+                memcpy(destPixels, sourcePixels, 4 * width);
+                sourcePixels += sourceLock.Pitch;
+                destPixels += destLock.Pitch;
+            }
+            break;
+          case D3DFMT_L8:
+            for (int y = 0; y < height; y++)
+            {
+                for (int x = 0; x < width; x++)
                 {
-                    memcpy(dest, source, 4 * width);
-
-                    source += sourceLock.Pitch;
-                    dest += destLock.Pitch;
+                    destPixels[x] = sourcePixels[x * 4 + 2];
                 }
-                break;
-              case D3DFMT_L8:
-                for(int y = 0; y < height; y++)
-                {
-                    for(int x = 0; x < width; x++)
-                    {
-                        dest[x] = source[x * 4 + 2];
-                    }
-
-                    source += sourceLock.Pitch;
-                    dest += destLock.Pitch;
-                }
-                break;
-              case D3DFMT_A8L8:
-                for(int y = 0; y < height; y++)
+                sourcePixels += sourceLock.Pitch;
+                destPixels += destLock.Pitch;
+            }
+            break;
+          case D3DFMT_A8L8:
+            for (int y = 0; y < height; y++)
+            {
+                for (int x = 0; x < width; x++)
                 {
-                    for(int x = 0; x < width; x++)
-                    {
-                        dest[x * 2 + 0] = source[x * 4 + 2];
-                        dest[x * 2 + 1] = source[x * 4 + 3];
-                    }
-
-                    source += sourceLock.Pitch;
-                    dest += destLock.Pitch;
+                    destPixels[x * 2 + 0] = sourcePixels[x * 4 + 2];
+                    destPixels[x * 2 + 1] = sourcePixels[x * 4 + 3];
                 }
-                break;
-              default:
-                UNREACHABLE();
+                sourcePixels += sourceLock.Pitch;
+                destPixels += destLock.Pitch;
             }
             break;
-          case D3DFMT_R5G6B5:
-            switch(getD3DFormat())
+          default:
+            UNREACHABLE();
+        }
+        break;
+      case D3DFMT_R5G6B5:
+        switch (getD3DFormat())
+        {
+          case D3DFMT_X8R8G8B8:
+            for (int y = 0; y < height; y++)
             {
-              case D3DFMT_X8R8G8B8:
-                for(int y = 0; y < height; y++)
+                for (int x = 0; x < width; x++)
                 {
-                    for(int x = 0; x < width; x++)
-                    {
-                        unsigned short rgb = ((unsigned short*)source)[x];
-                        unsigned char red = (rgb & 0xF800) >> 8;
-                        unsigned char green = (rgb & 0x07E0) >> 3;
-                        unsigned char blue = (rgb & 0x001F) << 3;
-                        dest[x + 0] = blue | (blue >> 5);
-                        dest[x + 1] = green | (green >> 6);
-                        dest[x + 2] = red | (red >> 5);
-                        dest[x + 3] = 0xFF;
-                    }
-
-                    source += sourceLock.Pitch;
-                    dest += destLock.Pitch;
+                    unsigned short rgb = ((unsigned short*)sourcePixels)[x];
+                    unsigned char red = (rgb & 0xF800) >> 8;
+                    unsigned char green = (rgb & 0x07E0) >> 3;
+                    unsigned char blue = (rgb & 0x001F) << 3;
+                    destPixels[x + 0] = blue | (blue >> 5);
+                    destPixels[x + 1] = green | (green >> 6);
+                    destPixels[x + 2] = red | (red >> 5);
+                    destPixels[x + 3] = 0xFF;
                 }
-                break;
-              case D3DFMT_L8:
-                for(int y = 0; y < height; y++)
+                sourcePixels += sourceLock.Pitch;
+                destPixels += destLock.Pitch;
+            }
+            break;
+          case D3DFMT_L8:
+            for (int y = 0; y < height; y++)
+            {
+                for (int x = 0; x < width; x++)
                 {
-                    for(int x = 0; x < width; x++)
-                    {
-                        unsigned char red = source[x * 2 + 1] & 0xF8;
-                        dest[x] = red | (red >> 5);
-                    }
-
-                    source += sourceLock.Pitch;
-                    dest += destLock.Pitch;
+                    unsigned char red = sourcePixels[x * 2 + 1] & 0xF8;
+                    destPixels[x] = red | (red >> 5);
                 }
-                break;
-              default:
-                UNREACHABLE();
+                sourcePixels += sourceLock.Pitch;
+                destPixels += destLock.Pitch;
             }
             break;
-          case D3DFMT_A1R5G5B5:
-            switch(getD3DFormat())
+          default:
+            UNREACHABLE();
+        }
+        break;
+      case D3DFMT_A1R5G5B5:
+        switch (getD3DFormat())
+        {
+          case D3DFMT_X8R8G8B8:
+            for (int y = 0; y < height; y++)
             {
-              case D3DFMT_X8R8G8B8:
-                for(int y = 0; y < height; y++)
+                for (int x = 0; x < width; x++)
                 {
-                    for(int x = 0; x < width; x++)
-                    {
-                        unsigned short argb = ((unsigned short*)source)[x];
-                        unsigned char red = (argb & 0x7C00) >> 7;
-                        unsigned char green = (argb & 0x03E0) >> 2;
-                        unsigned char blue = (argb & 0x001F) << 3;
-                        dest[x + 0] = blue | (blue >> 5);
-                        dest[x + 1] = green | (green >> 5);
-                        dest[x + 2] = red | (red >> 5);
-                        dest[x + 3] = 0xFF;
-                    }
-
-                    source += sourceLock.Pitch;
-                    dest += destLock.Pitch;
+                    unsigned short argb = ((unsigned short*)sourcePixels)[x];
+                    unsigned char red = (argb & 0x7C00) >> 7;
+                    unsigned char green = (argb & 0x03E0) >> 2;
+                    unsigned char blue = (argb & 0x001F) << 3;
+                    destPixels[x + 0] = blue | (blue >> 5);
+                    destPixels[x + 1] = green | (green >> 5);
+                    destPixels[x + 2] = red | (red >> 5);
+                    destPixels[x + 3] = 0xFF;
                 }
-                break;
-              case D3DFMT_A8R8G8B8:
-                for(int y = 0; y < height; y++)
+                sourcePixels += sourceLock.Pitch;
+                destPixels += destLock.Pitch;
+            }
+            break;
+          case D3DFMT_A8R8G8B8:
+            for (int y = 0; y < height; y++)
+            {
+                for (int x = 0; x < width; x++)
                 {
-                    for(int x = 0; x < width; x++)
-                    {
-                        unsigned short argb = ((unsigned short*)source)[x];
-                        unsigned char red = (argb & 0x7C00) >> 7;
-                        unsigned char green = (argb & 0x03E0) >> 2;
-                        unsigned char blue = (argb & 0x001F) << 3;
-                        unsigned char alpha = (signed short)argb >> 15;
-                        dest[x + 0] = blue | (blue >> 5);
-                        dest[x + 1] = green | (green >> 5);
-                        dest[x + 2] = red | (red >> 5);
-                        dest[x + 3] = alpha;
-                    }
-
-                    source += sourceLock.Pitch;
-                    dest += destLock.Pitch;
+                    unsigned short argb = ((unsigned short*)sourcePixels)[x];
+                    unsigned char red = (argb & 0x7C00) >> 7;
+                    unsigned char green = (argb & 0x03E0) >> 2;
+                    unsigned char blue = (argb & 0x001F) << 3;
+                    unsigned char alpha = (signed short)argb >> 15;
+                    destPixels[x + 0] = blue | (blue >> 5);
+                    destPixels[x + 1] = green | (green >> 5);
+                    destPixels[x + 2] = red | (red >> 5);
+                    destPixels[x + 3] = alpha;
                 }
-                break;
-              case D3DFMT_L8:
-                for(int y = 0; y < height; y++)
+                sourcePixels += sourceLock.Pitch;
+                destPixels += destLock.Pitch;
+            }
+            break;
+          case D3DFMT_L8:
+            for (int y = 0; y < height; y++)
+            {
+                for (int x = 0; x < width; x++)
                 {
-                    for(int x = 0; x < width; x++)
-                    {
-                        unsigned char red = source[x * 2 + 1] & 0x7C;
-                        dest[x] = (red << 1) | (red >> 4);
-                    }
-
-                    source += sourceLock.Pitch;
-                    dest += destLock.Pitch;
+                    unsigned char red = sourcePixels[x * 2 + 1] & 0x7C;
+                    destPixels[x] = (red << 1) | (red >> 4);
                 }
-                break;
-              case D3DFMT_A8L8:
-                for(int y = 0; y < height; y++)
+                sourcePixels += sourceLock.Pitch;
+                destPixels += destLock.Pitch;
+            }
+            break;
+          case D3DFMT_A8L8:
+            for (int y = 0; y < height; y++)
+            {
+                for (int x = 0; x < width; x++)
                 {
-                    for(int x = 0; x < width; x++)
-                    {
-                        unsigned char red = source[x * 2 + 1] & 0x7C;
-                        dest[x * 2 + 0] = (red << 1) | (red >> 4);
-                        dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
-                    }
-
-                    source += sourceLock.Pitch;
-                    dest += destLock.Pitch;
+                    unsigned char red = sourcePixels[x * 2 + 1] & 0x7C;
+                    destPixels[x * 2 + 0] = (red << 1) | (red >> 4);
+                    destPixels[x * 2 + 1] = (signed char)sourcePixels[x * 2 + 1] >> 7;
                 }
-                break;
-              default:
-                UNREACHABLE();
+                sourcePixels += sourceLock.Pitch;
+                destPixels += destLock.Pitch;
             }
             break;
           default:
             UNREACHABLE();
         }
+        break;
+      default:
+        UNREACHABLE();
     }
 
     unlock();
@@ -701,6 +779,14 @@ void Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y,
     SafeRelease(surface);
 
     mDirty = true;
+    return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &area, const gl::ImageIndex &srcIndex, TextureStorage *srcStorage)
+{
+    // Currently unreachable, due to only being used in a D3D11-only workaround
+    UNIMPLEMENTED();
+    return gl::Error(GL_INVALID_OPERATION);
 }
 
 }