1 // Copyright 2018 The Dawn Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "dawn_native/Instance.h" 16 17 #include "common/Assert.h" 18 #include "dawn_native/ErrorData.h" 19 20 #include <iostream> 21 22 namespace dawn_native { 23 24 // Forward definitions of each backend's "Connect" function that creates new BackendConnection. 25 // Conditionally compiled declarations are used to avoid using static constructors instead. 26 #if defined(DAWN_ENABLE_BACKEND_D3D12) 27 namespace d3d12 { 28 BackendConnection* Connect(InstanceBase* instance); 29 } 30 #endif // defined(DAWN_ENABLE_BACKEND_D3D12) 31 #if defined(DAWN_ENABLE_BACKEND_METAL) 32 namespace metal { 33 BackendConnection* Connect(InstanceBase* instance); 34 } 35 #endif // defined(DAWN_ENABLE_BACKEND_METAL) 36 #if defined(DAWN_ENABLE_BACKEND_NULL) 37 namespace null { 38 BackendConnection* Connect(InstanceBase* instance); 39 } 40 #endif // defined(DAWN_ENABLE_BACKEND_NULL) 41 #if defined(DAWN_ENABLE_BACKEND_OPENGL) 42 namespace opengl { 43 BackendConnection* Connect(InstanceBase* instance); 44 } 45 #endif // defined(DAWN_ENABLE_BACKEND_OPENGL) 46 #if defined(DAWN_ENABLE_BACKEND_VULKAN) 47 namespace vulkan { 48 BackendConnection* Connect(InstanceBase* instance); 49 } 50 #endif // defined(DAWN_ENABLE_BACKEND_VULKAN) 51 52 namespace { 53 54 struct ToggleEnumAndInfo { 55 Toggle toggle; 56 ToggleInfo info; 57 }; 58 59 using ToggleEnumAndInfoList = 60 std::array<ToggleEnumAndInfo, static_cast<size_t>(Toggle::EnumCount)>; 61 62 static constexpr ToggleEnumAndInfoList kToggleNameAndInfoList = { 63 {{Toggle::EmulateStoreAndMSAAResolve, 64 {"emulate_store_and_msaa_resolve", 65 "Emulate storing into multisampled color attachments and doing MSAA resolve " 66 "simultaneously. This workaround is enabled by default on the Metal drivers that do " 67 "not support MTLStoreActionStoreAndMultisampleResolve. To support StoreOp::Store on " 68 "those platforms, we should do MSAA resolve in another render pass after ending the " 69 "previous one.", 70 "https://bugs.chromium.org/p/dawn/issues/detail?id=56"}}, 71 {Toggle::NonzeroClearResourcesOnCreationForTesting, 72 {"nonzero_clear_resources_on_creation_for_testing", 73 "Clears texture to full 1 bits as soon as they are created, but doesn't update " 74 "the tracking state of the texture. This way we can test the logic of clearing " 75 "textures that use recycled memory.", 76 "https://bugs.chromium.org/p/dawn/issues/detail?id=145"}}, 77 {Toggle::AlwaysResolveIntoZeroLevelAndLayer, 78 {"always_resolve_into_zero_level_and_layer", 79 "When the resolve target is a texture view that is created on the non-zero level or " 80 "layer of a texture, we first resolve into a temporarily 2D texture with only one " 81 "mipmap level and one array layer, and copy the result of MSAA resolve into the " 82 "true resolve target. This workaround is enabled by default on the Metal drivers " 83 "that have bugs when setting non-zero resolveLevel or resolveSlice.", 84 "https://bugs.chromium.org/p/dawn/issues/detail?id=56"}}, 85 {Toggle::LazyClearResourceOnFirstUse, 86 {"lazy_clear_resource_on_first_use", 87 "Clears resource to zero on first usage. This initializes the resource " 88 "so that no dirty bits from recycled memory is present in the new resource.", 89 "https://bugs.chromium.org/p/dawn/issues/detail?id=145"}}}}; 90 91 } // anonymous namespace 92 93 // InstanceBase 94 DiscoverDefaultAdapters()95 void InstanceBase::DiscoverDefaultAdapters() { 96 EnsureBackendConnections(); 97 98 if (mDiscoveredDefaultAdapters) { 99 return; 100 } 101 102 // Query and merge all default adapters for all backends 103 for (std::unique_ptr<BackendConnection>& backend : mBackends) { 104 std::vector<std::unique_ptr<AdapterBase>> backendAdapters = 105 backend->DiscoverDefaultAdapters(); 106 107 for (std::unique_ptr<AdapterBase>& adapter : backendAdapters) { 108 ASSERT(adapter->GetBackendType() == backend->GetType()); 109 ASSERT(adapter->GetInstance() == this); 110 mAdapters.push_back(std::move(adapter)); 111 } 112 } 113 114 mDiscoveredDefaultAdapters = true; 115 } 116 117 // This is just a wrapper around the real logic that uses Error.h error handling. DiscoverAdapters(const AdapterDiscoveryOptionsBase * options)118 bool InstanceBase::DiscoverAdapters(const AdapterDiscoveryOptionsBase* options) { 119 return !ConsumedError(DiscoverAdaptersInternal(options)); 120 } 121 ToggleEnumToName(Toggle toggle)122 const char* InstanceBase::ToggleEnumToName(Toggle toggle) { 123 ASSERT(toggle != Toggle::InvalidEnum); 124 125 const ToggleEnumAndInfo& toggleNameAndInfo = 126 kToggleNameAndInfoList[static_cast<size_t>(toggle)]; 127 ASSERT(toggleNameAndInfo.toggle == toggle); 128 return toggleNameAndInfo.info.name; 129 } 130 GetToggleInfo(const char * toggleName)131 const ToggleInfo* InstanceBase::GetToggleInfo(const char* toggleName) { 132 ASSERT(toggleName); 133 134 EnsureToggleNameToEnumMapInitialized(); 135 136 const auto& iter = mToggleNameToEnumMap.find(toggleName); 137 if (iter != mToggleNameToEnumMap.cend()) { 138 return &kToggleNameAndInfoList[static_cast<size_t>(iter->second)].info; 139 } 140 return nullptr; 141 } 142 ToggleNameToEnum(const char * toggleName)143 Toggle InstanceBase::ToggleNameToEnum(const char* toggleName) { 144 ASSERT(toggleName); 145 146 EnsureToggleNameToEnumMapInitialized(); 147 148 const auto& iter = mToggleNameToEnumMap.find(toggleName); 149 if (iter != mToggleNameToEnumMap.cend()) { 150 return kToggleNameAndInfoList[static_cast<size_t>(iter->second)].toggle; 151 } 152 return Toggle::InvalidEnum; 153 } 154 EnsureToggleNameToEnumMapInitialized()155 void InstanceBase::EnsureToggleNameToEnumMapInitialized() { 156 if (mToggleNameToEnumMapInitialized) { 157 return; 158 } 159 160 for (size_t index = 0; index < kToggleNameAndInfoList.size(); ++index) { 161 const ToggleEnumAndInfo& toggleNameAndInfo = kToggleNameAndInfoList[index]; 162 ASSERT(index == static_cast<size_t>(toggleNameAndInfo.toggle)); 163 mToggleNameToEnumMap[toggleNameAndInfo.info.name] = toggleNameAndInfo.toggle; 164 } 165 166 mToggleNameToEnumMapInitialized = true; 167 } 168 GetAdapters() const169 const std::vector<std::unique_ptr<AdapterBase>>& InstanceBase::GetAdapters() const { 170 return mAdapters; 171 } 172 EnsureBackendConnections()173 void InstanceBase::EnsureBackendConnections() { 174 if (mBackendsConnected) { 175 return; 176 } 177 178 auto Register = [this](BackendConnection* connection, BackendType expectedType) { 179 if (connection != nullptr) { 180 ASSERT(connection->GetType() == expectedType); 181 ASSERT(connection->GetInstance() == this); 182 mBackends.push_back(std::unique_ptr<BackendConnection>(connection)); 183 } 184 }; 185 186 #if defined(DAWN_ENABLE_BACKEND_D3D12) 187 Register(d3d12::Connect(this), BackendType::D3D12); 188 #endif // defined(DAWN_ENABLE_BACKEND_D3D12) 189 #if defined(DAWN_ENABLE_BACKEND_METAL) 190 Register(metal::Connect(this), BackendType::Metal); 191 #endif // defined(DAWN_ENABLE_BACKEND_METAL) 192 #if defined(DAWN_ENABLE_BACKEND_VULKAN) 193 Register(vulkan::Connect(this), BackendType::Vulkan); 194 #endif // defined(DAWN_ENABLE_BACKEND_VULKAN) 195 #if defined(DAWN_ENABLE_BACKEND_OPENGL) 196 Register(opengl::Connect(this), BackendType::OpenGL); 197 #endif // defined(DAWN_ENABLE_BACKEND_OPENGL) 198 #if defined(DAWN_ENABLE_BACKEND_NULL) 199 Register(null::Connect(this), BackendType::Null); 200 #endif // defined(DAWN_ENABLE_BACKEND_NULL) 201 202 mBackendsConnected = true; 203 } 204 FindBackend(BackendType type)205 ResultOrError<BackendConnection*> InstanceBase::FindBackend(BackendType type) { 206 for (std::unique_ptr<BackendConnection>& backend : mBackends) { 207 if (backend->GetType() == type) { 208 return backend.get(); 209 } 210 } 211 212 return DAWN_VALIDATION_ERROR("Backend isn't present."); 213 } 214 DiscoverAdaptersInternal(const AdapterDiscoveryOptionsBase * options)215 MaybeError InstanceBase::DiscoverAdaptersInternal(const AdapterDiscoveryOptionsBase* options) { 216 EnsureBackendConnections(); 217 218 BackendConnection* backend; 219 DAWN_TRY_ASSIGN(backend, FindBackend(options->backendType)); 220 221 std::vector<std::unique_ptr<AdapterBase>> newAdapters; 222 DAWN_TRY_ASSIGN(newAdapters, backend->DiscoverAdapters(options)); 223 224 for (std::unique_ptr<AdapterBase>& adapter : newAdapters) { 225 ASSERT(adapter->GetBackendType() == backend->GetType()); 226 ASSERT(adapter->GetInstance() == this); 227 mAdapters.push_back(std::move(adapter)); 228 } 229 230 return {}; 231 } 232 ConsumedError(MaybeError maybeError)233 bool InstanceBase::ConsumedError(MaybeError maybeError) { 234 if (maybeError.IsError()) { 235 ErrorData* error = maybeError.AcquireError(); 236 237 ASSERT(error != nullptr); 238 std::cout << error->GetMessage() << std::endl; 239 delete error; 240 241 return true; 242 } 243 return false; 244 } 245 EnableBackendValidation(bool enableBackendValidation)246 void InstanceBase::EnableBackendValidation(bool enableBackendValidation) { 247 mEnableBackendValidation = enableBackendValidation; 248 } 249 IsBackendValidationEnabled() const250 bool InstanceBase::IsBackendValidationEnabled() const { 251 return mEnableBackendValidation; 252 } 253 EnableBeginCaptureOnStartup(bool beginCaptureOnStartup)254 void InstanceBase::EnableBeginCaptureOnStartup(bool beginCaptureOnStartup) { 255 mBeginCaptureOnStartup = beginCaptureOnStartup; 256 } 257 IsBeginCaptureOnStartupEnabled() const258 bool InstanceBase::IsBeginCaptureOnStartupEnabled() const { 259 return mBeginCaptureOnStartup; 260 } 261 262 } // namespace dawn_native 263