Texture: Add validation that the mip chain can't be too large

BUG=chromium:954769

Change-Id: I07a00230294cb9385b79edb6150d9f0f7b4b7284
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/6760
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
diff --git a/src/dawn_native/Texture.cpp b/src/dawn_native/Texture.cpp
index 22a62e7..633b943 100644
--- a/src/dawn_native/Texture.cpp
+++ b/src/dawn_native/Texture.cpp
@@ -15,6 +15,7 @@
 #include "dawn_native/Texture.h"
 
 #include "common/Assert.h"
+#include "common/Math.h"
 #include "dawn_native/Device.h"
 #include "dawn_native/ValidationUtils_autogen.h"
 
@@ -173,6 +174,11 @@
             return DAWN_VALIDATION_ERROR("Cannot create an empty texture");
         }
 
+        if (Log2(descriptor->size.width) + 1 < descriptor->mipLevelCount ||
+            Log2(descriptor->size.height) + 1 < descriptor->mipLevelCount) {
+            return DAWN_VALIDATION_ERROR("Texture has too many mip levels");
+        }
+
         return {};
     }
 
diff --git a/src/tests/unittests/validation/TextureValidationTests.cpp b/src/tests/unittests/validation/TextureValidationTests.cpp
index a88a7df..4d01182 100644
--- a/src/tests/unittests/validation/TextureValidationTests.cpp
+++ b/src/tests/unittests/validation/TextureValidationTests.cpp
@@ -95,6 +95,74 @@
     }
 }
 
+// Test the validation of the mip level count
+TEST_F(TextureValidationTest, MipLevelCount) {
+    dawn::TextureDescriptor defaultDescriptor = CreateDefaultTextureDescriptor();
+
+    // mipLevelCount == 1 is allowed
+    {
+        dawn::TextureDescriptor descriptor = defaultDescriptor;
+        descriptor.size.width = 32;
+        descriptor.size.height = 32;
+        descriptor.mipLevelCount = 1;
+
+        device.CreateTexture(&descriptor);
+    }
+
+    // mipLevelCount == 0 is an error
+    {
+        dawn::TextureDescriptor descriptor = defaultDescriptor;
+        descriptor.size.width = 32;
+        descriptor.size.height = 32;
+        descriptor.mipLevelCount = 0;
+
+        ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
+    }
+
+    // Full mip chains are allowed
+    {
+        dawn::TextureDescriptor descriptor = defaultDescriptor;
+        descriptor.size.width = 32;
+        descriptor.size.height = 32;
+        // Mip level sizes: 32, 16, 8, 4, 2, 1
+        descriptor.mipLevelCount = 6;
+
+        device.CreateTexture(&descriptor);
+    }
+
+    // Too big mip chains on width are disallowed
+    {
+        dawn::TextureDescriptor descriptor = defaultDescriptor;
+        descriptor.size.width = 31;
+        descriptor.size.height = 32;
+        // Mip level width: 31, 15, 7, 3, 1
+        descriptor.mipLevelCount = 6;
+
+        ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
+    }
+
+    // Too big mip chains on height are disallowed
+    {
+        dawn::TextureDescriptor descriptor = defaultDescriptor;
+        descriptor.size.width = 32;
+        descriptor.size.height = 31;
+        // Mip level height: 31, 15, 7, 3, 1
+        descriptor.mipLevelCount = 6;
+
+        ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
+    }
+
+    // Undefined shift check if miplevel is bigger than the integer bit width.
+    {
+        dawn::TextureDescriptor descriptor = defaultDescriptor;
+        descriptor.size.width = 32;
+        descriptor.size.height = 32;
+        descriptor.mipLevelCount = 100;
+
+        ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
+    }
+}
+
 // Test that it is valid to destroy a texture
 TEST_F(TextureValidationTest, DestroyTexture) {
     dawn::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
diff --git a/src/tests/unittests/validation/TextureViewValidationTests.cpp b/src/tests/unittests/validation/TextureViewValidationTests.cpp
index 707db08..b7ddfc5 100644
--- a/src/tests/unittests/validation/TextureViewValidationTests.cpp
+++ b/src/tests/unittests/validation/TextureViewValidationTests.cpp
@@ -183,7 +183,7 @@
 
     // It is an error to create a cube map texture view with width != height.
     {
-        dawn::Texture nonSquareTexture = Create2DArrayTexture(device, 18, 32, 16);
+        dawn::Texture nonSquareTexture = Create2DArrayTexture(device, 18, 32, 16, 5);
 
         dawn::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor;
         descriptor.dimension = dawn::TextureViewDimension::Cube;
@@ -193,7 +193,7 @@
 
     // It is an error to create a cube map array texture view with width != height.
     {
-        dawn::Texture nonSquareTexture = Create2DArrayTexture(device, 18, 32, 16);
+        dawn::Texture nonSquareTexture = Create2DArrayTexture(device, 18, 32, 16, 5);
 
         dawn::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor;
         descriptor.dimension = dawn::TextureViewDimension::CubeArray;