Precompute all the Formats at Device creation in the FormatTable

This is needed for two reasons:
 - TextureBase and TextureViewBase stored Formats by value which isn't too
much overhead at this time but will get bigger in the future.
 - The OpenGL backends needs its own GLFormat structure to store data about
each format which will eventually contain complicated logic to detect
support in the GL driver so it shouldn't be duplicated in Textures.

The computations of the information about Format is moved from being done
whenever they are needed to being precomputed at DeviceBase initialization.
This makes each format have a constant "index" in that can be used in the
backends to address their own structure, for example a GLFormat table.

Also some DeviceBase pointers were made const for validation.

BUG=dawn:128

Change-Id: I37d1e9c739b87cddcea09cb1759e175704d90f9e
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/9101
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 3c76769..2c687bb 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -133,6 +133,8 @@
     "src/dawn_native/Fence.h",
     "src/dawn_native/FenceSignalTracker.cpp",
     "src/dawn_native/FenceSignalTracker.h",
+    "src/dawn_native/Format.cpp",
+    "src/dawn_native/Format.h",
     "src/dawn_native/Forward.h",
     "src/dawn_native/Instance.cpp",
     "src/dawn_native/Instance.h",
diff --git a/src/dawn_native/Device.cpp b/src/dawn_native/Device.cpp
index ae373bf..8be70b0 100644
--- a/src/dawn_native/Device.cpp
+++ b/src/dawn_native/Device.cpp
@@ -63,6 +63,8 @@
         mFenceSignalTracker = std::make_unique<FenceSignalTracker>(this);
         mDynamicUploader = std::make_unique<DynamicUploader>(this);
         SetDefaultToggles();
+
+        mFormatTable = BuildFormatTable(this);
     }
 
     DeviceBase::~DeviceBase() {
@@ -100,6 +102,27 @@
         return mFenceSignalTracker.get();
     }
 
+    ResultOrError<const Format*> DeviceBase::GetInternalFormat(dawn::TextureFormat format) const {
+        size_t index = ComputeFormatIndex(format);
+        if (index >= mFormatTable.size()) {
+            return DAWN_VALIDATION_ERROR("Unknown texture format");
+        }
+
+        const Format* internalFormat = &mFormatTable[index];
+        if (!internalFormat->isSupported) {
+            return DAWN_VALIDATION_ERROR("Unsupported texture format");
+        }
+
+        return internalFormat;
+    }
+
+    const Format& DeviceBase::GetValidInternalFormat(dawn::TextureFormat format) const {
+        size_t index = ComputeFormatIndex(format);
+        ASSERT(index < mFormatTable.size());
+        ASSERT(mFormatTable[index].isSupported);
+        return mFormatTable[index];
+    }
+
     ResultOrError<BindGroupLayoutBase*> DeviceBase::GetOrCreateBindGroupLayout(
         const BindGroupLayoutDescriptor* descriptor) {
         BindGroupLayoutBase blueprint(this, descriptor, true);
diff --git a/src/dawn_native/Device.h b/src/dawn_native/Device.h
index 197a87c..d99f0f9 100644
--- a/src/dawn_native/Device.h
+++ b/src/dawn_native/Device.h
@@ -17,6 +17,7 @@
 
 #include "common/Serial.h"
 #include "dawn_native/Error.h"
+#include "dawn_native/Format.h"
 #include "dawn_native/Forward.h"
 #include "dawn_native/ObjectBase.h"
 #include "dawn_native/Toggles.h"
@@ -56,6 +57,16 @@
 
         FenceSignalTracker* GetFenceSignalTracker() const;
 
+        // Returns the Format corresponding to the dawn::TextureFormat or an error if the format
+        // isn't a valid dawn::TextureFormat or isn't supported by this device.
+        // The pointer returned has the same lifetime as the device.
+        ResultOrError<const Format*> GetInternalFormat(dawn::TextureFormat format) const;
+
+        // Returns the Format corresponding to the dawn::TextureFormat and assumes the format is
+        // valid and supported.
+        // The reference returned has the same lifetime as the device.
+        const Format& GetValidInternalFormat(dawn::TextureFormat format) const;
+
         virtual CommandBufferBase* CreateCommandBuffer(
             CommandEncoderBase* encoder,
             const CommandBufferDescriptor* descriptor) = 0;
@@ -218,6 +229,8 @@
         void* mErrorUserdata = 0;
         uint32_t mRefCount = 1;
 
+        FormatTable mFormatTable;
+
         TogglesSet mTogglesSet;
     };
 
