Refactor Texture::copy*Image methods to use gl::Error objects.

BUG=angle:520

Change-Id: I8b6bf5d50ee0d1f796eff52919ee65823fdee6cb
Reviewed-on: https://chromium-review.googlesource.com/216647
Reviewed-by: Shannon Woods <shannonwoods@chromium.org>
Tested-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libGLESv2/renderer/d3d/ImageD3D.h b/src/libGLESv2/renderer/d3d/ImageD3D.h
index 7885db6..e77faef 100644
--- a/src/libGLESv2/renderer/d3d/ImageD3D.h
+++ b/src/libGLESv2/renderer/d3d/ImageD3D.h
@@ -35,10 +35,10 @@
 
     virtual bool isDirty() const = 0;
 
-    virtual void setManagedSurface2D(TextureStorage *storage, int level) {};
-    virtual void setManagedSurfaceCube(TextureStorage *storage, int face, int level) {};
-    virtual void setManagedSurface3D(TextureStorage *storage, int level) {};
-    virtual void setManagedSurface2DArray(TextureStorage *storage, int layer, int level) {};
+    virtual gl::Error setManagedSurface2D(TextureStorage *storage, int level) { return gl::Error(GL_NO_ERROR); };
+    virtual gl::Error setManagedSurfaceCube(TextureStorage *storage, int face, int level) { return gl::Error(GL_NO_ERROR); };
+    virtual gl::Error setManagedSurface3D(TextureStorage *storage, int level) { return gl::Error(GL_NO_ERROR); };
+    virtual gl::Error setManagedSurface2DArray(TextureStorage *storage, int layer, int level) { return gl::Error(GL_NO_ERROR); };
     virtual gl::Error copyToStorage2D(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region) = 0;
     virtual gl::Error copyToStorageCube(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region) = 0;
     virtual gl::Error copyToStorage3D(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region) = 0;
diff --git a/src/libGLESv2/renderer/d3d/TextureD3D.cpp b/src/libGLESv2/renderer/d3d/TextureD3D.cpp
index a4ca35e..d359164 100644
--- a/src/libGLESv2/renderer/d3d/TextureD3D.cpp
+++ b/src/libGLESv2/renderer/d3d/TextureD3D.cpp
@@ -378,28 +378,43 @@
     return false;
 }
 
-bool TextureD3D::ensureRenderTarget()
+gl::Error TextureD3D::ensureRenderTarget()
 {
-    initializeStorage(true);
+    gl::Error error = initializeStorage(true);
+    if (error.isError())
+    {
+        return error;
+    }
 
     if (!isBaseImageZeroSize())
     {
         ASSERT(mTexStorage);
         if (!mTexStorage->isRenderTarget())
         {
-            TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
-
-            if (mTexStorage->copyToStorage(newRenderTargetStorage).isError())
+            TextureStorage *newRenderTargetStorage = NULL;
+            error = createCompleteStorage(true, &newRenderTargetStorage);
+            if (error.isError())
             {
-                delete newRenderTargetStorage;
-                return gl::error(GL_OUT_OF_MEMORY, false);
+                return error;
             }
 
-            setCompleteTexStorage(newRenderTargetStorage);
+            error = mTexStorage->copyToStorage(newRenderTargetStorage);
+            if (error.isError())
+            {
+                SafeDelete(newRenderTargetStorage);
+                return error;
+            }
+
+            error = setCompleteTexStorage(newRenderTargetStorage);
+            if (error.isError())
+            {
+                SafeDelete(newRenderTargetStorage);
+                return error;
+            }
         }
     }
 
-    return (mTexStorage && mTexStorage->isRenderTarget());
+    return gl::Error(GL_NO_ERROR);
 }
 
 TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
@@ -597,7 +612,8 @@
     return commitRegion(index, region);
 }
 
-void TextureD3D_2D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
+gl::Error TextureD3D_2D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height,
+                                   gl::Framebuffer *source)
 {
     ASSERT(target == GL_TEXTURE_2D);
 
@@ -608,22 +624,39 @@
 
     if (!mImageArray[level]->isRenderableFormat())
     {
-        mImageArray[level]->copy(0, 0, 0, sourceRect, source);
+        gl::Error error = mImageArray[level]->copy(0, 0, 0, sourceRect, source);
+        if (error.isError())
+        {
+            return error;
+        }
+
         mDirtyImages = true;
     }
     else
     {
-        ensureRenderTarget();
+        gl::Error error = ensureRenderTarget();
+        if (error.isError())
+        {
+            return error;
+        }
+
         mImageArray[level]->markClean();
 
         if (width != 0 && height != 0 && isValidLevel(level))
         {
-            mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
+            gl::Error error = mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
+            if (error.isError())
+            {
+                return error;
+            }
         }
     }
+
+    return gl::Error(GL_NO_ERROR);
 }
 
-void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
+gl::Error TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
+                                      GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
 {
     ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
 
@@ -635,22 +668,41 @@
 
     if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
     {
-        mImageArray[level]->copy(xoffset, yoffset, 0, sourceRect, source);
+        gl::Error error = mImageArray[level]->copy(xoffset, yoffset, 0, sourceRect, source);
+        if (error.isError())
+        {
+            return error;
+        }
+
         mDirtyImages = true;
     }
     else
     {
-        ensureRenderTarget();
+        gl::Error error = ensureRenderTarget();
+        if (error.isError())
+        {
+            return error;
+        }
 
         if (isValidLevel(level))
         {
-            updateStorageLevel(level);
+            error = updateStorageLevel(level);
+            if (error.isError())
+            {
+                return error;
+            }
 
-            mRenderer->copyImage2D(source, sourceRect,
-                                   gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
-                                   xoffset, yoffset, mTexStorage, level);
+            error = mRenderer->copyImage2D(source, sourceRect,
+                                           gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
+                                           xoffset, yoffset, mTexStorage, level);
+            if (error.isError())
+            {
+                return error;
+            }
         }
     }
+
+    return gl::Error(GL_NO_ERROR);
 }
 
 void TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
@@ -720,7 +772,7 @@
 unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
 {
     ASSERT(!index.hasLayer());
-    return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
+    return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
 }
 
 RenderTarget *TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index)
