Vulkan: Remove initImmutableImage and use initImage instead

This is follow up of crrev.com/c/2368038. There was concern that
initImmutableImage and initImage are a bit duplicated. This CL gets rid
of initImmutableImage and uses initImage instead.

Bug: b/181800403
Change-Id: I2c73c7ce979792cc762214f1e5ef9978eeab6212
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2800422
Commit-Queue: Charlie Lao <cclao@google.com>
Reviewed-by: Ian Elliott <ianelliott@google.com>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
diff --git a/src/libANGLE/renderer/vulkan/TextureVk.cpp b/src/libANGLE/renderer/vulkan/TextureVk.cpp
index ffa150f..937005d 100644
--- a/src/libANGLE/renderer/vulkan/TextureVk.cpp
+++ b/src/libANGLE/renderer/vulkan/TextureVk.cpp
@@ -1294,7 +1294,15 @@
 
     ASSERT(mState.getImmutableFormat());
     ASSERT(!mRedefinedLevels.any());
-    ANGLE_TRY(initImmutableImage(contextVk, format));
+
+    // For immutable texture, we always allocate the full immutable levels specified by texStorage
+    // call.
+    const gl::ImageDesc &Level0Desc  = mState.getLevelZeroDesc();
+    const gl::Extents &Level0Extents = Level0Desc.size;
+    const uint32_t levelCount        = mState.getImmutableLevels();
+
+    ANGLE_TRY(
+        initImage(contextVk, format, Level0Desc.format.info->sized, Level0Extents, 0, levelCount));
 
     return angle::Result::Continue;
 }
@@ -2053,18 +2061,25 @@
         // Create the image helper
         ANGLE_TRY(ensureImageAllocated(contextVk, format));
 
-        // Create the image
+        // Create the image. For immutable texture, we always allocate the full immutable levels
+        // specified by texStorage call. Otherwise we only try to allocate from base to max levels.
         if (mState.getImmutableFormat())
         {
-            ANGLE_TRY(initImmutableImage(contextVk, format));
+            const gl::ImageDesc &Level0Desc  = mState.getLevelZeroDesc();
+            const gl::Extents &Level0Extents = Level0Desc.size;
+            const uint32_t levelCount        = mState.getImmutableLevels();
+
+            ANGLE_TRY(initImage(contextVk, format, Level0Desc.format.info->sized, Level0Extents, 0,
+                                levelCount));
         }
         else
         {
             const gl::ImageDesc &baseLevelDesc  = mState.getBaseLevelDesc();
             const gl::Extents &baseLevelExtents = baseLevelDesc.size;
             const uint32_t levelCount           = getMipLevelCount(ImageMipLevels::EnabledLevels);
+
             ANGLE_TRY(initImage(contextVk, format, baseLevelDesc.format.info->sized,
-                                baseLevelExtents, levelCount));
+                                baseLevelExtents, mState.getEffectiveBaseLevel(), levelCount));
         }
 
         // Set the newly created mImage as the destination for the staging operation
@@ -2134,13 +2149,16 @@
 
     if (!mImage->valid())
     {
+        // Immutable texture must already have a valid image
+        ASSERT(!mState.getImmutableFormat());
+
         const gl::ImageDesc &baseLevelDesc  = mState.getBaseLevelDesc();
         const gl::Extents &baseLevelExtents = baseLevelDesc.size;
         const uint32_t levelCount           = getMipLevelCount(ImageMipLevels::EnabledLevels);
         const vk::Format &format            = getBaseLevelFormat(contextVk->getRenderer());
 
         ANGLE_TRY(initImage(contextVk, format, baseLevelDesc.format.info->sized, baseLevelExtents,
-                            levelCount));
+                            mState.getEffectiveBaseLevel(), levelCount));
     }
 
     const bool hasRenderToTextureEXT =
@@ -2199,9 +2217,17 @@
         ASSERT(!mRedefinedLevels.any());
 
         const vk::Format &format = getBaseLevelFormat(contextVk->getRenderer());