diff --git a/src/dawn_native/Format.cpp b/src/dawn_native/Format.cpp
new file mode 100644
index 0000000..da2946a
--- /dev/null
+++ b/src/dawn_native/Format.cpp
@@ -0,0 +1,195 @@
+// 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/Format.h"
+
+#include <bitset>
+
+namespace dawn_native {
+
+    // Format
+
+    bool Format::IsColor() const {
+        return aspect == Aspect::Color;
+    }
+
+    bool Format::HasDepth() const {
+        return aspect == Depth || aspect == DepthStencil;
+    }
+
+    bool Format::HasStencil() const {
+        return aspect == Stencil || aspect == DepthStencil;
+    }
+
+    bool Format::HasDepthOrStencil() const {
+        return aspect != Color;
+    }
+
+    size_t Format::GetIndex() const {
+        return ComputeFormatIndex(format);
+    }
+
+    // Implementation details of the format table of the DeviceBase
+
+    // For the enum for formats are packed but this might change when we have a broader extension
+    // mechanism for webgpu.h
+    size_t ComputeFormatIndex(dawn::TextureFormat format) {
+        return static_cast<size_t>(static_cast<uint32_t>(format));
+    }
+
+    FormatTable BuildFormatTable(const DeviceBase*) {
+        FormatTable table;
+        std::bitset<kKnownFormatCount> formatsSet;
+
+        auto AddFormat = [&table, &formatsSet](Format format) {
+            size_t index = ComputeFormatIndex(format.format);
+            ASSERT(index < table.size());
+
+            // This checks that each format is set at most once, the first part of checking that all
+            // formats are set exactly once.
+            ASSERT(!formatsSet[index]);
+
+            table[index] = format;
+            formatsSet.set(index);
+        };
+
+        auto AddColorFormat = [&AddFormat](dawn::TextureFormat format, bool renderable,
+                                           uint32_t byteSize) {
+            Format internalFormat;
+            internalFormat.format = format;
+            internalFormat.isRenderable = renderable;
+            internalFormat.isCompressed = false;
+            internalFormat.isSupported = true;
+            internalFormat.aspect = Format::Aspect::Color;
+            internalFormat.blockByteSize = byteSize;
+            internalFormat.blockWidth = 1;
+            internalFormat.blockHeight = 1;
+            AddFormat(internalFormat);
+        };
+
+        auto AddDepthStencilFormat = [&AddFormat](dawn::TextureFormat format, Format::Aspect aspect,
+                                                  uint32_t byteSize) {
+            Format internalFormat;
+            internalFormat.format = format;
+            internalFormat.isRenderable = true;
+            internalFormat.isCompressed = false;
+            internalFormat.isSupported = true;
+            internalFormat.aspect = aspect;
+            internalFormat.blockByteSize = byteSize;
+            internalFormat.blockWidth = 1;
+            internalFormat.blockHeight = 1;
+            AddFormat(internalFormat);
+        };
+
+        auto AddCompressedFormat = [&AddFormat](dawn::TextureFormat format, uint32_t byteSize,
+                                                uint32_t width, uint32_t height) {
+            Format internalFormat;
+            internalFormat.format = format;
+            internalFormat.isRenderable = false;
+            internalFormat.isCompressed = true;
+            internalFormat.isSupported = true;
+            internalFormat.aspect = Format::Aspect::Color;
+            internalFormat.blockByteSize = byteSize;
+            internalFormat.blockWidth = width;
+            internalFormat.blockHeight = height;
+            AddFormat(internalFormat);
+        };
+
+        // clang-format off
+
+        // 1 byte color formats
+        AddColorFormat(dawn::TextureFormat::R8Unorm, true, 1);
+        AddColorFormat(dawn::TextureFormat::R8Snorm, true, 1);
+        AddColorFormat(dawn::TextureFormat::R8Uint, true, 1);
+        AddColorFormat(dawn::TextureFormat::R8Sint, true, 1);
+
+        // 2 bytes color formats
+        AddColorFormat(dawn::TextureFormat::R16Unorm, true, 2);
+        AddColorFormat(dawn::TextureFormat::R16Snorm, true, 2);
+        AddColorFormat(dawn::TextureFormat::R16Uint, true, 2);
+        AddColorFormat(dawn::TextureFormat::R16Sint, true, 2);
+        AddColorFormat(dawn::TextureFormat::R16Float, true, 2);
+        AddColorFormat(dawn::TextureFormat::RG8Unorm, true, 2);
+        AddColorFormat(dawn::TextureFormat::RG8Snorm, true, 2);
+        AddColorFormat(dawn::TextureFormat::RG8Uint, true, 2);
+        AddColorFormat(dawn::TextureFormat::RG8Sint, true, 2);
+
+        // 4 bytes color formats
+        AddColorFormat(dawn::TextureFormat::R32Uint, true, 4);
+        AddColorFormat(dawn::TextureFormat::R32Sint, true, 4);
+        AddColorFormat(dawn::TextureFormat::R32Float, true, 4);
+        AddColorFormat(dawn::TextureFormat::RG16Unorm, true, 4);
+        AddColorFormat(dawn::TextureFormat::RG16Snorm, true, 4);
+        AddColorFormat(dawn::TextureFormat::RG16Uint, true, 4);
+        AddColorFormat(dawn::TextureFormat::RG16Sint, true, 4);
+        AddColorFormat(dawn::TextureFormat::RG16Float, true, 4);
+        AddColorFormat(dawn::TextureFormat::RGBA8Unorm, true, 4);
+        AddColorFormat(dawn::TextureFormat::RGBA8UnormSrgb, true, 4);
+        AddColorFormat(dawn::TextureFormat::RGBA8Snorm, true, 4);
+        AddColorFormat(dawn::TextureFormat::RGBA8Uint, true, 4);
+        AddColorFormat(dawn::TextureFormat::RGBA8Sint, true, 4);
+        AddColorFormat(dawn::TextureFormat::BGRA8Unorm, true, 4);
+        AddColorFormat(dawn::TextureFormat::BGRA8UnormSrgb, true, 4);
+        AddColorFormat(dawn::TextureFormat::RGB10A2Unorm, true, 4);
+
+        AddColorFormat(dawn::TextureFormat::RG11B10Float, false, 4);
+
+        // 8 bytes color formats
+        AddColorFormat(dawn::TextureFormat::RG32Uint, true, 8);
+        AddColorFormat(dawn::TextureFormat::RG32Sint, true, 8);
+        AddColorFormat(dawn::TextureFormat::RG32Float, true, 8);
+        AddColorFormat(dawn::TextureFormat::RGBA16Unorm, true, 8);
+        AddColorFormat(dawn::TextureFormat::RGBA16Snorm, true, 8);
+        AddColorFormat(dawn::TextureFormat::RGBA16Uint, true, 8);
+        AddColorFormat(dawn::TextureFormat::RGBA16Sint, true, 8);
+        AddColorFormat(dawn::TextureFormat::RGBA16Float, true, 8);
+
+        // 16 bytes color formats
+        AddColorFormat(dawn::TextureFormat::RGBA32Uint, true, 16);
+        AddColorFormat(dawn::TextureFormat::RGBA32Sint, true, 16);
+        AddColorFormat(dawn::TextureFormat::RGBA32Float, true, 16);
+
+        // Depth stencil formats
+        AddDepthStencilFormat(dawn::TextureFormat::Depth32Float, Format::Aspect::Depth, 4);
+        AddDepthStencilFormat(dawn::TextureFormat::Depth24Plus, Format::Aspect::Depth, 4);
+        // TODO(cwallez@chromium.org): It isn't clear if this format should be copyable
+        // because its size isn't well defined, is it 4, 5 or 8?
+        AddDepthStencilFormat(dawn::TextureFormat::Depth24PlusStencil8, Format::Aspect::DepthStencil, 4);
+
+        // BC compressed formats
+        AddCompressedFormat(dawn::TextureFormat::BC1RGBAUnorm, 8, 4, 4);
+        AddCompressedFormat(dawn::TextureFormat::BC1RGBAUnormSrgb, 8, 4, 4);
+        AddCompressedFormat(dawn::TextureFormat::BC4RSnorm, 8, 4, 4);
+        AddCompressedFormat(dawn::TextureFormat::BC4RUnorm, 8, 4, 4);
+        AddCompressedFormat(dawn::TextureFormat::BC2RGBAUnorm, 16, 4, 4);
+        AddCompressedFormat(dawn::TextureFormat::BC2RGBAUnormSrgb, 16, 4, 4);
+        AddCompressedFormat(dawn::TextureFormat::BC3RGBAUnorm, 16, 4, 4);
+        AddCompressedFormat(dawn::TextureFormat::BC3RGBAUnormSrgb, 16, 4, 4);
+        AddCompressedFormat(dawn::TextureFormat::BC5RGSnorm, 16, 4, 4);
+        AddCompressedFormat(dawn::TextureFormat::BC5RGUnorm, 16, 4, 4);
+        AddCompressedFormat(dawn::TextureFormat::BC6HRGBSfloat, 16, 4, 4);
+        AddCompressedFormat(dawn::TextureFormat::BC6HRGBUfloat, 16, 4, 4);
+        AddCompressedFormat(dawn::TextureFormat::BC7RGBAUnorm, 16, 4, 4);
+        AddCompressedFormat(dawn::TextureFormat::BC7RGBAUnormSrgb, 16, 4, 4);
+
+        // clang-format on
+
+        // This checks that each format is set at least once, the second part of checking that all
+        // formats are checked exactly once.
+        ASSERT(formatsSet.all());
+
+        return table;
+    }
+
+}  // namespace dawn_native
diff --git a/src/dawn_native/Format.h b/src/dawn_native/Format.h
new file mode 100644
index 0000000..334198c
--- /dev/null
+++ b/src/dawn_native/Format.h
@@ -0,0 +1,73 @@
+// 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_FORMAT_H_
+#define DAWNNATIVE_FORMAT_H_
+
+#include "dawn_native/dawn_platform.h"
+
+#include "dawn_native/Error.h"
+
+#include <array>
+
+namespace dawn_native {
+
+    class DeviceBase;
+
+    // The number of formats Dawn knows about. Asserts in BuildFormatTable ensure that this is the
+    // exact number of known format.
+    static constexpr size_t kKnownFormatCount = 58;
+
+    // A dawn::TextureFormat along with all the information about it necessary for validation.
+    struct Format {
+        enum Aspect {
+            Color,
+            Depth,
+            Stencil,
+            DepthStencil,
+        };
+
+        dawn::TextureFormat format;
+        bool isRenderable;
+        bool isCompressed;
+        // A format can be known but not supported because it is part of a disabled extension.
+        bool isSupported;
+        Aspect aspect;
+
+        uint32_t blockByteSize;
+        uint32_t blockWidth;
+        uint32_t blockHeight;
+
+        bool IsColor() const;
+        bool HasDepth() const;
+        bool HasStencil() const;
+        bool HasDepthOrStencil() const;
+
+        // The index of the format in the list of all known formats: a unique number for each format
+        // in [0, kKnownFormatCount)
+        size_t GetIndex() const;
+    };
+
+    // Implementation details of the format table in the device.
+
+    using FormatTable = std::array<Format, kKnownFormatCount>;
+
+    // Returns the index of a format in the FormatTable.
+    size_t ComputeFormatIndex(dawn::TextureFormat format);
+    // Builds the format table with the extensions enabled on the device.
+    FormatTable BuildFormatTable(const DeviceBase* device);
+
+}  // namespace dawn_native
+
+#endif  // DAWNNATIVE_FORMAT_H_
diff --git a/src/dawn_native/Forward.h b/src/dawn_native/Forward.h
index db53904..b4c3e83 100644
--- a/src/dawn_native/Forward.h
+++ b/src/dawn_native/Forward.h
@@ -48,6 +48,9 @@
 
     template <typename T>
     class PerStage;