@@ -728,12 +780,18 @@
     ASSERT(!index.hasLayer());
 
     // ensure the underlying texture is created
-    if (!ensureRenderTarget())
+    gl::Error error = ensureRenderTarget();
+    if (error.isError())
     {
         return NULL;
     }
 
-    updateStorageLevel(index.mipIndex);
+    error = updateStorageLevel(index.mipIndex);
+    if (error.isError())
+    {
+        return NULL;
+    }
+
     return mTexStorage->getRenderTarget(index);
 }
 
@@ -787,30 +845,49 @@
 }
 
 // Constructs a native texture resource from the texture images
-void TextureD3D_2D::initializeStorage(bool renderTarget)
+gl::Error TextureD3D_2D::initializeStorage(bool renderTarget)
 {
     // Only initialize the first time this texture is used as a render target or shader resource
     if (mTexStorage)
     {
-        return;
+        return gl::Error(GL_NO_ERROR);
     }
 
     // do not attempt to create storage for nonexistant data
     if (!isLevelComplete(0))
     {
-        return;
+        return gl::Error(GL_NO_ERROR);
     }
 
     bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
 
-    setCompleteTexStorage(createCompleteStorage(createRenderTarget));
+    TextureStorage *storage = NULL;
+    gl::Error error = createCompleteStorage(createRenderTarget, &storage);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    error = setCompleteTexStorage(storage);
+    if (error.isError())
+    {
+        SafeDelete(storage);
+        return error;
+    }
+
     ASSERT(mTexStorage);
 
     // flush image data to the storage
-    updateStorage();
+    error = updateStorage();
+    if (error.isError())
+    {
+        return error;
+    }
+
+    return gl::Error(GL_NO_ERROR);
 }
 
-TextureStorage *TextureD3D_2D::createCompleteStorage(bool renderTarget) const
+gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
 {
     GLsizei width = getBaseLevelWidth();
     GLsizei height = getBaseLevelHeight();
@@ -821,26 +898,35 @@
     // use existing storage level count, when previously specified by TexStorage*D
     GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
 
-    return mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
+    // TODO(geofflang): Determine if the texture creation succeeded
+    *outTexStorage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
+
+    return gl::Error(GL_NO_ERROR);
 }
 
-void TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
+gl::Error TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
 {
-    SafeDelete(mTexStorage);
-    mTexStorage = newCompleteTexStorage;
-
-    if (mTexStorage && mTexStorage->isManaged())
+    if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
     {
-        for (int level = 0; level < mTexStorage->getLevelCount(); level++)
+        for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
         {
-            mImageArray[level]->setManagedSurface2D(mTexStorage, level);
+            gl::Error error = mImageArray[level]->setManagedSurface2D(newCompleteTexStorage, level);
+            if (error.isError())
+            {
+                return error;
+            }
         }
     }
 
+    SafeDelete(mTexStorage);
+    mTexStorage = newCompleteTexStorage;
+
     mDirtyImages = true;
+
+    return gl::Error(GL_NO_ERROR);
 }
 
-void TextureD3D_2D::updateStorage()
+gl::Error TextureD3D_2D::updateStorage()
 {
     ASSERT(mTexStorage != NULL);
     GLint storageLevels = mTexStorage->getLevelCount();
@@ -848,12 +934,18 @@
     {
         if (mImageArray[level]->isDirty() && isLevelComplete(level))
         {
-            updateStorageLevel(level);
+            gl::Error error = updateStorageLevel(level);
+            if (error.isError())
+            {
+                return error;
+            }
         }
     }
+
+    return gl::Error(GL_NO_ERROR);
 }
 
-void TextureD3D_2D::updateStorageLevel(int level)
+gl::Error TextureD3D_2D::updateStorageLevel(int level)
 {
     ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
     ASSERT(isLevelComplete(level));
@@ -862,8 +954,14 @@
     {
         gl::ImageIndex index = gl::ImageIndex::Make2D(level);
         gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
-        commitRegion(index, region);
+        gl::Error error = commitRegion(index, region);
+        if (error.isError())
+        {
+            return error;
+        }
     }
+
+    return gl::Error(GL_NO_ERROR);
 }
 
 void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
@@ -1042,7 +1140,8 @@
     return commitRegion(index, region);
 }
 
-void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
+gl::Error TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
+                                     GLsizei width, GLsizei height, gl::Framebuffer *source)
 {
     int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
     GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
@@ -1053,24 +1152,41 @@
 
     if (!mImageArray[faceIndex][level]->isRenderableFormat())
     {
-        mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
+        gl::Error error = mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
+        if (error.isError())
+        {
+            return error;
+        }
+
         mDirtyImages = true;
     }
     else
     {
-        ensureRenderTarget();
+        gl::Error error = ensureRenderTarget();
+        if (error.isError())
+        {
+            return error;
+        }
+
         mImageArray[faceIndex][level]->markClean();
 
         ASSERT(width == height);
 
         if (width > 0 && isValidFaceLevel(faceIndex, level))
         {
-            mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
+            error = mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
+            if (error.isError())
+            {
+                return error;
+            }
         }
     }
+
+    return gl::Error(GL_NO_ERROR);
 }
 
-void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
+gl::Error TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
+                                        GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
 {
     int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
 
@@ -1083,21 +1199,40 @@
 
     if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
     {
-        mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
+        gl::Error error =mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
+        if (error.isError())
+        {
+            return error;
+        }
+
         mDirtyImages = true;
     }
     else
     {
-        ensureRenderTarget();
+        gl::Error error = ensureRenderTarget();
+        if (error.isError())
+        {
+            return error;
+        }
 
         if (isValidFaceLevel(faceIndex, level))
         {
-            updateStorageFaceLevel(faceIndex, level);
+            error = updateStorageFaceLevel(faceIndex, level);
+            if (error.isError())
+            {
+                return error;
+            }
 
-            mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
-                                     xoffset, yoffset, mTexStorage, target, level);
+            error = mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
+                                             xoffset, yoffset, mTexStorage, target, level);
+            if (error.isError())
+            {
+                return error;
+            }
         }
     }
