Refactor storage management in Texture3D.

TRAC #23976

Signed-off-by: Geoff Lang
Signed-off-by: Shannon Woods
diff --git a/src/libGLESv2/Texture.cpp b/src/libGLESv2/Texture.cpp
index 558410c..3a4e503 100644
--- a/src/libGLESv2/Texture.cpp
+++ b/src/libGLESv2/Texture.cpp
@@ -1798,16 +1798,12 @@
 
 void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
 {
-    delete mTexStorage;
-    mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, IsRenderTargetUsage(mUsage), width, height, depth);
-    mImmutable = true;
-
     for (int level = 0; level < levels; level++)
     {
-        mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, true);
-        width = std::max(1, width >> 1);
-        height = std::max(1, height >> 1);
-        depth = std::max(1, depth >> 1);
+        GLsizei levelWidth = std::max(1, width >> level);
+        GLsizei levelHeight = std::max(1, height >> level);
+        GLsizei levelDepth = std::max(1, depth >> level);
+        mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
     }
 
     for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
@@ -1815,18 +1811,11 @@
         mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
     }
 
-    if (mTexStorage->isManaged())
-    {
-        int levels = levelCount();
+    mImmutable = true;
 
-        for (int level = 0; level < levels; level++)
-        {
-            mImageArray[level]->setManagedSurface(mTexStorage, level);
-        }
-    }
+    setCompleteTexStorage(new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, IsRenderTargetUsage(mUsage), width, height, depth));
 }
 
-
 void Texture3D::generateMipmaps()
 {
     // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
@@ -2016,29 +2005,49 @@
 
 void Texture3D::initializeStorage(bool renderTarget)
 {
+    // Only initialize the first time this texture is used as a render target or shader resource
+    if (mTexStorage)
+    {
+        return;
+    }
+
+    // do not attempt to create storage for nonexistant data
+    if (!isLevelComplete(0))
+    {
+        return;
+    }
+
+    bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
+
+    setCompleteTexStorage(createCompleteStorage(createRenderTarget));
+    ASSERT(mTexStorage);
+
+    // flush image data to the storage
+    updateStorage();
+}
+
+rx::TextureStorageInterface3D *Texture3D::createCompleteStorage(bool renderTarget) const
+{
     GLsizei width = getBaseLevelWidth();
     GLsizei height = getBaseLevelHeight();
     GLsizei depth = getBaseLevelDepth();
 
-    if (!(width > 0 && height > 0 && depth > 0))
-        return; // do not attempt to create native textures for nonexistant data
+    ASSERT(width > 0 && height > 0 && depth > 0);
 
-    GLint levels = creationLevels(width, height, depth);
+    // use existing storage level count, when previously specified by TexStorage*D
+    GLint levels = (mTexStorage ? mTexStorage->levelCount() : creationLevels(width, height, depth));
 
-    delete mTexStorage;
-    mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, getBaseLevelInternalFormat(), IsRenderTargetUsage(mUsage), width, height, depth);
+    return new rx::TextureStorageInterface3D(mRenderer, levels, getBaseLevelInternalFormat(), renderTarget, width, height, depth);
+}
 
-    if (mTexStorage->isManaged())
-    {
-        int levels = levelCount();
-
-        for (int level = 0; level < levels; level++)
-        {
-            mImageArray[level]->setManagedSurface(mTexStorage, level);
-        }
-    }
-
+void Texture3D::setCompleteTexStorage(rx::TextureStorageInterface3D *newCompleteTexStorage)
+{
+    SafeDelete(mTexStorage);
+    mTexStorage = newCompleteTexStorage;
     mDirtyImages = true;
+
+    // We do not support managed 3D storage, as that is D3D9/ES2-only
+    ASSERT(!mTexStorage->isManaged());
 }
 
 void Texture3D::updateStorage()
@@ -2067,36 +2076,25 @@
 
 bool Texture3D::ensureRenderTarget()
 {
-    if (mTexStorage && mTexStorage->isRenderTarget())
+    initializeStorage(true);
+
+    if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
     {
-        return true;
-    }
-
-    rx::TextureStorageInterface3D *newTexStorage = NULL;
-
-    if (getBaseLevelWidth() != 0 && getBaseLevelHeight() != 0 && getBaseLevelDepth() != 0)
-    {
-        GLsizei width = getBaseLevelWidth();
-        GLsizei height = getBaseLevelHeight();
-        GLsizei depth = getBaseLevelDepth();
-        GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height, depth);
-
-        newTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, getBaseLevelInternalFormat(), true, width, height, depth);
-
-        if (mTexStorage != NULL)
+        ASSERT(mTexStorage);
+        if (!mTexStorage->isRenderTarget())
         {
-            if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
+            rx::TextureStorageInterface3D *newRenderTargetStorage = createCompleteStorage(true);
+
+            if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
             {
-                delete newTexStorage;
+                delete newRenderTargetStorage;
                 return gl::error(GL_OUT_OF_MEMORY, false);
             }
+
+            setCompleteTexStorage(newRenderTargetStorage);
         }
     }
 
-    delete mTexStorage;
-    mTexStorage = newTexStorage;
-
-    mDirtyImages = true;
     return (mTexStorage && mTexStorage->isRenderTarget());
 }
 
diff --git a/src/libGLESv2/Texture.h b/src/libGLESv2/Texture.h
index b5ff6bb..73fbd1e 100644
--- a/src/libGLESv2/Texture.h
+++ b/src/libGLESv2/Texture.h
@@ -329,6 +329,9 @@
     DISALLOW_COPY_AND_ASSIGN(Texture3D);
 
     virtual void initializeStorage(bool renderTarget);
+    rx::TextureStorageInterface3D *createCompleteStorage(bool renderTarget) const;
+    void setCompleteTexStorage(rx::TextureStorageInterface3D *newCompleteTexStorage);
+
     virtual void updateStorage();
     virtual bool ensureRenderTarget();