+
+    struct Format;
+
 }  // namespace dawn_native
 
 #endif  // DAWNNATIVE_FORWARD_H_
diff --git a/src/dawn_native/Pipeline.cpp b/src/dawn_native/Pipeline.cpp
index 639df34..6551e17 100644
--- a/src/dawn_native/Pipeline.cpp
+++ b/src/dawn_native/Pipeline.cpp
@@ -20,7 +20,7 @@
 
 namespace dawn_native {
 
-    MaybeError ValidatePipelineStageDescriptor(DeviceBase* device,
+    MaybeError ValidatePipelineStageDescriptor(const DeviceBase* device,
                                                const PipelineStageDescriptor* descriptor,
                                                const PipelineLayoutBase* layout,
                                                ShaderStage stage) {
diff --git a/src/dawn_native/Pipeline.h b/src/dawn_native/Pipeline.h
index c72a724..209fade 100644
--- a/src/dawn_native/Pipeline.h
+++ b/src/dawn_native/Pipeline.h
@@ -28,7 +28,7 @@
 
 namespace dawn_native {
 
-    MaybeError ValidatePipelineStageDescriptor(DeviceBase* device,
+    MaybeError ValidatePipelineStageDescriptor(const DeviceBase* device,
                                                const PipelineStageDescriptor* descriptor,
                                                const PipelineLayoutBase* layout,
                                                ShaderStage stage);
diff --git a/src/dawn_native/RenderPipeline.cpp b/src/dawn_native/RenderPipeline.cpp
index b8b2d2b..421abf2 100644
--- a/src/dawn_native/RenderPipeline.cpp
+++ b/src/dawn_native/RenderPipeline.cpp
@@ -18,7 +18,6 @@
 #include "common/HashUtils.h"
 #include "dawn_native/Commands.h"
 #include "dawn_native/Device.h"
-#include "dawn_native/Texture.h"
 #include "dawn_native/ValidationUtils_autogen.h"
 
 namespace dawn_native {
@@ -112,7 +111,8 @@
             return {};
         }
 
-        MaybeError ValidateColorStateDescriptor(const ColorStateDescriptor* descriptor) {
+        MaybeError ValidateColorStateDescriptor(const DeviceBase* device,
+                                                const ColorStateDescriptor* descriptor) {
             if (descriptor->nextInChain != nullptr) {
                 return DAWN_VALIDATION_ERROR("nextInChain must be nullptr");
             }
@@ -124,9 +124,9 @@
             DAWN_TRY(ValidateBlendFactor(descriptor->colorBlend.dstFactor));
             DAWN_TRY(ValidateColorWriteMask(descriptor->writeMask));
 
-            Format format;
-            DAWN_TRY_ASSIGN(format, ConvertFormat(descriptor->format));
-            if (!format.IsColor() || !format.isRenderable) {
+            const Format* format;
+            DAWN_TRY_ASSIGN(format, device->GetInternalFormat(descriptor->format));
+            if (!format->IsColor() || !format->isRenderable) {
                 return DAWN_VALIDATION_ERROR("Color format must be color renderable");
             }
 
@@ -134,6 +134,7 @@
         }
 
         MaybeError ValidateDepthStencilStateDescriptor(
+            const DeviceBase* device,
             const DepthStencilStateDescriptor* descriptor) {
             if (descriptor->nextInChain != nullptr) {
                 return DAWN_VALIDATION_ERROR("nextInChain must be nullptr");
@@ -148,9 +149,9 @@
             DAWN_TRY(ValidateStencilOperation(descriptor->stencilBack.depthFailOp));
             DAWN_TRY(ValidateStencilOperation(descriptor->stencilBack.passOp));
 
-            Format format;
-            DAWN_TRY_ASSIGN(format, ConvertFormat(descriptor->format));
-            if (!format.HasDepthOrStencil() || !format.isRenderable) {
+            const Format* format;
+            DAWN_TRY_ASSIGN(format, device->GetInternalFormat(descriptor->format));
+            if (!format->HasDepthOrStencil() || !format->isRenderable) {
                 return DAWN_VALIDATION_ERROR(
                     "Depth stencil format must be depth-stencil renderable");
             }
@@ -258,7 +259,7 @@
         return VertexFormatNumComponents(format) * VertexFormatComponentSize(format);
     }
 
-    MaybeError ValidateRenderPipelineDescriptor(DeviceBase* device,
+    MaybeError ValidateRenderPipelineDescriptor(const DeviceBase* device,
                                                 const RenderPipelineDescriptor* descriptor) {
         if (descriptor->nextInChain != nullptr) {
             return DAWN_VALIDATION_ERROR("nextInChain must be nullptr");
@@ -301,11 +302,11 @@
         }
 
         for (uint32_t i = 0; i < descriptor->colorStateCount; ++i) {
-            DAWN_TRY(ValidateColorStateDescriptor(descriptor->colorStates[i]));
+            DAWN_TRY(ValidateColorStateDescriptor(device, descriptor->colorStates[i]));
         }
 
         if (descriptor->depthStencilState) {
-            DAWN_TRY(ValidateDepthStencilStateDescriptor(descriptor->depthStencilState));
+            DAWN_TRY(ValidateDepthStencilStateDescriptor(device, descriptor->depthStencilState));
         }
 
         if (descriptor->sampleMask != 0xFFFFFFFF) {
diff --git a/src/dawn_native/RenderPipeline.h b/src/dawn_native/RenderPipeline.h
index aedf699..dfc46f7 100644
--- a/src/dawn_native/RenderPipeline.h
+++ b/src/dawn_native/RenderPipeline.h
@@ -28,7 +28,7 @@
 
     class DeviceBase;
 
-    MaybeError ValidateRenderPipelineDescriptor(DeviceBase* device,
+    MaybeError ValidateRenderPipelineDescriptor(const DeviceBase* device,
                                                 const RenderPipelineDescriptor* descriptor);
     size_t IndexFormatSize(dawn::IndexFormat format);
     uint32_t VertexFormatNumComponents(dawn::VertexFormat format);
diff --git a/src/dawn_native/Texture.cpp b/src/dawn_native/Texture.cpp
index d3c034e..f2f35a6 100644
--- a/src/dawn_native/Texture.cpp
+++ b/src/dawn_native/Texture.cpp
@@ -86,134 +86,8 @@
             }
         }
 
-        // Returns a format with a blockByteSize of 0 for an invalid input format
-        Format ConvertFormatInternal(dawn::TextureFormat format) {
-            auto MakeColorFormat = [](dawn::TextureFormat format, bool renderable,
-                                      uint32_t byteSize) -> Format {
-                Format result;
-                result.format = format;
-                result.isRenderable = renderable;
-                result.isCompressed = false;
-                result.aspect = Format::Aspect::Color;
-                result.blockByteSize = byteSize;
-                result.blockWidth = 1;
-                result.blockHeight = 1;
-                return result;
-            };
-
-            auto MakeDepthStencilFormat = [](dawn::TextureFormat format, Format::Aspect aspect,
-                                             uint32_t byteSize) -> Format {
-                Format result;
-                result.format = format;
-                result.isRenderable = true;
-                result.isCompressed = false;
-                result.aspect = aspect;
-                result.blockByteSize = byteSize;
-                result.blockWidth = 1;
-                result.blockHeight = 1;
-                return result;
-            };
-
-            auto MakeCompressedFormat = [](dawn::TextureFormat format, uint32_t byteSize,
-                                           uint32_t width, uint32_t height) -> Format {
-                Format result;
-                result.format = format;
-                result.isRenderable = false;
-                result.isCompressed = true;
-                result.aspect = Format::Aspect::Color;
-                result.blockByteSize = byteSize;
-                result.blockWidth = width;
-                result.blockHeight = height;
-                return result;
-            };
-
-            switch (format) {
-                case dawn::TextureFormat::R8Unorm:
-                case dawn::TextureFormat::R8Snorm:
-                case dawn::TextureFormat::R8Uint:
-                case dawn::TextureFormat::R8Sint:
-                    return MakeColorFormat(format, true, 1);
-
-                case dawn::TextureFormat::R16Unorm:
-                case dawn::TextureFormat::R16Snorm:
-                case dawn::TextureFormat::R16Uint:
-                case dawn::TextureFormat::R16Sint:
-                case dawn::TextureFormat::R16Float:
-                case dawn::TextureFormat::RG8Unorm:
-                case dawn::TextureFormat::RG8Snorm:
-                case dawn::TextureFormat::RG8Uint:
-                case dawn::TextureFormat::RG8Sint:
-                    return MakeColorFormat(format, true, 2);
-
-                case dawn::TextureFormat::R32Uint:
-                case dawn::TextureFormat::R32Sint:
-                case dawn::TextureFormat::R32Float:
-                case dawn::TextureFormat::RG16Unorm:
-                case dawn::TextureFormat::RG16Snorm:
-                case dawn::TextureFormat::RG16Uint:
-                case dawn::TextureFormat::RG16Sint:
-                case dawn::TextureFormat::RG16Float:
-                case dawn::TextureFormat::RGBA8Unorm:
-                case dawn::TextureFormat::RGBA8UnormSrgb:
-                case dawn::TextureFormat::RGBA8Snorm:
-                case dawn::TextureFormat::RGBA8Uint:
-                case dawn::TextureFormat::RGBA8Sint:
-                case dawn::TextureFormat::BGRA8Unorm:
-                case dawn::TextureFormat::BGRA8UnormSrgb:
-                case dawn::TextureFormat::RGB10A2Unorm:
-                    return MakeColorFormat(format, true, 4);
-                case dawn::TextureFormat::RG11B10Float:
-                    return MakeColorFormat(format, false, 4);
-
-                case dawn::TextureFormat::RG32Uint:
-                case dawn::TextureFormat::RG32Sint:
-                case dawn::TextureFormat::RG32Float:
-                case dawn::TextureFormat::RGBA16Unorm:
-                case dawn::TextureFormat::RGBA16Snorm:
-                case dawn::TextureFormat::RGBA16Uint:
-                case dawn::TextureFormat::RGBA16Sint:
-                case dawn::TextureFormat::RGBA16Float:
-                    return MakeColorFormat(format, true, 8);
-
-                case dawn::TextureFormat::RGBA32Uint:
-                case dawn::TextureFormat::RGBA32Sint:
-                case dawn::TextureFormat::RGBA32Float:
-                    return MakeColorFormat(format, true, 16);
-
-                case dawn::TextureFormat::Depth32Float:
-                case dawn::TextureFormat::Depth24Plus:
-                    return MakeDepthStencilFormat(format, Format::Aspect::Depth, 4);
-                case dawn::TextureFormat::Depth24PlusStencil8:
-                    // TODO(cwallez@chromium.org): It isn't clear if this format should be copyable
-                    // because its size isn't well defined, is it 4, 5 or 8?
-                    return MakeDepthStencilFormat(format, Format::Aspect::DepthStencil, 4);
-
-                case dawn::TextureFormat::BC1RGBAUnorm:
-                case dawn::TextureFormat::BC1RGBAUnormSrgb:
-                case dawn::TextureFormat::BC4RSnorm:
-                case dawn::TextureFormat::BC4RUnorm:
-                    return MakeCompressedFormat(format, 8, 4, 4);
-                case dawn::TextureFormat::BC2RGBAUnorm:
-                case dawn::TextureFormat::BC2RGBAUnormSrgb:
-                case dawn::TextureFormat::BC3RGBAUnorm:
-                case dawn::TextureFormat::BC3RGBAUnormSrgb:
-                case dawn::TextureFormat::BC5RGSnorm:
-                case dawn::TextureFormat::BC5RGUnorm:
-                case dawn::TextureFormat::BC6HRGBSfloat:
-                case dawn::TextureFormat::BC6HRGBUfloat:
-                case dawn::TextureFormat::BC7RGBAUnorm:
-                case dawn::TextureFormat::BC7RGBAUnormSrgb:
-                    return MakeCompressedFormat(format, 16, 4, 4);
-
-                default:
-                    Format result = {};
-                    result.blockByteSize = 0;
-                    return result;
-            }
-        }
-
         // TODO(jiawei.shao@intel.com): support more sample count.
-        MaybeError ValidateSampleCount(const TextureDescriptor* descriptor, const Format& format) {
+        MaybeError ValidateSampleCount(const TextureDescriptor* descriptor, const Format* format) {
             if (!IsValidSampleCount(descriptor->sampleCount)) {
                 return DAWN_VALIDATION_ERROR("The sample count of the texture is not supported.");
             }
@@ -230,7 +104,7 @@
                     return DAWN_VALIDATION_ERROR("Multisampled 2D array texture is not supported.");
                 }
 
-                if (format.isCompressed) {
+                if (format->isCompressed) {
                     return DAWN_VALIDATION_ERROR(
                         "The sample counts of the textures in BC formats must be 1.");
                 }
@@ -289,7 +163,7 @@
             return descriptor;
         }
 
-        MaybeError ValidateTextureSize(const TextureDescriptor* descriptor, const Format& format) {
+        MaybeError ValidateTextureSize(const TextureDescriptor* descriptor, const Format* format) {
             ASSERT(descriptor->size.width != 0 && descriptor->size.height != 0);
 
             if (Log2(std::max(descriptor->size.width, descriptor->size.height)) + 1 <
@@ -297,8 +171,8 @@
                 return DAWN_VALIDATION_ERROR("Texture has too many mip levels");
             }
 
-            if (format.isCompressed && (descriptor->size.width % format.blockWidth != 0 ||
-                                        descriptor->size.height % format.blockHeight != 0)) {
+            if (format->isCompressed && (descriptor->size.width % format->blockWidth != 0 ||
+                                         descriptor->size.height % format->blockHeight != 0)) {
                 return DAWN_VALIDATION_ERROR(
                     "The size of the texture is incompatible with the texture format");
             }
@@ -306,18 +180,18 @@
             return {};
         }
 
-        MaybeError ValidateTextureUsage(const TextureDescriptor* descriptor, const Format& format) {
+        MaybeError ValidateTextureUsage(const TextureDescriptor* descriptor, const Format* format) {
             DAWN_TRY(ValidateTextureUsageBit(descriptor->usage));
 
             constexpr dawn::TextureUsageBit kValidCompressedUsages =
                 dawn::TextureUsageBit::Sampled | dawn::TextureUsageBit::CopySrc |
                 dawn::TextureUsageBit::CopyDst;
-            if (format.isCompressed && (descriptor->usage & (~kValidCompressedUsages))) {
+            if (format->isCompressed && (descriptor->usage & (~kValidCompressedUsages))) {
                 return DAWN_VALIDATION_ERROR(
                     "Compressed texture format is incompatible with the texture usage");
             }
 
-            if (!format.isRenderable &&
+            if (!format->isRenderable &&
                 (descriptor->usage & dawn::TextureUsageBit::OutputAttachment)) {
                 return DAWN_VALIDATION_ERROR(
                     "Non-renderable format used with OutputAttachment usage");
@@ -332,13 +206,14 @@
 
     }  // anonymous namespace
 
-    MaybeError ValidateTextureDescriptor(DeviceBase*, const TextureDescriptor* descriptor) {
+    MaybeError ValidateTextureDescriptor(const DeviceBase* device,
+                                         const TextureDescriptor* descriptor) {
         if (descriptor->nextInChain != nullptr) {
             return DAWN_VALIDATION_ERROR("nextInChain must be nullptr");
         }
 
-        Format format;
-        DAWN_TRY_ASSIGN(format, ConvertFormat(descriptor->format));
+        const Format* format;
+        DAWN_TRY_ASSIGN(format, device->GetInternalFormat(descriptor->format));
 
         DAWN_TRY(ValidateTextureUsage(descriptor, format));
         DAWN_TRY(ValidateTextureDimension(descriptor->dimension));
@@ -412,36 +287,6 @@
         }
     }
 
-    ResultOrError<Format> ConvertFormat(dawn::TextureFormat format) {
-        Format result = ConvertFormatInternal(format);
-        if (result.blockByteSize == 0) {
-            return DAWN_VALIDATION_ERROR("Invalid texture format");
-        }
-        return result;
-    }
-
-    Format ConvertValidFormat(dawn::TextureFormat format) {
-        Format result = ConvertFormatInternal(format);
-        ASSERT(result.blockByteSize != 0);
-        return result;
-    }
-
-    bool Format::IsColor() const {
-        return aspect == Aspect::Color;
-    }
-
-    bool Format::HasDepth() const {
-        return aspect == Depth || aspect == DepthStencil;
-    }
-
-    bool Format::HasStencil() const {
-        return aspect == Stencil || aspect == DepthStencil;
-    }
-
-    bool Format::HasDepthOrStencil() const {
-        return aspect != Color;
-    }
-
     // TextureBase
 
     TextureBase::TextureBase(DeviceBase* device,
@@ -449,7 +294,7 @@
                              TextureState state)
         : ObjectBase(device),
           mDimension(descriptor->dimension),
-          mFormat(ConvertValidFormat(descriptor->format)),
+          mFormat(device->GetValidInternalFormat(descriptor->format)),
           mSize(descriptor->size),
           mArrayLayerCount(descriptor->arrayLayerCount),
           mMipLevelCount(descriptor->mipLevelCount),
@@ -461,8 +306,10 @@
         mIsSubresourceContentInitializedAtIndex = std::vector<bool>(subresourceCount, false);
     }
 
+    static Format kUnusedFormat;
+
     TextureBase::TextureBase(DeviceBase* device, ObjectBase::ErrorTag tag)
-        : ObjectBase(device, tag) {
+        : ObjectBase(device, tag), mFormat(kUnusedFormat) {
     }
 
     // static
@@ -627,7 +474,7 @@
     TextureViewBase::TextureViewBase(TextureBase* texture, const TextureViewDescriptor* descriptor)
         : ObjectBase(texture->GetDevice()),
           mTexture(texture),
-          mFormat(ConvertValidFormat(descriptor->format)),
+          mFormat(GetDevice()->GetValidInternalFormat(descriptor->format)),
           mBaseMipLevel(descriptor->baseMipLevel),
           mMipLevelCount(descriptor->mipLevelCount),
           mBaseArrayLayer(descriptor->baseArrayLayer),
@@ -635,7 +482,7 @@
     }
 
     TextureViewBase::TextureViewBase(DeviceBase* device, ObjectBase::ErrorTag tag)
-        : ObjectBase(device, tag) {
+        : ObjectBase(device, tag), mFormat(kUnusedFormat) {
     }
 
     // static
diff --git a/src/dawn_native/Texture.h b/src/dawn_native/Texture.h
index 02cefe3..fa32758 100644
--- a/src/dawn_native/Texture.h
+++ b/src/dawn_native/Texture.h
@@ -24,7 +24,8 @@
 #include <vector>
 
 namespace dawn_native {
-    MaybeError ValidateTextureDescriptor(DeviceBase* device, const TextureDescriptor* descriptor);
+    MaybeError ValidateTextureDescriptor(const DeviceBase* device,
+                                         const TextureDescriptor* descriptor);
     MaybeError ValidateTextureViewDescriptor(const DeviceBase* device,
                                              const TextureBase* texture,
                                              const TextureViewDescriptor* descriptor);
@@ -39,36 +40,6 @@
         dawn::TextureUsageBit::CopyDst | dawn::TextureUsageBit::Storage |
         dawn::TextureUsageBit::OutputAttachment;
 
-    struct Format {
-        enum Aspect {
-            Color,
-            Depth,
-            Stencil,
-            DepthStencil,
-        };
-
-        dawn::TextureFormat format;
-        bool isRenderable;
-        bool isCompressed;
-        Aspect aspect;
-
-        uint32_t blockByteSize;
-        uint32_t blockWidth;
-        uint32_t blockHeight;
-
-        bool IsColor() const;
-        bool HasDepth() const;
-        bool HasStencil() const;
-        bool HasDepthOrStencil() const;
-    };
-
-    // Returns the Format corresponding to the dawn::TextureFormat or an error if the format
-    // isn't valid.
-    ResultOrError<Format> ConvertFormat(dawn::TextureFormat format);
-
-    // Returns the Format corresponding to the dawn::TextureFormat and assumes the format is valid.
-    Format ConvertValidFormat(dawn::TextureFormat format);
-
     class TextureBase : public ObjectBase {
       public:
         enum class TextureState { OwnedInternal, OwnedExternal, Destroyed };
@@ -122,7 +93,7 @@
         MaybeError ValidateDestroy() const;
         dawn::TextureDimension mDimension;
         // TODO(cwallez@chromium.org): This should be deduplicated in the Device
-        Format mFormat;
+        const Format& mFormat;
         Extent3D mSize;
         uint32_t mArrayLayerCount;
         uint32_t mMipLevelCount;
@@ -155,7 +126,7 @@
         Ref<TextureBase> mTexture;
 
         // TODO(cwallez@chromium.org): This should be deduplicated in the Device
-        Format mFormat;
+        const Format& mFormat;
         uint32_t mBaseMipLevel;
         uint32_t mMipLevelCount;
         uint32_t mBaseArrayLayer;
diff --git a/src/dawn_native/d3d12/TextureCopySplitter.cpp b/src/dawn_native/d3d12/TextureCopySplitter.cpp
index aa76517..c206fe2 100644
--- a/src/dawn_native/d3d12/TextureCopySplitter.cpp
+++ b/src/dawn_native/d3d12/TextureCopySplitter.cpp
@@ -15,12 +15,13 @@
 #include "dawn_native/d3d12/TextureCopySplitter.h"
 
 #include "common/Assert.h"
+#include "dawn_native/Format.h"
 #include "dawn_native/d3d12/d3d12_platform.h"
 
 namespace dawn_native { namespace d3d12 {
 
     namespace {
-        Origin3D ComputeTexelOffsets(Format format,
+        Origin3D ComputeTexelOffsets(const Format& format,
                                      uint32_t offset,
                                      uint32_t rowPitch,
                                      uint32_t slicePitch) {
@@ -36,7 +37,7 @@
 
     TextureCopySplit ComputeTextureCopySplit(Origin3D origin,
                                              Extent3D copySize,
-                                             Format format,
+                                             const Format& format,
                                              uint64_t offset,
                                              uint32_t rowPitch,
                                              uint32_t imageHeight) {
diff --git a/src/dawn_native/d3d12/TextureCopySplitter.h b/src/dawn_native/d3d12/TextureCopySplitter.h
index 540702f..0e06ebd 100644
--- a/src/dawn_native/d3d12/TextureCopySplitter.h
+++ b/src/dawn_native/d3d12/TextureCopySplitter.h
@@ -15,11 +15,16 @@
 #ifndef DAWNNATIVE_D3D12_TEXTURECOPYSPLITTER_H_
 #define DAWNNATIVE_D3D12_TEXTURECOPYSPLITTER_H_
 
-#include "dawn_native/Texture.h"
 #include "dawn_native/dawn_platform.h"
 
 #include <array>
 
+namespace dawn_native {
+
+    struct Format;
+
+}  // namespace dawn_native
+
 namespace dawn_native { namespace d3d12 {
 
     struct TextureCopySplit {
@@ -40,7 +45,7 @@
 
     TextureCopySplit ComputeTextureCopySplit(Origin3D origin,
                                              Extent3D copySize,
-                                             Format format,
+                                             const Format& format,
                                              uint64_t offset,
                                              uint32_t rowPitch,
                                              uint32_t imageHeight);
diff --git a/src/dawn_native/vulkan/NativeSwapChainImplVk.cpp b/src/dawn_native/vulkan/NativeSwapChainImplVk.cpp
index 95b53e5..0b037db 100644
--- a/src/dawn_native/vulkan/NativeSwapChainImplVk.cpp
+++ b/src/dawn_native/vulkan/NativeSwapChainImplVk.cpp
@@ -93,7 +93,7 @@
         createInfo.imageExtent.height = height;
         createInfo.imageArrayLayers = 1;
         createInfo.imageUsage = VulkanImageUsage(static_cast<dawn::TextureUsageBit>(usage),
-                                                 ConvertValidFormat(mConfig.format));
+                                                 mDevice->GetValidInternalFormat(mConfig.format));
         createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
         createInfo.queueFamilyIndexCount = 0;
         createInfo.pQueueFamilyIndices = nullptr;
diff --git a/src/tests/unittests/d3d12/CopySplitTests.cpp b/src/tests/unittests/d3d12/CopySplitTests.cpp
index 527ee07..da703a0 100644
--- a/src/tests/unittests/d3d12/CopySplitTests.cpp
+++ b/src/tests/unittests/d3d12/CopySplitTests.cpp
@@ -17,7 +17,7 @@
 #include "common/Assert.h"
 #include "common/Constants.h"
 #include "common/Math.h"
-#include "dawn_native/Texture.h"
+#include "dawn_native/Format.h"
 #include "dawn_native/d3d12/TextureCopySplitter.h"
 #include "dawn_native/d3d12/d3d12_platform.h"