+
+    return gl::Error(GL_NO_ERROR);
 }
 
 void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
@@ -1183,7 +1318,7 @@
 
 unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
 {
-    return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
+    return (ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
 }
 
 RenderTarget *TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index)
@@ -1191,39 +1326,64 @@
     ASSERT(gl::IsCubemapTextureTarget(index.type));
 
     // ensure the underlying texture is created
-    if (!ensureRenderTarget())
+    gl::Error error = ensureRenderTarget();
+    if (error.isError())
     {
         return NULL;
     }
 
-    updateStorageFaceLevel(index.layerIndex, index.mipIndex);
+    error = updateStorageFaceLevel(index.layerIndex, index.mipIndex);
+    if (error.isError())
+    {
+        return NULL;
+    }
+
     return mTexStorage->getRenderTarget(index);
 }
 
-void TextureD3D_Cube::initializeStorage(bool renderTarget)
+gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget)
 {
     // Only initialize the first time this texture is used as a render target or shader resource
     if (mTexStorage)
     {
-        return;
+        return gl::Error(GL_NO_ERROR);
     }
 
     // do not attempt to create storage for nonexistant data
     if (!isFaceLevelComplete(0, 0))
     {
-        return;
+        return gl::Error(GL_NO_ERROR);
     }
 
     bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
 
-    setCompleteTexStorage(createCompleteStorage(createRenderTarget));
+    TextureStorage *storage = NULL;
+    gl::Error error = createCompleteStorage(createRenderTarget, &storage);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    error = setCompleteTexStorage(storage);
+    if (error.isError())
+    {
+        SafeDelete(storage);
+        return error;
+    }
+
     ASSERT(mTexStorage);
 
     // flush image data to the storage
-    updateStorage();
+    error = updateStorage();
+    if (error.isError())
+    {
+        return error;
+    }
+
+    return gl::Error(GL_NO_ERROR);
 }
 
-TextureStorage *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const
+gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
 {
     GLsizei size = getBaseLevelWidth();
 
@@ -1232,29 +1392,37 @@
     // use existing storage level count, when previously specified by TexStorage*D
     GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
 
-    return mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
+    // TODO (geofflang): detect if storage creation succeeded
+    *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
+
+    return gl::Error(GL_NO_ERROR);
 }
 
-void TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
+gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
 {
-    SafeDelete(mTexStorage);
-    mTexStorage = newCompleteTexStorage;
-
-    if (mTexStorage && mTexStorage->isManaged())
+    if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
     {
         for (int faceIndex = 0; faceIndex < 6; faceIndex++)
         {
-            for (int level = 0; level < mTexStorage->getLevelCount(); level++)
+            for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
             {
-                mImageArray[faceIndex][level]->setManagedSurfaceCube(mTexStorage, faceIndex, level);
+                gl::Error error = mImageArray[faceIndex][level]->setManagedSurfaceCube(newCompleteTexStorage, faceIndex, level);
+                if (error.isError())
+                {
+                    return error;
+                }
             }
         }
     }
 
+    SafeDelete(mTexStorage);
+    mTexStorage = newCompleteTexStorage;
+
     mDirtyImages = true;
+    return gl::Error(GL_NO_ERROR);
 }
 
-void TextureD3D_Cube::updateStorage()
+gl::Error TextureD3D_Cube::updateStorage()
 {
     ASSERT(mTexStorage != NULL);
     GLint storageLevels = mTexStorage->getLevelCount();
@@ -1264,10 +1432,16 @@
         {
             if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
             {
-                updateStorageFaceLevel(face, level);
+                gl::Error error = updateStorageFaceLevel(face, level);
+                if (error.isError())
+                {
+                    return error;
+                }
             }
         }
     }
+
+    return gl::Error(GL_NO_ERROR);
 }
 
 bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
@@ -1315,7 +1489,7 @@
     return true;
 }
 
-void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
+gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
 {
     ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
     ImageD3D *image = mImageArray[faceIndex][level];
@@ -1325,8 +1499,14 @@
         GLenum faceTarget = gl::TextureCubeMap::layerIndexToTarget(faceIndex);
         gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level);
         gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
-        commitRegion(index, region);
+        gl::Error error = commitRegion(index, region);
+        if (error.isError())
+        {
+            return error;
+        }
     }
+
+    return gl::Error(GL_NO_ERROR);
 }
 
 void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
@@ -1592,12 +1772,15 @@
     return commitRegion(index, region);
 }
 
-void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
+gl::Error TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
+                                   GLsizei width, GLsizei height, gl::Framebuffer *source)
 {
     UNIMPLEMENTED();
+    return gl::Error(GL_INVALID_OPERATION, "Copying 3D textures is unimplemented.");
 }
 
-void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
+gl::Error TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
+                                      GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
 {
     ASSERT(target == GL_TEXTURE_3D);
 
@@ -1609,22 +1792,41 @@
 
     if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
     {
-        mImageArray[level]->copy(xoffset, yoffset, zoffset, sourceRect, source);
+        gl::Error error = mImageArray[level]->copy(xoffset, yoffset, zoffset, sourceRect, source);
+        if (error.isError())
+        {
+            return error;
+        }
+
         mDirtyImages = true;
     }
     else
     {
-        ensureRenderTarget();
+        gl::Error error = ensureRenderTarget();
+        if (error.isError())
+        {
+            return error;
+        }
 
         if (isValidLevel(level))
         {
-            updateStorageLevel(level);
+            error = updateStorageLevel(level);
+            if (error.isError())
+            {
+                return error;
+            }
 
-            mRenderer->copyImage3D(source, sourceRect,
-                                   gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
-                                   xoffset, yoffset, zoffset, mTexStorage, level);
+            error = mRenderer->copyImage3D(source, sourceRect,
+                                           gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
+                                           xoffset, yoffset, zoffset, mTexStorage, level);
+            if (error.isError())
+            {
+                return error;
+            }
         }
     }
+
+    return gl::Error(GL_NO_ERROR);
 }
 
 void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
