Emulate store and multisample resolve on Metal

This patch implements "store and MSAA resolve" store operation on Metal
drivers that don't support MTLStoreActionStoreAndMultisampleResolve with
a workaround that does MSAA resolve in another render pass.

Driver workaround is one type of Dawn Toggles. Dawn Toggles will include
other optional optimizations and features that can be configured to use
or not when we create Dawn Devices.

As all Metal try bots don't need this toggle, to better test this
patch on the try bots:
1. We add the support of forcing enabling a workaround when starting an
   Dawn end2end test so that we can test the workaround on the platforms
   where the workaround is disabled.
2. We add an optional parameter DeviceDescriptor to CreateDevice() so
   that we can custom the toggles the Dawn device should use.

This patch also adds the support of querying toggle details from Instance
and the names of the toggles in use from Device. These APIs are tested in
the Dawn unittests added in this patch.

BUG=dawn:56
TEST=dawn_end2end_tests
TEST=dawn_unittests

Change-Id: Iae31d2ded6057eee638b6099d3061e9d78b04d55
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/6620
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
diff --git a/src/dawn_native/Device.cpp b/src/dawn_native/Device.cpp
index 44be88a..b7aa559 100644
--- a/src/dawn_native/Device.cpp
+++ b/src/dawn_native/Device.cpp
@@ -25,6 +25,7 @@
 #include "dawn_native/ErrorData.h"
 #include "dawn_native/Fence.h"
 #include "dawn_native/FenceSignalTracker.h"
+#include "dawn_native/Instance.h"
 #include "dawn_native/PipelineLayout.h"
 #include "dawn_native/Queue.h"
 #include "dawn_native/RenderPipeline.h"
@@ -50,7 +51,8 @@
 
     // DeviceBase
 
-    DeviceBase::DeviceBase(AdapterBase* adapter) : mAdapter(adapter) {
+    DeviceBase::DeviceBase(AdapterBase* adapter, const DeviceDescriptor* descriptor)
+        : mAdapter(adapter) {
         mCaches = std::make_unique<DeviceBase::Caches>();
         mFenceSignalTracker = std::make_unique<FenceSignalTracker>(this);
         mDynamicUploader = std::make_unique<DynamicUploader>(this);
@@ -257,6 +259,42 @@
         }
     }
 
+    void DeviceBase::ApplyToggleOverrides(const DeviceDescriptor* deviceDescriptor) {
+        ASSERT(deviceDescriptor);
+
+        for (const char* toggleName : deviceDescriptor->forceEnabledToggles) {
+            Toggle toggle = GetAdapter()->GetInstance()->ToggleNameToEnum(toggleName);
+            if (toggle != Toggle::InvalidEnum) {
+                mTogglesSet.SetToggle(toggle, true);
+            }
+        }
+
+        for (const char* toggleName : deviceDescriptor->forceDisabledToggles) {
+            Toggle toggle = GetAdapter()->GetInstance()->ToggleNameToEnum(toggleName);
+            if (toggle != Toggle::InvalidEnum) {
+                mTogglesSet.SetToggle(toggle, false);
+            }
+        }
+    }
+
+    std::vector<const char*> DeviceBase::GetTogglesUsed() const {
+        std::vector<const char*> togglesNameInUse(mTogglesSet.toggleBitset.count());
+
+        uint32_t index = 0;
+        for (uint32_t i : IterateBitSet(mTogglesSet.toggleBitset)) {
+            const char* toggleName =
+                GetAdapter()->GetInstance()->ToggleEnumToName(static_cast<Toggle>(i));
+            togglesNameInUse[index] = toggleName;
+            ++index;
+        }
+
+        return togglesNameInUse;
+    }
+
+    bool DeviceBase::IsToggleEnabled(Toggle toggle) const {
+        return mTogglesSet.IsEnabled(toggle);
+    }
+
     // Implementation details of object creation
 
     MaybeError DeviceBase::CreateBindGroupInternal(BindGroupBase** result,
@@ -361,4 +399,8 @@
         return mDynamicUploader.get();
     }
 
+    void DeviceBase::SetToggle(Toggle toggle, bool isEnabled) {
+        mTogglesSet.SetToggle(toggle, isEnabled);
+    }
+
 }  // namespace dawn_native