+
+        // For immutable texture, we always allocate the full immutable levels specified by
+        // texStorage call. Otherwise we only try to allocate from base to max levels.
         if (mState.getImmutableFormat())
         {
-            ANGLE_TRY(initImmutableImage(contextVk, format));
+            const gl::ImageDesc &Level0Desc  = mState.getLevelZeroDesc();
+            const gl::Extents &Level0Extents = Level0Desc.size;
+            const uint32_t levelCount        = mState.getImmutableLevels();
+
+            ANGLE_TRY(initImage(contextVk, format, Level0Desc.format.info->sized, Level0Extents, 0,
+                                levelCount));
         }
         else
         {
@@ -2210,7 +2236,7 @@
             const uint32_t levelCount           = getMipLevelCount(mipLevels);
 
             ANGLE_TRY(initImage(contextVk, format, baseLevelDesc.format.info->sized,
-                                baseLevelExtents, levelCount));
+                                baseLevelExtents, mState.getEffectiveBaseLevel(), levelCount));
         }
 
         if (mipLevels == ImageMipLevels::FullMipChain)
@@ -2453,7 +2479,8 @@
     // usage flags), make sure it's recreated.
     if (isGenerateMipmap && mImage->valid() &&
         (oldUsageFlags != mImageUsageFlags ||
-         mImage->getLevelCount() != getMipLevelCount(ImageMipLevels::FullMipChain)))
+         (!mState.getImmutableFormat() &&
+          mImage->getLevelCount() != getMipLevelCount(ImageMipLevels::FullMipChain))))
     {
         ASSERT(mOwnsImage);
         // Immutable texture is not expected to reach here. The usage flag change should have
@@ -2713,21 +2740,22 @@
 angle::Result TextureVk::initImage(ContextVk *contextVk,
                                    const vk::Format &format,
                                    const bool sized,
-                                   const gl::Extents &extents,
+                                   const gl::Extents &firstLevelExtents,
+                                   const uint32_t firstLevel,
                                    const uint32_t levelCount)
 {
     RendererVk *renderer = contextVk->getRenderer();
 
     VkExtent3D vkExtent;
     uint32_t layerCount;
-    gl_vk::GetExtentsAndLayerCount(mState.getType(), extents, &vkExtent, &layerCount);
+    gl_vk::GetExtentsAndLayerCount(mState.getType(), firstLevelExtents, &vkExtent, &layerCount);
     GLint samples = mState.getBaseLevelDesc().samples ? mState.getBaseLevelDesc().samples : 1;
 
     bool imageFormatListEnabled = false;
     ANGLE_TRY(mImage->initExternal(
         contextVk, mState.getType(), vkExtent, format, samples, mImageUsageFlags, mImageCreateFlags,
-        vk::ImageLayout::Undefined, nullptr, gl::LevelIndex(mState.getEffectiveBaseLevel()),
-        levelCount, layerCount, contextVk->isRobustResourceInitEnabled(), &imageFormatListEnabled));
+        vk::ImageLayout::Undefined, nullptr, gl::LevelIndex(firstLevel), levelCount, layerCount,
+        contextVk->isRobustResourceInitEnabled(), &imageFormatListEnabled));
 
     mRequiresMutableStorage = (mImageCreateFlags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) != 0;
 
@@ -2735,40 +2763,9 @@
 
     ANGLE_TRY(mImage->initMemory(contextVk, renderer->getMemoryProperties(), flags));
 