@@ -1677,53 +1879,81 @@
 
 unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
 {
-    return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
+    return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
 }
 
 RenderTarget *TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index)
 {
     // ensure the underlying texture is created
-    if (!ensureRenderTarget())
+    gl::Error error = ensureRenderTarget();
+    if (error.isError())
     {
         return NULL;
     }
 
     if (index.hasLayer())
     {
-        updateStorage();
+        error = updateStorage();
+        if (error.isError())
+        {
+            return NULL;
+        }
     }
     else
     {
-        updateStorageLevel(index.mipIndex);
+        error = updateStorageLevel(index.mipIndex);
+        if (error.isError())
+        {
+            return NULL;
+        }
     }
 
     return mTexStorage->getRenderTarget(index);
 }
 
-void TextureD3D_3D::initializeStorage(bool renderTarget)
+gl::Error TextureD3D_3D::initializeStorage(bool renderTarget)
 {
     // Only initialize the first time this texture is used as a render target or shader resource
     if (mTexStorage)
     {
-        return;
+        return gl::Error(GL_NO_ERROR);
     }
 
     // do not attempt to create storage for nonexistant data
     if (!isLevelComplete(0))
     {
-        return;
+        return gl::Error(GL_NO_ERROR);
     }
 
     bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
 
-    setCompleteTexStorage(createCompleteStorage(createRenderTarget));
+    rx::TextureStorage *storage = NULL;
+    gl::Error error = createCompleteStorage(createRenderTarget, &storage);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    error = setCompleteTexStorage(storage);
+    if (error.isError())
+    {
+        SafeDelete(storage);
+        return error;
+    }
+
     ASSERT(mTexStorage);
 
     // flush image data to the storage
-    updateStorage();
+    error = updateStorage();
+    if (error.isError())
+    {
+        return error;
+    }
+
+    return gl::Error(GL_NO_ERROR);
 }
 
-TextureStorage *TextureD3D_3D::createCompleteStorage(bool renderTarget) const
+gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
 {
     GLsizei width = getBaseLevelWidth();
     GLsizei height = getBaseLevelHeight();
@@ -1735,10 +1965,13 @@
     // use existing storage level count, when previously specified by TexStorage*D
     GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
 
-    return mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
+    // TODO: Verify creation of the storage succeeded
+    *outStorage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
+
+    return gl::Error(GL_NO_ERROR);
 }
 
-void TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
+gl::Error TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
 {
     SafeDelete(mTexStorage);
     mTexStorage = newCompleteTexStorage;
@@ -1746,9 +1979,11 @@
 
     // We do not support managed 3D storage, as that is D3D9/ES2-only
     ASSERT(!mTexStorage->isManaged());
+
+    return gl::Error(GL_NO_ERROR);
 }
 
-void TextureD3D_3D::updateStorage()
+gl::Error TextureD3D_3D::updateStorage()
 {
     ASSERT(mTexStorage != NULL);
     GLint storageLevels = mTexStorage->getLevelCount();
@@ -1756,9 +1991,15 @@
     {
         if (mImageArray[level]->isDirty() && isLevelComplete(level))
         {
-            updateStorageLevel(level);
+            gl::Error error = updateStorageLevel(level);
+            if (error.isError())
+            {
+                return error;
+            }
         }
     }
+
+    return gl::Error(GL_NO_ERROR);
 }
 
 bool TextureD3D_3D::isValidLevel(int level) const
@@ -1814,7 +2055,7 @@
     return true;
 }
 
-void TextureD3D_3D::updateStorageLevel(int level)
+gl::Error TextureD3D_3D::updateStorageLevel(int level)
 {
     ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
     ASSERT(isLevelComplete(level));
@@ -1823,8 +2064,14 @@
     {
         gl::ImageIndex index = gl::ImageIndex::Make3D(level);
         gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
-        commitRegion(index, region);
+        gl::Error error = commitRegion(index, region);
+        if (error.isError())
+        {
+            return error;
+        }
     }
+
+    return gl::Error(GL_NO_ERROR);
 }
 
 void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
@@ -2060,12 +2307,13 @@
     return gl::Error(GL_NO_ERROR);
 }
 
-void TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
+gl::Error TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
 {
     UNIMPLEMENTED();
+    return gl::Error(GL_INVALID_OPERATION, "Copying 2D array textures is unimplemented.");
 }
 
-void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
+gl::Error TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
 {
     ASSERT(target == GL_TEXTURE_2D_ARRAY);
 
@@ -2077,21 +2325,39 @@
 
     if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
     {
-        mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, sourceRect, source);
+        gl::Error error = mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, sourceRect, source);
+        if (error.isError())
+        {
+            return error;
+        }
+
         mDirtyImages = true;
     }
     else
     {
-        ensureRenderTarget();
+        gl::Error error = ensureRenderTarget();
+        if (error.isError())
+        {
+            return error;
+        }
 
         if (isValidLevel(level))
         {
-            updateStorageLevel(level);
+            error = updateStorageLevel(level);
+            if (error.isError())
+            {
+                return error;
+            }
 
-            mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
-                                        xoffset, yoffset, zoffset, mTexStorage, level);
+            error = mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
+                                                xoffset, yoffset, zoffset, mTexStorage, level);
+            if (error.isError())
+            {
+                return error;
+            }
         }
     }
+    return gl::Error(GL_NO_ERROR);
 }
 
 void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
@@ -2156,45 +2422,70 @@
 
 unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
 {
-    return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
+    return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
 }
 
 RenderTarget *TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index)
 {
     // ensure the underlying texture is created
-    if (!ensureRenderTarget())
+    gl::Error error = ensureRenderTarget();
+    if (error.isError())
     {
         return NULL;
     }
 
-    updateStorageLevel(index.mipIndex);
+    error = updateStorageLevel(index.mipIndex);
+    if (error.isError())
+    {
+        return NULL;
+    }
+
     return mTexStorage->getRenderTarget(index);
 }
 
