Support creating texture view with descriptor on OpenGL version >= 4.3

This patch implements creating texture view with texture view descriptor
with glTextureView, which is supported on OpenGL version >= 4.3. As is
required by glTextureView, we allocate storage for a texture by
glTexStorage*D instead of glTexImage*D.

BUG=dawn:16
TEST=dawn_end2end_tests

Change-Id: I29bcf6d538a70b4d6d1e5a21276b9e8d6e93ca51
Reviewed-on: https://dawn-review.googlesource.com/c/1980
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
diff --git a/src/dawn_native/opengl/CommandBufferGL.cpp b/src/dawn_native/opengl/CommandBufferGL.cpp
index 2f3737b..ec03c77 100644
--- a/src/dawn_native/opengl/CommandBufferGL.cpp
+++ b/src/dawn_native/opengl/CommandBufferGL.cpp
@@ -258,12 +258,11 @@
 
                     case dawn::BindingType::SampledTexture: {
                         TextureView* view = ToBackend(group->GetBindingAsTextureView(binding));
-                        Texture* texture = ToBackend(view->GetTexture());
-                        GLuint handle = texture->GetHandle();
-                        GLenum target = texture->GetGLTarget();
-                        GLuint textureIndex = indices[binding];
+                        GLuint handle = view->GetHandle();
+                        GLenum target = view->GetGLTarget();
+                        GLuint viewIndex = indices[binding];
 
-                        for (auto unit : pipeline->GetTextureUnitsForTexture(textureIndex)) {
+                        for (auto unit : pipeline->GetTextureUnitsForTextureView(viewIndex)) {
                             glActiveTexture(GL_TEXTURE0 + unit);
                             glBindTexture(target, handle);
                         }
diff --git a/src/dawn_native/opengl/PipelineGL.cpp b/src/dawn_native/opengl/PipelineGL.cpp
index c3cdc33..f03ab87 100644
--- a/src/dawn_native/opengl/PipelineGL.cpp
+++ b/src/dawn_native/opengl/PipelineGL.cpp
@@ -204,7 +204,7 @@
         return mUnitsForSamplers[index];
     }
 
-    const std::vector<GLuint>& PipelineGL::GetTextureUnitsForTexture(GLuint index) const {
+    const std::vector<GLuint>& PipelineGL::GetTextureUnitsForTextureView(GLuint index) const {
         ASSERT(index < mUnitsForSamplers.size());
         return mUnitsForTextures[index];
     }
diff --git a/src/dawn_native/opengl/PipelineGL.h b/src/dawn_native/opengl/PipelineGL.h
index 400e0f5..b3feeb9 100644
--- a/src/dawn_native/opengl/PipelineGL.h
+++ b/src/dawn_native/opengl/PipelineGL.h
@@ -40,7 +40,7 @@
 
         const GLPushConstantInfo& GetGLPushConstants(dawn::ShaderStage stage) const;
         const std::vector<GLuint>& GetTextureUnitsForSampler(GLuint index) const;
-        const std::vector<GLuint>& GetTextureUnitsForTexture(GLuint index) const;
+        const std::vector<GLuint>& GetTextureUnitsForTextureView(GLuint index) const;
         GLuint GetProgramHandle() const;
 
         void ApplyNow();
diff --git a/src/dawn_native/opengl/TextureGL.cpp b/src/dawn_native/opengl/TextureGL.cpp
index 6b9d90c..bbe6a12 100644
--- a/src/dawn_native/opengl/TextureGL.cpp
+++ b/src/dawn_native/opengl/TextureGL.cpp
@@ -31,6 +31,19 @@
                     return (arrayLayer > 1) ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
                 default:
                     UNREACHABLE();
+                    return GL_TEXTURE_2D;
+            }
+        }
+
+        GLenum TargetForTextureViewDimension(dawn::TextureViewDimension dimension) {
+            switch (dimension) {
+                case dawn::TextureViewDimension::e2D:
+                    return GL_TEXTURE_2D;
+                case dawn::TextureViewDimension::e2DArray:
+                    return GL_TEXTURE_2D_ARRAY;
+                default:
+                    UNREACHABLE();
+                    return GL_TEXTURE_2D;
             }
         }
 
@@ -56,6 +69,7 @@
                             GL_FLOAT_32_UNSIGNED_INT_24_8_REV};
                 default:
                     UNREACHABLE();
+                    return {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE};
             }
         }
 
@@ -86,23 +100,20 @@
 
         glBindTexture(mTarget, handle);
 
