Improve D3D11 FL9_3 zero-LOD workaround (e.g. TextureCubes)

D3D11 Feature Level 9_3 can't disable mipmaps on a mipmapped
texture, and sample from level zero of it. A previous commit
added a workaround for this in ANGLE to Texture2Ds. This
commit fixes some minor issues in that commit, and extends
the workaround to apply to TextureCubes too.

Change-Id: Ic97321af6f8bbf7ad5d96e58655c342db3978a6a
Reviewed-on: https://chromium-review.googlesource.com/241944
Tested-by: Austin Kinross <aukinros@microsoft.com>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/renderer/d3d/TextureD3D.cpp b/src/libANGLE/renderer/d3d/TextureD3D.cpp
index 2173462..7b7c822 100644
--- a/src/libANGLE/renderer/d3d/TextureD3D.cpp
+++ b/src/libANGLE/renderer/d3d/TextureD3D.cpp
@@ -352,9 +352,6 @@
         return gl::Error(GL_NO_ERROR); // no-op
     }
 
-    // Set up proper mipmap chain in our Image array.
-    initMipmapsImages();
-
     if (mTexStorage && mRenderer->getWorkarounds().zeroMaxLodWorkaround)
     {
         // Switch to using the mipmapped texture.
@@ -365,6 +362,9 @@
         }
     }
 
+    // Set up proper mipmap chain in our Image array.
+    initMipmapsImages();
+
     // We know that all layers have the same dimension, for the texture to be complete
     GLint layerCount = static_cast<GLint>(getLayerCount(0));
 
@@ -728,7 +728,9 @@
     gl::ImageIndex index = gl::ImageIndex::Make2D(level);
     gl::Offset destOffset(0, 0, 0);
 
-    if (!canCreateRenderTargetForImage(index))
+    // If the zero max LOD workaround is active, then we can't sample from individual layers of the framebuffer in shaders,
+    // so we should use the non-rendering copy path.
+    if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround)
     {
         gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source);
         if (error.isError())
@@ -771,7 +773,9 @@
 
     gl::ImageIndex index = gl::ImageIndex::Make2D(level);
 
-    if (!canCreateRenderTargetForImage(index))
+    // If the zero max LOD workaround is active, then we can't sample from individual layers of the framebuffer in shaders,
+    // so we should use the non-rendering copy path.
+    if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround)
     {
         gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source);
         if (error.isError())
@@ -1030,11 +1034,9 @@
         // If any of the CPU images (levels >= 1) are dirty, then the textureStorage2D should use the mipped texture to begin with.
         // Otherwise, it should use the level-zero-only texture.
         hintLevelZeroOnly = true;
-        int level = 1;
-        while (hintLevelZeroOnly && level < levels)
+        for (int level = 1; level < levels && hintLevelZeroOnly; level++)
         {
             hintLevelZeroOnly = !(mImageArray[level]->isDirty() && isLevelComplete(level));
-            level += 1;
         }
     }
 
@@ -1381,7 +1383,8 @@
 
     // TODO(geofflang): Verify storage creation had no errors
     bool renderTarget = IsRenderTargetUsage(mUsage);
-    TextureStorage *storage = mRenderer->createTextureStorageCube(internalFormat, renderTarget, size.width, levels);
+
+    TextureStorage *storage = mRenderer->createTextureStorageCube(internalFormat, renderTarget, size.width, levels, false);
 
     gl::Error error = setCompleteTexStorage(storage);
     if (error.isError())
@@ -1524,8 +1527,23 @@
     // use existing storage level count, when previously specified by TexStorage*D
     GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
 
+    bool hintLevelZeroOnly = false;
+    if (mRenderer->getWorkarounds().zeroMaxLodWorkaround)
+    {
+        // If any of the CPU images (levels >= 1) are dirty, then the textureStorage should use the mipped texture to begin with.
+        // Otherwise, it should use the level-zero-only texture.
+        hintLevelZeroOnly = true;
+        for (int faceIndex = 0; faceIndex < 6 && hintLevelZeroOnly; faceIndex++)
+        {
+            for (int level = 1; level < levels && hintLevelZeroOnly; level++)
+            {
+                hintLevelZeroOnly = !(mImageArray[faceIndex][level]->isDirty() && isFaceLevelComplete(faceIndex, level));
+            }
+        }
+    }
+
     // TODO (geofflang): detect if storage creation succeeded
-    *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
+    *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels, hintLevelZeroOnly);
 
     return gl::Error(GL_NO_ERROR);
 }