-void TextureD3D_2DArray::initializeStorage(bool renderTarget)
+gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget)
 {
     // Only initialize the first time this texture is used as a render target or shader resource
     if (mTexStorage)
     {
-        return;
+        return gl::Error(GL_NO_ERROR);
     }
 
     // do not attempt to create storage for nonexistant data
     if (!isLevelComplete(0))
     {
-        return;
+        return gl::Error(GL_NO_ERROR);
     }
 
     bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
 
-    setCompleteTexStorage(createCompleteStorage(createRenderTarget));
+    TextureStorage *storage = NULL;
+    gl::Error error = createCompleteStorage(createRenderTarget, &storage);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    error = setCompleteTexStorage(storage);
+    if (error.isError())
+    {
+        SafeDelete(storage);
+        return error;
+    }
+
     ASSERT(mTexStorage);
 
     // flush image data to the storage
-    updateStorage();
+    error = updateStorage();
+    if (error.isError())
+    {
+        return error;
+    }
+
+    return gl::Error(GL_NO_ERROR);
 }
 
-TextureStorage *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const
+gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
 {
     GLsizei width = getBaseLevelWidth();
     GLsizei height = getBaseLevelHeight();
@@ -2206,10 +2497,13 @@
     // use existing storage level count, when previously specified by TexStorage*D
     GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
 
-    return mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
+    // TODO(geofflang): Verify storage creation succeeds
+    *outStorage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
+
+    return gl::Error(GL_NO_ERROR);
 }
 
-void TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
+gl::Error TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
 {
     SafeDelete(mTexStorage);
     mTexStorage = newCompleteTexStorage;
@@ -2217,9 +2511,11 @@
 
     // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
     ASSERT(!mTexStorage->isManaged());
+
+    return gl::Error(GL_NO_ERROR);
 }
 
-void TextureD3D_2DArray::updateStorage()
+gl::Error TextureD3D_2DArray::updateStorage()
 {
     ASSERT(mTexStorage != NULL);
     GLint storageLevels = mTexStorage->getLevelCount();
@@ -2227,9 +2523,15 @@
     {
         if (isLevelComplete(level))
         {
-            updateStorageLevel(level);
+            gl::Error error = updateStorageLevel(level);
+            if (error.isError())
+            {
+                return error;
+            }
         }
     }
+
+    return gl::Error(GL_NO_ERROR);
 }
 
 bool TextureD3D_2DArray::isValidLevel(int level) const
@@ -2283,7 +2585,7 @@
     return true;
 }
 
-void TextureD3D_2DArray::updateStorageLevel(int level)
+gl::Error TextureD3D_2DArray::updateStorageLevel(int level)
 {
     ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
     ASSERT(isLevelComplete(level));
@@ -2295,9 +2597,15 @@
         {
             gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
             gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
-            commitRegion(index, region);
+            gl::Error error = commitRegion(index, region);
+            if (error.isError())
+            {
+                return error;
+            }
         }
     }
+
+    return gl::Error(GL_NO_ERROR);
 }
 
 void TextureD3D_2DArray::deleteImages()
diff --git a/src/libGLESv2/renderer/d3d/TextureD3D.h b/src/libGLESv2/renderer/d3d/TextureD3D.h
index 0327edb..bc08be6 100644
--- a/src/libGLESv2/renderer/d3d/TextureD3D.h
+++ b/src/libGLESv2/renderer/d3d/TextureD3D.h
@@ -78,10 +78,10 @@
     virtual void initMipmapsImages() = 0;
     bool isBaseImageZeroSize() const;
 
-    virtual bool ensureRenderTarget();
+    virtual gl::Error ensureRenderTarget();
 
-    virtual TextureStorage *createCompleteStorage(bool renderTarget) const = 0;
-    virtual void setCompleteTexStorage(TextureStorage *newCompleteTexStorage) = 0;
+    virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const = 0;
+    virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage) = 0;
     virtual gl::Error commitRegion(const gl::ImageIndex &index, const gl::Box &region) = 0;
 
     Renderer *mRenderer;
@@ -96,9 +96,9 @@
   private:
     DISALLOW_COPY_AND_ASSIGN(TextureD3D);
 
-    virtual void initializeStorage(bool renderTarget) = 0;
+    virtual gl::Error initializeStorage(bool renderTarget) = 0;
 
-    virtual void updateStorage() = 0;
+    virtual gl::Error updateStorage() = 0;
 };
 
 class TextureD3D_2D : public TextureD3D
@@ -121,8 +121,8 @@
     virtual gl::Error setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels);
     virtual gl::Error subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels);
     virtual gl::Error subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels);
-    virtual void copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source);
-    virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source);
+    virtual gl::Error copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source);
+    virtual gl::Error copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source);
     virtual void storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
 
     virtual void bindTexImage(egl::Surface *surface);
@@ -137,18 +137,18 @@
   private:
     DISALLOW_COPY_AND_ASSIGN(TextureD3D_2D);
 
-    virtual void initializeStorage(bool renderTarget);
-    virtual TextureStorage *createCompleteStorage(bool renderTarget) const;
-    virtual void setCompleteTexStorage(TextureStorage *newCompleteTexStorage);
+    virtual gl::Error initializeStorage(bool renderTarget);
+    gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const;
+    gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage);
     gl::Error commitRegion(const gl::ImageIndex &index, const gl::Box &region);
 
-    virtual void updateStorage();
+    virtual gl::Error updateStorage();
     virtual void initMipmapsImages();
 
     bool isValidLevel(int level) const;
     bool isLevelComplete(int level) const;
 
-    void updateStorageLevel(int level);
+    gl::Error updateStorageLevel(int level);
 
     void redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height);
 
@@ -176,8 +176,8 @@
     virtual gl::Error setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels);
     virtual gl::Error subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels);
     virtual gl::Error subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels);
-    virtual void copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source);
-    virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source);
+    virtual gl::Error copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source);
+    virtual gl::Error copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source);
     virtual void storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
 
     virtual void bindTexImage(egl::Surface *surface);
@@ -192,18 +192,18 @@
   private:
     DISALLOW_COPY_AND_ASSIGN(TextureD3D_Cube);
 
