Support BC formats as the first extension in Dawn

This patch refactors the current implementation of BC formats to treat
it as the first extension in Dawn and adds all the related tests.

Note that in Dawn all the extensions are disabled unless we enable them
when we create the device, which means the BC formats can only be used
when we enable the related extension on the creation of the device, and
the creation of the device will fail if the adapter does not support the
extension

BUG=dawn:42
TEST=dawn_end2end_tests
TEST=dawn_unittests

Change-Id: I04d818b0218ebb3b1b7a70a4fea71779f308f85f
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/9520
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/src/dawn_native/Extensions.cpp b/src/dawn_native/Extensions.cpp
new file mode 100644
index 0000000..2de7a85
--- /dev/null
+++ b/src/dawn_native/Extensions.cpp
@@ -0,0 +1,113 @@
+// 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 <array>
+
+#include "common/Assert.h"
+#include "common/BitSetIterator.h"
+#include "dawn_native/Extensions.h"
+
+namespace dawn_native {
+    namespace {
+
+        struct ExtensionEnumAndInfo {
+            Extension extension;
+            ExtensionInfo info;
+        };
+
+        using ExtensionEnumAndInfoList =
+            std::array<ExtensionEnumAndInfo, static_cast<size_t>(Extension::EnumCount)>;
+
+        static constexpr ExtensionEnumAndInfoList kExtensionNameAndInfoList = {
+            {{Extension::TextureCompressionBC,
+              {"texture_compression_bc", "Support Block Compressed (BC) texture formats",
+               "https://bugs.chromium.org/p/dawn/issues/detail?id=42"}}}};
+
+    }  // anonymous namespace
+
+    void ExtensionsSet::EnableExtension(Extension extension) {
+        ASSERT(extension != Extension::InvalidEnum);
+        const size_t extensionIndex = static_cast<size_t>(extension);
+        extensionsBitSet.set(extensionIndex);
+    }
+
+    bool ExtensionsSet::IsEnabled(Extension extension) const {
+        ASSERT(extension != Extension::InvalidEnum);
+        const size_t extensionIndex = static_cast<size_t>(extension);
+        return extensionsBitSet[extensionIndex];
+    }
+
+    std::vector<const char*> ExtensionsSet::GetEnabledExtensionNames() const {
+        std::vector<const char*> enabledExtensionNames(extensionsBitSet.count());
+
+        uint32_t index = 0;
+        for (uint32_t i : IterateBitSet(extensionsBitSet)) {
+            const char* extensionName = ExtensionEnumToName(static_cast<Extension>(i));
+            enabledExtensionNames[index] = extensionName;
+            ++index;
+        }
+        return enabledExtensionNames;
+    }
+
+    const char* ExtensionEnumToName(Extension extension) {
+        ASSERT(extension != Extension::InvalidEnum);
+
+        const ExtensionEnumAndInfo& extensionNameAndInfo =
+            kExtensionNameAndInfoList[static_cast<size_t>(extension)];
+        ASSERT(extensionNameAndInfo.extension == extension);
+        return extensionNameAndInfo.info.name;
+    }
+
+    ExtensionsInfo::ExtensionsInfo() {
+        for (size_t index = 0; index < kExtensionNameAndInfoList.size(); ++index) {
+            const ExtensionEnumAndInfo& extensionNameAndInfo = kExtensionNameAndInfoList[index];
+            ASSERT(index == static_cast<size_t>(extensionNameAndInfo.extension));
+            mExtensionNameToEnumMap[extensionNameAndInfo.info.name] =
+                extensionNameAndInfo.extension;
+        }
+    }
+
+    const ExtensionInfo* ExtensionsInfo::GetExtensionInfo(const char* extensionName) const {
+        ASSERT(extensionName);
+
+        const auto& iter = mExtensionNameToEnumMap.find(extensionName);
+        if (iter != mExtensionNameToEnumMap.cend()) {
+            return &kExtensionNameAndInfoList[static_cast<size_t>(iter->second)].info;
+        }
+        return nullptr;
+    }
+
+    Extension ExtensionsInfo::ExtensionNameToEnum(const char* extensionName) const {
+        ASSERT(extensionName);
+
+        const auto& iter = mExtensionNameToEnumMap.find(extensionName);
+        if (iter != mExtensionNameToEnumMap.cend()) {
+            return kExtensionNameAndInfoList[static_cast<size_t>(iter->second)].extension;
+        }
+        return Extension::InvalidEnum;
+    }
+
+    ExtensionsSet ExtensionsInfo::ExtensionNamesToExtensionsSet(
+        const std::vector<const char*>& requiredExtensions) const {
+        ExtensionsSet extensionsSet;
+
+        for (const char* extensionName : requiredExtensions) {
+            Extension extensionEnum = ExtensionNameToEnum(extensionName);
+            ASSERT(extensionEnum != Extension::InvalidEnum);
+            extensionsSet.EnableExtension(extensionEnum);
+        }
+        return extensionsSet;
+    }
+
+}  // namespace dawn_native