-    ANGLE_TRY(initImageViews(contextVk, format, sized, levelCount, layerCount));
-
-    return angle::Result::Continue;
-}
-
-angle::Result TextureVk::initImmutableImage(ContextVk *contextVk, const vk::Format &format)
-{
-    ASSERT(mState.getImmutableFormat());
-
-    // For immutable texture, we always create a underlying image object with levels [0,
-    // immutableLevels-1] regardless of base level and max level. base/max level information are
-    // used to create ImageViewHelper object.
-    VkExtent3D vkExtentLevel0;
-    uint32_t layerCount;
-    const gl::ImageDesc &Level0Desc  = mState.getLevelZeroDesc();
-    const gl::Extents &Level0Extents = Level0Desc.size;
-    gl_vk::GetExtentsAndLayerCount(mState.getType(), Level0Extents, &vkExtentLevel0, &layerCount);
-    GLint samples = mState.getBaseLevelDesc().samples ? mState.getBaseLevelDesc().samples : 1;
-
-    bool imageFormatListEnabled = false;
-    ANGLE_TRY(mImage->initExternal(contextVk, mState.getType(), vkExtentLevel0, format, samples,
-                                   mImageUsageFlags, mImageCreateFlags, vk::ImageLayout::Undefined,
-                                   nullptr, gl::LevelIndex(0), mState.getImmutableLevels(),
-                                   layerCount, contextVk->isRobustResourceInitEnabled(),
-                                   &imageFormatListEnabled));
-
-    mRequiresMutableStorage = (mImageCreateFlags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) != 0;
-
-    RendererVk *renderer              = contextVk->getRenderer();
-    const VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
-    ANGLE_TRY(mImage->initMemory(contextVk, renderer->getMemoryProperties(), flags));
-
-    ANGLE_TRY(initImageViews(contextVk, format, Level0Desc.format.info->sized,
-                             getMipLevelCount(ImageMipLevels::EnabledLevels), layerCount));
+    const uint32_t viewLevelCount =
+        mState.getImmutableFormat() ? getMipLevelCount(ImageMipLevels::EnabledLevels) : levelCount;
+    ANGLE_TRY(initImageViews(contextVk, format, sized, viewLevelCount, layerCount));
 
     return angle::Result::Continue;
 }
@@ -2857,14 +2854,13 @@
 {
     switch (mipLevels)
     {
+        // Returns level count from base to max that has been specified, i.e, enabled.
         case ImageMipLevels::EnabledLevels:
             return mState.getEnabledLevelCount();
+        // Returns all mipmap levels from base to max regardless if an image has been specified or
+        // not.
         case ImageMipLevels::FullMipChain:
-            // For immutable textures, it is the same during life time of the texture regardless of
-            // base/max level setting.
-            return mState.getImmutableFormat()
-                       ? mState.getImmutableLevels()
-                       : getMaxLevelCount() - mState.getEffectiveBaseLevel();
+            return getMaxLevelCount() - mState.getEffectiveBaseLevel();
 
         default:
             UNREACHABLE();
@@ -2874,11 +2870,8 @@
 
 uint32_t TextureVk::getMaxLevelCount() const
 {
-    // For immutable textures, it is always the same during life time of the texture. For mutable
-    // texture, getMipmapMaxLevel will be 0 here if mipmaps are not used, so the levelCount is
-    // always +1.
-    return mState.getImmutableFormat() ? mState.getImmutableLevels()
-                                       : mState.getMipmapMaxLevel() + 1;
+    // getMipmapMaxLevel will be 0 here if mipmaps are not used, so the levelCount is always +1.
+    return mState.getMipmapMaxLevel() + 1;
 }
 
 angle::Result TextureVk::generateMipmapLevelsWithCPU(ContextVk *contextVk,
diff --git a/src/libANGLE/renderer/vulkan/TextureVk.h b/src/libANGLE/renderer/vulkan/TextureVk.h
index 52232f2..92cb4e4 100644
--- a/src/libANGLE/renderer/vulkan/TextureVk.h
+++ b/src/libANGLE/renderer/vulkan/TextureVk.h
@@ -410,9 +410,9 @@
     angle::Result initImage(ContextVk *contextVk,
                             const vk::Format &format,
                             const bool sized,
-                            const gl::Extents &extents,
+                            const gl::Extents &firstLevelExtents,
+                            const uint32_t firstLevel,
                             const uint32_t levelCount);
-    angle::Result initImmutableImage(ContextVk *contextVk, const vk::Format &format);
     void releaseImage(ContextVk *contextVk);
     void releaseStagingBuffer(ContextVk *contextVk);
     uint32_t getMipLevelCount(ImageMipLevels mipLevels) const;