-    virtual void initializeStorage(bool renderTarget);
-    virtual TextureStorage *createCompleteStorage(bool renderTarget) const;
-    virtual void setCompleteTexStorage(TextureStorage *newCompleteTexStorage);
+    virtual gl::Error initializeStorage(bool renderTarget);
+    gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const;
+    gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage);
     virtual gl::Error commitRegion(const gl::ImageIndex &index, const gl::Box &region);
 
-    virtual void updateStorage();
+    virtual gl::Error updateStorage();
     virtual void initMipmapsImages();
 
     bool isValidFaceLevel(int faceIndex, int level) const;
     bool isFaceLevelComplete(int faceIndex, int level) const;
     bool isCubeComplete() const;
-    void updateStorageFaceLevel(int faceIndex, int level);
+    gl::Error updateStorageFaceLevel(int faceIndex, int level);
 
     void redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height);
 
@@ -230,8 +230,8 @@
     virtual gl::Error setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels);
     virtual gl::Error subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels);
     virtual gl::Error subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels);
-    virtual void copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source);
-    virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source);
+    virtual gl::Error copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source);
+    virtual gl::Error copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source);
     virtual void storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
 
     virtual void bindTexImage(egl::Surface *surface);
@@ -246,17 +246,17 @@
   private:
     DISALLOW_COPY_AND_ASSIGN(TextureD3D_3D);
 
-    virtual void initializeStorage(bool renderTarget);
-    virtual TextureStorage *createCompleteStorage(bool renderTarget) const;
-    virtual void setCompleteTexStorage(TextureStorage *newCompleteTexStorage);
+    virtual gl::Error initializeStorage(bool renderTarget);
+    gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const;
+    gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage);
     virtual gl::Error commitRegion(const gl::ImageIndex &index, const gl::Box &region);
 
-    virtual void updateStorage();
+    virtual gl::Error updateStorage();
     virtual void initMipmapsImages();
 
     bool isValidLevel(int level) const;
     bool isLevelComplete(int level) const;
-    void updateStorageLevel(int level);
+    gl::Error updateStorageLevel(int level);
 
     void redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
 
@@ -282,8 +282,8 @@
     virtual gl::Error setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels);
     virtual gl::Error subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels);
     virtual gl::Error subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels);
-    virtual void copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source);
-    virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source);
+    virtual gl::Error copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source);
+    virtual gl::Error copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source);
     virtual void storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
 
     virtual void bindTexImage(egl::Surface *surface);
@@ -298,17 +298,17 @@
   private:
     DISALLOW_COPY_AND_ASSIGN(TextureD3D_2DArray);
 
-    virtual void initializeStorage(bool renderTarget);
-    virtual TextureStorage *createCompleteStorage(bool renderTarget) const;
-    virtual void setCompleteTexStorage(TextureStorage *newCompleteTexStorage);
+    virtual gl::Error initializeStorage(bool renderTarget);
+    gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const;
+    gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage);
     virtual gl::Error commitRegion(const gl::ImageIndex &index, const gl::Box &region);
 
-    virtual void updateStorage();
+    virtual gl::Error updateStorage();
     virtual void initMipmapsImages();
 
     bool isValidLevel(int level) const;
     bool isLevelComplete(int level) const;
-    void updateStorageLevel(int level);
+    gl::Error updateStorageLevel(int level);
 
     void deleteImages();
     void redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
diff --git a/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp b/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp
index 5faaae0..aa2cb5c 100644
--- a/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp
+++ b/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp
@@ -321,7 +321,7 @@
     return gl::Error(GL_NO_ERROR);
 }
 
-void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source)
+gl::Error Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source)
 {
     RenderTarget11 *sourceRenderTarget = RenderTarget11::makeRenderTarget11(source);
     ASSERT(sourceRenderTarget->getTexture());
@@ -331,16 +331,17 @@
 
     if (!sourceTexture2D)
     {
-        // Error already generated
-        return;
+        return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the ID3D11Texture2D from the source RenderTarget.");
     }
 
-    copy(xoffset, yoffset, zoffset, sourceArea, sourceTexture2D, subresourceIndex);
+    gl::Error error = copy(xoffset, yoffset, zoffset, sourceArea, sourceTexture2D, subresourceIndex);
 
     SafeRelease(sourceTexture2D);
+
+    return error;
 }
 
-void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, const gl::ImageIndex &sourceIndex, TextureStorage *source)
+gl::Error Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, const gl::ImageIndex &sourceIndex, TextureStorage *source)
 {
     TextureStorage11 *sourceStorage11 = TextureStorage11::makeTextureStorage11(source);
 
@@ -349,16 +350,17 @@
 
     if (!sourceTexture2D)
     {
-        // Error already generated
-        return;
+        return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the ID3D11Texture2D from the source TextureStorage.");
     }
 
-    copy(xoffset, yoffset, zoffset, sourceArea, sourceTexture2D, subresourceIndex);
+    gl::Error error = copy(xoffset, yoffset, zoffset, sourceArea, sourceTexture2D, subresourceIndex);
 
     SafeRelease(sourceTexture2D);
+
+    return error;
 }
 
-void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, ID3D11Texture2D *source, UINT sourceSubResource)
+gl::Error Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, ID3D11Texture2D *source, UINT sourceSubResource)
 {
     D3D11_TEXTURE2D_DESC textureDesc;
     source->GetDesc(&textureDesc);
@@ -390,8 +392,7 @@
             HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex);
             if (FAILED(result))
             {
-                ERR("Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result);
-                return;
+                return gl::Error(GL_OUT_OF_MEMORY, "Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result);
             }
 
             deviceContext->ResolveSubresource(srcTex, 0, source, sourceSubResource, textureDesc.Format);
@@ -424,8 +425,7 @@
         HRESULT result = map(D3D11_MAP_WRITE, &mappedImage);
         if (FAILED(result))
         {
-            ERR("Failed to map texture for Image11::copy, HRESULT: 0x%X.", result);
-            return;
+            return gl::Error(GL_OUT_OF_MEMORY, "Failed to map texture for Image11::copy, HRESULT: 0x%X.", result);
         }
 
         // determine the offset coordinate into the destination buffer
@@ -434,12 +434,19 @@
 
         const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat);
 
-        mRenderer->readTextureData(source, sourceSubResource, sourceArea, formatInfo.format, formatInfo.type, mappedImage.RowPitch, gl::PixelPackState(), dataOffset);
+        gl::Error error = mRenderer->readTextureData(source, sourceSubResource, sourceArea, formatInfo.format, formatInfo.type, mappedImage.RowPitch, gl::PixelPackState(), dataOffset);
 
         unmap();
+
+        if (error.isError())
+        {
+            return error;
+        }
     }
 
     mDirty = true;