-        for (uint32_t i = 0; i < levels; ++i) {
-            switch (GetDimension()) {
-                case dawn::TextureDimension::e2D:
-                    if (arrayLayers > 1) {
-                        glTexImage3D(mTarget, i, formatInfo.internalFormat, width, height,
-                                     arrayLayers, 0, formatInfo.format, formatInfo.type, nullptr);
-                    } else {
-                        glTexImage2D(mTarget, i, formatInfo.internalFormat, width, height, 0,
-                                     formatInfo.format, formatInfo.type, nullptr);
-                    }
-                    break;
-                default:
-                    UNREACHABLE();
-            }
-
-            width = std::max(uint32_t(1), width / 2);
-            height = std::max(uint32_t(1), height / 2);
+        // glTextureView() requires the value of GL_TEXTURE_IMMUTABLE_FORMAT for origtexture to be
+        // GL_TRUE, so the storage of the texture must be allocated with glTexStorage*D.
+        // https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glTextureView.xhtml
+        switch (GetDimension()) {
+            case dawn::TextureDimension::e2D:
+                if (arrayLayers > 1) {
+                    glTexStorage3D(mTarget, levels, formatInfo.internalFormat, width, height,
+                                   arrayLayers);
+                } else {
+                    glTexStorage2D(mTarget, levels, formatInfo.internalFormat, width, height);
+                }
+                break;
+            default:
+                UNREACHABLE();
         }
 
         // The texture is not complete if it uses mipmapping and not all levels up to
@@ -129,9 +140,30 @@
 
     // TextureView
 
-    // TODO(jiawei.shao@intel.com): create texture view by TextureViewDescriptor
     TextureView::TextureView(TextureBase* texture, const TextureViewDescriptor* descriptor)
         : TextureViewBase(texture, descriptor) {
+        mTarget = TargetForTextureViewDimension(descriptor->dimension);
+
+        // glTextureView() is supported on OpenGL version >= 4.3
+        // TODO(jiawei.shao@intel.com): support texture view on OpenGL version <= 4.2
+        mHandle = GenTexture();
+        const Texture* textureGL = ToBackend(texture);
+        TextureFormatInfo textureViewFormat = GetGLFormatInfo(descriptor->format);
+        glTextureView(mHandle, mTarget, textureGL->GetHandle(), textureViewFormat.internalFormat,
+                      descriptor->baseMipLevel, descriptor->levelCount, descriptor->baseArrayLayer,
+                      descriptor->layerCount);
+    }
+
+    TextureView::~TextureView() {
+        glDeleteTextures(1, &mHandle);
+    }
+
+    GLuint TextureView::GetHandle() const {
+        return mHandle;
+    }
+
+    GLenum TextureView::GetGLTarget() const {
+        return mTarget;
     }
 
 }}  // namespace dawn_native::opengl
diff --git a/src/dawn_native/opengl/TextureGL.h b/src/dawn_native/opengl/TextureGL.h
index be7d159..5b12da5 100644
--- a/src/dawn_native/opengl/TextureGL.h
+++ b/src/dawn_native/opengl/TextureGL.h
@@ -47,6 +47,14 @@
     class TextureView : public TextureViewBase {
       public:
         TextureView(TextureBase* texture, const TextureViewDescriptor* descriptor);
+        ~TextureView();
+
+        GLuint GetHandle() const;
+        GLenum GetGLTarget() const;
+
+      private:
+        GLuint mHandle;
+        GLenum mTarget;
     };
 
 }}  // namespace dawn_native::opengl
diff --git a/src/tests/end2end/TextureViewTests.cpp b/src/tests/end2end/TextureViewTests.cpp
index 1877cf4..f3fdcae 100644
--- a/src/tests/end2end/TextureViewTests.cpp
+++ b/src/tests/end2end/TextureViewTests.cpp
@@ -163,10 +163,6 @@
                            uint32_t textureMipLevels,
                            uint32_t textureViewBaseLayer,
                            uint32_t textureViewBaseMipLevel) {
-        // TODO(jiawei.shao@intel.com): support creating texture view with a texture view descriptor
-        // on OpenGL.
-        DAWN_SKIP_TEST_IF(IsOpenGL());
-
         ASSERT(textureViewBaseLayer < textureArrayLayers);
         ASSERT(textureViewBaseMipLevel < textureMipLevels);
 
@@ -200,10 +196,6 @@
                                 uint32_t textureMipLevels,
                                 uint32_t textureViewBaseLayer,
                                 uint32_t textureViewBaseMipLevel) {
-        // TODO(jiawei.shao@intel.com): support creating texture view with a texture view descriptor
-        // on OpenGL.
-        DAWN_SKIP_TEST_IF(IsOpenGL());
-
         ASSERT(textureViewBaseLayer < textureArrayLayers);
         ASSERT(textureViewBaseMipLevel < textureMipLevels);