• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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