+
+    return gl::Error(GL_NO_ERROR);
 }
 
 ID3D11Resource *Image11::getStagingTexture()
diff --git a/src/libGLESv2/renderer/d3d/d3d11/Image11.h b/src/libGLESv2/renderer/d3d/d3d11/Image11.h
index 59b00f3..ee437c8 100644
--- a/src/libGLESv2/renderer/d3d/d3d11/Image11.h
+++ b/src/libGLESv2/renderer/d3d/d3d11/Image11.h
@@ -52,9 +52,9 @@
     virtual gl::Error loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
                                          const void *input);
 
-    virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source);
-    virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea,
-                      const gl::ImageIndex &sourceIndex, TextureStorage *source);
+    virtual gl::Error copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source);
+    virtual gl::Error copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea,
+                           const gl::ImageIndex &sourceIndex, TextureStorage *source);
 
     bool recoverFromAssociatedStorage();
     bool isAssociatedStorageValid(TextureStorage11* textureStorage) const;
@@ -68,7 +68,7 @@
     DISALLOW_COPY_AND_ASSIGN(Image11);
 
     gl::Error copyToStorageImpl(TextureStorage11 *storage11, const gl::ImageIndex &index, const gl::Box &region);
-    void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, ID3D11Texture2D *source, UINT sourceSubResource);
+    gl::Error copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, ID3D11Texture2D *source, UINT sourceSubResource);
 
     ID3D11Resource *getStagingTexture();
     unsigned int getStagingSubresource();
diff --git a/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp b/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp
index fc5dacb..19cc378 100644
--- a/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp
+++ b/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp
@@ -92,35 +92,47 @@
     dest->markDirty();
 }
 
-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;
 
-    if (sourceLock.pBits && destLock.pBits)
+    result = source->LockRect(&sourceLock, NULL, 0);
+    if (FAILED(result))
     {
-        D3DSURFACE_DESC desc;
-        source->GetDesc(&desc);
-
-        const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format);
-        unsigned int rows = desc.Height / d3dFormatInfo.blockHeight;
-
-        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);
-        }
-
-        source->UnlockRect();
-        dest->UnlockRect();
+        return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock source surface for copy, result: 0x%X.", result);
     }
-    else UNREACHABLE();
+
+    result = dest->LockRect(&destLock, NULL, 0);
+    if (FAILED(result))
+    {
+        source->UnlockRect();
+        return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock source surface for copy, result: 0x%X.", result);
+    }
+
+    ASSERT(sourceLock.pBits && destLock.pBits);
+
+    D3DSURFACE_DESC desc;
+    source->GetDesc(&desc);
+
+    const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format);
+    unsigned int rows = desc.Height / d3dFormatInfo.blockHeight;
+
+    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);
+    }
+
+    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)
@@ -270,19 +282,19 @@
     return mSurface;
 }
 
-void Image9::setManagedSurface2D(TextureStorage *storage, int level)
+gl::Error Image9::setManagedSurface2D(TextureStorage *storage, int level)
 {
     TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage);
-    setManagedSurface(storage9->getSurfaceLevel(level, false));
+    return setManagedSurface(storage9->getSurfaceLevel(level, false));
 }
 
-void Image9::setManagedSurfaceCube(TextureStorage *storage, int face, int level)
+gl::Error Image9::setManagedSurfaceCube(TextureStorage *storage, int face, int level)
 {
     TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage);
-    setManagedSurface(storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false));
+    return setManagedSurface(storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false));
 }
 
-void Image9::setManagedSurface(IDirect3DSurface9 *surface)
+gl::Error Image9::setManagedSurface(IDirect3DSurface9 *surface)
 {
     D3DSURFACE_DESC desc;
     surface->GetDesc(&desc);
@@ -292,13 +304,19 @@
     {
         if (mSurface)
         {
-            copyLockableSurfaces(surface, mSurface);
+            gl::Error error = copyLockableSurfaces(surface, mSurface);
             SafeRelease(mSurface);
+            if (error.isError())
+            {
+                return error;
+            }
         }
 
         mSurface = surface;
         mD3DPool = desc.Pool;
     }
+
+    return gl::Error(GL_NO_ERROR);
 }
 
 gl::Error Image9::copyToStorage2D(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region)
@@ -466,7 +484,7 @@
 }
 
 // This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
-void Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source)
+gl::Error Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source)
 {
     ASSERT(source);
 
@@ -483,8 +501,7 @@
 
     if (!surface)
     {
-        ERR("Failed to retrieve the render target.");
-        return gl::error(GL_OUT_OF_MEMORY);
+        return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the internal render target.");
     }
 
     IDirect3DDevice9 *device = mRenderer->getDevice();
@@ -497,19 +514,17 @@
 
     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);
     }
 
     int width = sourceArea.width;
@@ -523,10 +538,9 @@
 
     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};
@@ -534,178 +548,167 @@
 
     if (FAILED(result))
     {
-        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 gl::Error(GL_OUT_OF_MEMORY, "Failed to lock the destination surface (rectangle might be invalid), result: 0x%X.", result);
     }
 
-    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(dest, source, 4 * width);
-
-                    source += sourceLock.Pitch;
-                    dest += destLock.Pitch;
-                }
-                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++)
-                {
-                    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;
-                }
-                break;
-              default:
-                UNREACHABLE();
+                memcpy(destPixels, sourcePixels, 4 * width);
+                sourcePixels += sourceLock.Pitch;
+                destPixels += destLock.Pitch;
             }
             break;
