Introduce a format table in the OpenGL

The information about formats in OpenGL will grow to include more
information than just (internalFormat, format, type) and will gain more
logic to depend on GL version and available extensions over time.

BUG=dawn:128

Change-Id: I63a6ac7d48797fb4a9f97a65871306e640cf41d6
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/9201
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Jiawei Shao <jiawei.shao@intel.com>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index 8245a6a..42396ce 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -302,6 +302,8 @@
       "src/dawn_native/opengl/DeviceGL.cpp",
       "src/dawn_native/opengl/DeviceGL.h",
       "src/dawn_native/opengl/Forward.h",
+      "src/dawn_native/opengl/GLFormat.cpp",
+      "src/dawn_native/opengl/GLFormat.h",
       "src/dawn_native/opengl/NativeSwapChainImplGL.cpp",
       "src/dawn_native/opengl/NativeSwapChainImplGL.h",
       "src/dawn_native/opengl/OpenGLFunctions.cpp",
diff --git a/src/dawn_native/opengl/CommandBufferGL.cpp b/src/dawn_native/opengl/CommandBufferGL.cpp
index a670967..8e4a3ea 100644
--- a/src/dawn_native/opengl/CommandBufferGL.cpp
+++ b/src/dawn_native/opengl/CommandBufferGL.cpp
@@ -394,7 +394,7 @@
                     Buffer* buffer = ToBackend(src.buffer.Get());
                     Texture* texture = ToBackend(dst.texture.Get());
                     GLenum target = texture->GetGLTarget();
-                    auto format = texture->GetGLFormat();
+                    const GLFormat& format = texture->GetGLFormat();
                     if (IsCompleteSubresourceCopiedTo(texture, copySize, dst.mipLevel)) {
                         texture->SetIsSubresourceContentInitialized(dst.mipLevel, 1, dst.arrayLayer,
                                                                     1);
@@ -442,7 +442,7 @@
                     auto& copySize = copy->copySize;
                     Texture* texture = ToBackend(src.texture.Get());
                     Buffer* buffer = ToBackend(dst.buffer.Get());
-                    auto format = texture->GetGLFormat();
+                    const GLFormat& format = texture->GetGLFormat();
                     GLenum target = texture->GetGLTarget();
 
                     texture->EnsureSubresourceContentInitialized(src.mipLevel, 1, src.arrayLayer,
diff --git a/src/dawn_native/opengl/DeviceGL.cpp b/src/dawn_native/opengl/DeviceGL.cpp
index 36937cd..0283722 100644
--- a/src/dawn_native/opengl/DeviceGL.cpp
+++ b/src/dawn_native/opengl/DeviceGL.cpp
@@ -38,6 +38,7 @@
         if (descriptor != nullptr) {
             ApplyToggleOverrides(descriptor);
         }
+        mFormatTable = BuildGLFormatTable();
     }
 
     Device::~Device() {
@@ -54,6 +55,15 @@
         Tick();
     }
 
+    const GLFormat& Device::GetGLFormat(const Format& format) {
+        ASSERT(format.isSupported);
+        ASSERT(format.GetIndex() < mFormatTable.size());
+
+        const GLFormat& result = mFormatTable[format.GetIndex()];
+        ASSERT(result.isSupportedOnBackend);
+        return result;
+    }
+
     ResultOrError<BindGroupBase*> Device::CreateBindGroupImpl(
         const BindGroupDescriptor* descriptor) {
         return new BindGroup(this, descriptor);
diff --git a/src/dawn_native/opengl/DeviceGL.h b/src/dawn_native/opengl/DeviceGL.h
index 4f90beb..bfbdc27 100644
--- a/src/dawn_native/opengl/DeviceGL.h
+++ b/src/dawn_native/opengl/DeviceGL.h
@@ -20,6 +20,7 @@
 #include "common/Platform.h"
 #include "dawn_native/Device.h"
 #include "dawn_native/opengl/Forward.h"
+#include "dawn_native/opengl/GLFormat.h"
 #include "dawn_native/opengl/OpenGLFunctions.h"
 
 #include <queue>
@@ -41,6 +42,8 @@
         // Contains all the OpenGL entry points, glDoFoo is called via device->gl.DoFoo.
         const OpenGLFunctions gl;
 
+        const GLFormat& GetGLFormat(const Format& format);
+
         void SubmitFenceSync();
 
         // Dawn API
@@ -87,6 +90,8 @@
         Serial mCompletedSerial = 0;
         Serial mLastSubmittedSerial = 0;
         std::queue<std::pair<GLsync, Serial>> mFencesInFlight;
+
+        GLFormatTable mFormatTable;
     };
 
 }}  // namespace dawn_native::opengl