-          case D3DFMT_R5G6B5:
-            switch(getD3DFormat())
+          case D3DFMT_L8:
+            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;
+                    destPixels[x] = sourcePixels[x * 4 + 2];
                 }
-                break;
-              case D3DFMT_L8:
-                for (int y = 0; y < height; y++)
-                {
-                    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;
-                }
-                break;
-              default:
-                UNREACHABLE();
+                sourcePixels += sourceLock.Pitch;
+                destPixels += destLock.Pitch;
             }
             break;
-          case D3DFMT_A1R5G5B5:
-            switch (getD3DFormat())
+          case D3DFMT_A8L8:
+            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;
+                    destPixels[x * 2 + 0] = sourcePixels[x * 4 + 2];
+                    destPixels[x * 2 + 1] = sourcePixels[x * 4 + 3];
                 }
-                break;
-              case D3DFMT_A8R8G8B8:
-                for (int y = 0; y < height; y++)
-                {
-                    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;
-                }
-                break;
-              case D3DFMT_L8:
-                for (int y = 0; y < height; y++)
-                {
-                    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;
-                }
-                break;
-              case D3DFMT_A8L8:
-                for (int y = 0; y < height; y++)
-                {
-                    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;
-                }
-                break;
-              default:
-                UNREACHABLE();
+                sourcePixels += sourceLock.Pitch;
+                destPixels += destLock.Pitch;
             }
             break;
           default:
             UNREACHABLE();
         }
+        break;
+      case D3DFMT_R5G6B5:
+        switch (getD3DFormat())
+        {
+          case D3DFMT_X8R8G8B8:
+            for (int y = 0; y < height; y++)
+            {
+                for (int x = 0; x < width; x++)
+                {
+                    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;
+                }
+                sourcePixels += sourceLock.Pitch;
+                destPixels += destLock.Pitch;
+            }
+            break;
+          case D3DFMT_L8:
+            for (int y = 0; y < height; y++)
+            {
+                for (int x = 0; x < width; x++)
+                {
+                    unsigned char red = sourcePixels[x * 2 + 1] & 0xF8;
+                    destPixels[x] = red | (red >> 5);
+                }
+                sourcePixels += sourceLock.Pitch;
+                destPixels += destLock.Pitch;
+            }
+            break;
+          default:
+            UNREACHABLE();
+        }
+        break;
+      case D3DFMT_A1R5G5B5:
+        switch (getD3DFormat())
+        {
+          case D3DFMT_X8R8G8B8:
+            for (int y = 0; y < height; y++)
+            {
+                for (int x = 0; x < width; x++)
+                {
+                    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;
+                }
+                sourcePixels += sourceLock.Pitch;
+                destPixels += destLock.Pitch;
+            }
+            break;
+          case D3DFMT_A8R8G8B8:
+            for (int y = 0; y < height; y++)
+            {
+                for (int x = 0; x < width; x++)
+                {
+                    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;
+                }
+                sourcePixels += sourceLock.Pitch;
+                destPixels += destLock.Pitch;
+            }
+            break;
+          case D3DFMT_L8:
+            for (int y = 0; y < height; y++)
+            {
+                for (int x = 0; x < width; x++)
+                {
+                    unsigned char red = sourcePixels[x * 2 + 1] & 0x7C;
+                    destPixels[x] = (red << 1) | (red >> 4);
+                }
+                sourcePixels += sourceLock.Pitch;
+                destPixels += destLock.Pitch;
+            }
+            break;
+          case D3DFMT_A8L8:
+            for (int y = 0; y < height; y++)
+            {
+                for (int x = 0; x < width; x++)
+                {
+                    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;
+                }
+                sourcePixels += sourceLock.Pitch;
+                destPixels += destLock.Pitch;
+            }
+            break;
+          default:
+            UNREACHABLE();
+        }
+        break;
+      default:
+        UNREACHABLE();
     }
 
     unlock();
@@ -715,12 +718,14 @@
     SafeRelease(surface);
 
     mDirty = true;
+    return gl::Error(GL_NO_ERROR);
 }
 
-void Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &area, const gl::ImageIndex &srcIndex, TextureStorage *srcStorage)
+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);
 }
 
 }
diff --git a/src/libGLESv2/renderer/d3d/d3d9/Image9.h b/src/libGLESv2/renderer/d3d/d3d9/Image9.h
index e8b40b5..f4ee1c4 100644
--- a/src/libGLESv2/renderer/d3d/d3d9/Image9.h
+++ b/src/libGLESv2/renderer/d3d/d3d9/Image9.h
@@ -33,7 +33,7 @@
 
     static void generateMipmap(Image9 *dest, Image9 *source);
     static void generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface);
-    static void copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source);
+    static gl::Error copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source);
 
     virtual bool redefine(Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease);
 
@@ -42,8 +42,8 @@
     virtual bool isDirty() const;
     IDirect3DSurface9 *getSurface();
 
-    virtual void setManagedSurface2D(TextureStorage *storage, int level);
-    virtual void setManagedSurfaceCube(TextureStorage *storage, int face, int level);
+    virtual gl::Error setManagedSurface2D(TextureStorage *storage, int level);
+    virtual gl::Error setManagedSurfaceCube(TextureStorage *storage, int face, int level);
     virtual gl::Error copyToStorage2D(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region);
     virtual gl::Error copyToStorageCube(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region);
     virtual gl::Error copyToStorage3D(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region);
@@ -54,15 +54,15 @@
     virtual gl::Error loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
                                          const void *input);
 
-    virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source);
-    virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea,
-                      const gl::ImageIndex &sourceIndex, TextureStorage *source);
+    virtual gl::Error copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source);
+    virtual gl::Error copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea,
+                           const gl::ImageIndex &sourceIndex, TextureStorage *source);
 
   private:
     DISALLOW_COPY_AND_ASSIGN(Image9);
 
     void createSurface();
-    void setManagedSurface(IDirect3DSurface9 *surface);
+    gl::Error setManagedSurface(IDirect3DSurface9 *surface);
     gl::Error copyToSurface(IDirect3DSurface9 *dest, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
 
     HRESULT lock(D3DLOCKED_RECT *lockedRect, const RECT *rect);