diff --git a/src/dawn_native/opengl/GLFormat.cpp b/src/dawn_native/opengl/GLFormat.cpp
new file mode 100644
index 0000000..617a02e
--- /dev/null
+++ b/src/dawn_native/opengl/GLFormat.cpp
@@ -0,0 +1,48 @@
+// Copyright 2019 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "dawn_native/opengl/GLFormat.h"
+
+namespace dawn_native { namespace opengl {
+
+    GLFormatTable BuildGLFormatTable() {
+        GLFormatTable table;
+
+        auto AddFormat = [&table](dawn::TextureFormat dawnFormat, GLenum internalFormat,
+                                  GLenum format, GLenum type) {
+            size_t index = ComputeFormatIndex(dawnFormat);
+            ASSERT(index < table.size());
+
+            table[index].internalFormat = internalFormat;
+            table[index].format = format;
+            table[index].type = type;
+            table[index].isSupportedOnBackend = true;
+        };
+
+        AddFormat(dawn::TextureFormat::RGBA8Unorm, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
+        AddFormat(dawn::TextureFormat::RG8Unorm, GL_RG8, GL_RG, GL_UNSIGNED_BYTE);
+        AddFormat(dawn::TextureFormat::R8Unorm, GL_R8, GL_RED, GL_UNSIGNED_BYTE);
+        AddFormat(dawn::TextureFormat::RGBA8Uint, GL_RGBA8UI, GL_RGBA, GL_UNSIGNED_INT);
+        AddFormat(dawn::TextureFormat::RG8Uint, GL_RG8UI, GL_RG, GL_UNSIGNED_INT);
+        AddFormat(dawn::TextureFormat::R8Uint, GL_R8UI, GL_RED, GL_UNSIGNED_INT);
+        // This doesn't have an enum for the internal format in OpenGL, so use RGBA8.
+        AddFormat(dawn::TextureFormat::BGRA8Unorm, GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE);
+
+        AddFormat(dawn::TextureFormat::Depth24PlusStencil8, GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL,
+                  GL_FLOAT_32_UNSIGNED_INT_24_8_REV);
+
+        return table;
+    }
+
+}}  // namespace dawn_native::opengl
diff --git a/src/dawn_native/opengl/GLFormat.h b/src/dawn_native/opengl/GLFormat.h
new file mode 100644
index 0000000..fdd04e9
--- /dev/null
+++ b/src/dawn_native/opengl/GLFormat.h
@@ -0,0 +1,37 @@
+// Copyright 2019 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef DAWNNATIVE_OPENGL_GLFORMAT_H_
+#define DAWNNATIVE_OPENGL_GLFORMAT_H_
+
+#include "dawn_native/Format.h"
+#include "dawn_native/opengl/opengl_platform.h"
+
+namespace dawn_native { namespace opengl {
+
+    class Device;
+
+    struct GLFormat {
+        GLenum internalFormat = 0;
+        GLenum format = 0;
+        GLenum type = 0;
+        bool isSupportedOnBackend = false;
+    };
+
+    using GLFormatTable = std::array<GLFormat, kKnownFormatCount>;
+    GLFormatTable BuildGLFormatTable();
+
+}}  // namespace dawn_native::opengl
+
+#endif  // DAWNNATIVE_OPENGL_GLFORMAT_H_
diff --git a/src/dawn_native/opengl/TextureGL.cpp b/src/dawn_native/opengl/TextureGL.cpp
index e27c506..cdb7419 100644
--- a/src/dawn_native/opengl/TextureGL.cpp
+++ b/src/dawn_native/opengl/TextureGL.cpp
@@ -13,14 +13,10 @@
 // limitations under the License.
 
 #include "dawn_native/opengl/TextureGL.h"
-#include "dawn_native/opengl/DeviceGL.h"
-#include "dawn_native/opengl/UtilsGL.h"
 
 #include "common/Assert.h"
-#include "dawn_native/Commands.h"
-
-#include <algorithm>
-#include <vector>
+#include "dawn_native/opengl/DeviceGL.h"
+#include "dawn_native/opengl/UtilsGL.h"
 
 namespace dawn_native { namespace opengl {
 
@@ -64,32 +60,6 @@
             }
         }
 
-        TextureFormatInfo GetGLFormatInfo(dawn::TextureFormat format) {
-            switch (format) {
-                case dawn::TextureFormat::RGBA8Unorm:
-                    return {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE};
-                case dawn::TextureFormat::RG8Unorm:
-                    return {GL_RG8, GL_RG, GL_UNSIGNED_BYTE};
-                case dawn::TextureFormat::R8Unorm:
-                    return {GL_R8, GL_RED, GL_UNSIGNED_BYTE};
-                case dawn::TextureFormat::RGBA8Uint:
-                    return {GL_RGBA8UI, GL_RGBA, GL_UNSIGNED_INT};
-                case dawn::TextureFormat::RG8Uint:
-                    return {GL_RG8UI, GL_RG, GL_UNSIGNED_INT};
-                case dawn::TextureFormat::R8Uint:
-                    return {GL_R8UI, GL_RED, GL_UNSIGNED_INT};
-                case dawn::TextureFormat::BGRA8Unorm:
-                    // This doesn't have an enum for the internal format in OpenGL, so use RGBA8.
-                    return {GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE};
-                case dawn::TextureFormat::Depth24PlusStencil8:
-                    return {GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL,
-                            GL_FLOAT_32_UNSIGNED_INT_24_8_REV};
-                default:
-                    UNREACHABLE();
-                    return {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE};
-            }
-        }
-
         GLuint GenTexture(const OpenGLFunctions& gl) {
             GLuint handle = 0;
             gl.GenTextures(1, &handle);
@@ -141,7 +111,7 @@
         uint32_t arrayLayers = GetArrayLayers();
         uint32_t sampleCount = GetSampleCount();
 
-        auto formatInfo = GetGLFormatInfo(GetFormat().format);
+        const GLFormat& glFormat = GetGLFormat();
 
         gl.BindTexture(mTarget, mHandle);
 
@@ -152,14 +122,14 @@
             case dawn::TextureDimension::e2D:
                 if (arrayLayers > 1) {
                     ASSERT(!IsMultisampledTexture());
-                    gl.TexStorage3D(mTarget, levels, formatInfo.internalFormat, width, height,
+                    gl.TexStorage3D(mTarget, levels, glFormat.internalFormat, width, height,
                                     arrayLayers);
                 } else {
                     if (IsMultisampledTexture()) {
-                        gl.TexStorage2DMultisample(mTarget, sampleCount, formatInfo.internalFormat,
+                        gl.TexStorage2DMultisample(mTarget, sampleCount, glFormat.internalFormat,
                                                    width, height, true);
                     } else {
-                        gl.TexStorage2D(mTarget, levels, formatInfo.internalFormat, width, height);
+                        gl.TexStorage2D(mTarget, levels, glFormat.internalFormat, width, height);
                     }
                 }
                 break;
@@ -178,7 +148,7 @@
             std::fill(clearColor, clearColor + MAX_TEXEL_SIZE, 255);
             // TODO(natlee@microsoft.com): clear all subresources
             for (uint32_t i = 0; i < GetNumMipLevels(); i++) {
-                gl.ClearTexImage(mHandle, i, formatInfo.format, formatInfo.type, clearColor);
+                gl.ClearTexImage(mHandle, i, glFormat.format, glFormat.type, clearColor);
             }
         }
     }
@@ -208,8 +178,8 @@
         return mTarget;
     }
 
-    TextureFormatInfo Texture::GetGLFormat() const {
-        return GetGLFormatInfo(GetFormat().format);
+    const GLFormat& Texture::GetGLFormat() const {
+        return ToBackend(GetDevice())->GetGLFormat(GetFormat());
     }
 
     void Texture::ClearTexture(GLint baseMipLevel,
@@ -243,11 +213,11 @@
             }
             gl.DeleteFramebuffers(1, &framebuffer);
         } else {
-            auto formatInfo = GetGLFormatInfo(GetFormat().format);
+            const GLFormat& glFormat = GetGLFormat();
             for (GLint level = baseMipLevel; level < baseMipLevel + levelCount; ++level) {
                 Extent3D mipSize = GetMipLevelPhysicalSize(level);
                 gl.ClearTexSubImage(mHandle, level, 0, 0, baseArrayLayer, mipSize.width,
-                                    mipSize.height, layerCount, formatInfo.format, formatInfo.type,
+                                    mipSize.height, layerCount, glFormat.format, glFormat.type,
                                     nullptr);
             }
         }
@@ -283,11 +253,10 @@
             const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
             mHandle = GenTexture(gl);
             const Texture* textureGL = ToBackend(texture);
-            TextureFormatInfo textureViewFormat = GetGLFormatInfo(descriptor->format);
-            gl.TextureView(mHandle, mTarget, textureGL->GetHandle(),
-                           textureViewFormat.internalFormat, descriptor->baseMipLevel,
-                           descriptor->mipLevelCount, descriptor->baseArrayLayer,
-                           descriptor->arrayLayerCount);
+            const GLFormat& glFormat = ToBackend(GetDevice())->GetGLFormat(GetFormat());
+            gl.TextureView(mHandle, mTarget, textureGL->GetHandle(), glFormat.internalFormat,
+                           descriptor->baseMipLevel, descriptor->mipLevelCount,
+                           descriptor->baseArrayLayer, descriptor->arrayLayerCount);
             mOwnsHandle = true;
         }
     }
diff --git a/src/dawn_native/opengl/TextureGL.h b/src/dawn_native/opengl/TextureGL.h
index 28dc238..4b8798e 100644
--- a/src/dawn_native/opengl/TextureGL.h
+++ b/src/dawn_native/opengl/TextureGL.h
@@ -22,12 +22,7 @@
 namespace dawn_native { namespace opengl {
 
     class Device;
-
-    struct TextureFormatInfo {
-        GLenum internalFormat;
-        GLenum format;
-        GLenum type;
-    };
+    struct GLFormat;
 
     class Texture : public TextureBase {
       public:
@@ -40,7 +35,7 @@
 
         GLuint GetHandle() const;
         GLenum GetGLTarget() const;
-        TextureFormatInfo GetGLFormat() const;
+        const GLFormat& GetGLFormat() const;
 
         void EnsureSubresourceContentInitialized(uint32_t baseMipLevel,
                                                  uint32_t levelCount,