1 | // Copyright (c) 2017-2023, The Khronos Group Inc. |
2 | // Copyright (c) 2017-2019 Valve Corporation |
3 | // Copyright (c) 2017-2019 LunarG, Inc. |
4 | // |
5 | // SPDX-License-Identifier: Apache-2.0 OR MIT |
6 | // |
7 | // Initial Authors: Mark Young <marky@lunarg.com>, Dave Houlton <daveh@lunarg.com> |
8 | // |
9 | |
10 | #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) |
11 | #define _CRT_SECURE_NO_WARNINGS |
12 | #endif // defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) |
13 | |
14 | #include "api_layer_interface.hpp" |
15 | #include "exception_handling.hpp" |
16 | #include "hex_and_handles.h" |
17 | #include "loader_instance.hpp" |
18 | #include "loader_logger_recorders.hpp" |
19 | #include "loader_logger.hpp" |
20 | #include "loader_platform.hpp" |
21 | #include "runtime_interface.hpp" |
22 | #include "xr_generated_dispatch_table.h" |
23 | #include "xr_generated_loader.hpp" |
24 | |
25 | #include <openxr/openxr.h> |
26 | |
27 | #include <cstring> |
28 | #include <memory> |
29 | #include <mutex> |
30 | #include <sstream> |
31 | #include <string> |
32 | #include <utility> |
33 | #include <vector> |
34 | |
35 | // Global loader lock to: |
36 | // 1. Ensure ActiveLoaderInstance get and set operations are done atomically. |
37 | // 2. Ensure RuntimeInterface isn't used to unload the runtime while the runtime is in use. |
38 | static std::mutex &GetGlobalLoaderMutex() { |
39 | static std::mutex loader_mutex; |
40 | return loader_mutex; |
41 | } |
42 | |
43 | // Prototypes for the debug utils calls used internally. |
44 | static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineCreateDebugUtilsMessengerEXT( |
45 | XrInstance instance, const XrDebugUtilsMessengerCreateInfoEXT *createInfo, XrDebugUtilsMessengerEXT *messenger); |
46 | static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger); |
47 | |
48 | // Terminal functions needed by xrCreateInstance. |
49 | static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermGetInstanceProcAddr(XrInstance, const char *, PFN_xrVoidFunction *); |
50 | static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateInstance(const XrInstanceCreateInfo *, XrInstance *); |
51 | static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateApiLayerInstance(const XrInstanceCreateInfo *, |
52 | const struct XrApiLayerCreateInfo *, XrInstance *); |
53 | static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermSetDebugUtilsObjectNameEXT(XrInstance, const XrDebugUtilsObjectNameInfoEXT *); |
54 | static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateDebugUtilsMessengerEXT(XrInstance, |
55 | const XrDebugUtilsMessengerCreateInfoEXT *, |
56 | XrDebugUtilsMessengerEXT *); |
57 | static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT); |
58 | static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermSubmitDebugUtilsMessageEXT( |
59 | XrInstance instance, XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, XrDebugUtilsMessageTypeFlagsEXT messageTypes, |
60 | const XrDebugUtilsMessengerCallbackDataEXT *callbackData); |
61 | static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrGetInstanceProcAddr(XrInstance instance, const char *name, |
62 | PFN_xrVoidFunction *function); |
63 | |
64 | // Utility template function meant to validate if a fixed size string contains |
65 | // a null-terminator. |
66 | template <size_t max_length> |
67 | inline bool IsMissingNullTerminator(const char (&str)[max_length]) { |
68 | for (size_t index = 0; index < max_length; ++index) { |
69 | if (str[index] == '\0') { |
70 | return false; |
71 | } |
72 | } |
73 | return true; |
74 | } |
75 | |
76 | // ---- Core 1.0 manual loader trampoline functions |
77 | #ifdef XR_KHR_LOADER_INIT_SUPPORT // platforms that support XR_KHR_loader_init. |
78 | XRAPI_ATTR XrResult XRAPI_CALL LoaderXrInitializeLoaderKHR(const XrLoaderInitInfoBaseHeaderKHR *loaderInitInfo) XRLOADER_ABI_TRY { |
79 | LoaderLogger::LogVerboseMessage("xrInitializeLoaderKHR" , "Entering loader trampoline" ); |
80 | return InitializeLoader(loaderInitInfo); |
81 | } |
82 | XRLOADER_ABI_CATCH_FALLBACK |
83 | #endif |
84 | |
85 | static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrEnumerateApiLayerProperties(uint32_t propertyCapacityInput, |
86 | uint32_t *propertyCountOutput, |
87 | XrApiLayerProperties *properties) XRLOADER_ABI_TRY { |
88 | LoaderLogger::LogVerboseMessage("xrEnumerateApiLayerProperties" , "Entering loader trampoline" ); |
89 | |
90 | // Make sure only one thread is attempting to read the JSON files at a time. |
91 | std::unique_lock<std::mutex> loader_lock(GetGlobalLoaderMutex()); |
92 | |
93 | XrResult result = ApiLayerInterface::GetApiLayerProperties("xrEnumerateApiLayerProperties" , propertyCapacityInput, |
94 | propertyCountOutput, properties); |
95 | if (XR_FAILED(result)) { |
96 | LoaderLogger::LogErrorMessage("xrEnumerateApiLayerProperties" , "Failed ApiLayerInterface::GetApiLayerProperties" ); |
97 | } |
98 | |
99 | return result; |
100 | } |
101 | XRLOADER_ABI_CATCH_FALLBACK |
102 | |
103 | static XRAPI_ATTR XrResult XRAPI_CALL |
104 | LoaderXrEnumerateInstanceExtensionProperties(const char *layerName, uint32_t propertyCapacityInput, uint32_t *propertyCountOutput, |
105 | XrExtensionProperties *properties) XRLOADER_ABI_TRY { |
106 | bool just_layer_properties = false; |
107 | LoaderLogger::LogVerboseMessage("xrEnumerateInstanceExtensionProperties" , "Entering loader trampoline" ); |
108 | |
109 | // "Independent of elementCapacityInput or elements parameters, elementCountOutput must be a valid pointer, |
110 | // and the function sets elementCountOutput." - 2.11 |
111 | if (nullptr == propertyCountOutput) { |
112 | return XR_ERROR_VALIDATION_FAILURE; |
113 | } |
114 | |
115 | if (nullptr != layerName && 0 != strlen(layerName)) { |
116 | // Application is only interested in layer's properties, not all of them. |
117 | just_layer_properties = true; |
118 | } |
119 | |
120 | std::vector<XrExtensionProperties> extension_properties = {}; |
121 | XrResult result; |
122 | |
123 | { |
124 | // Make sure the runtime isn't unloaded while this call is in progress. |
125 | std::unique_lock<std::mutex> loader_lock(GetGlobalLoaderMutex()); |
126 | |
127 | // Get the layer extension properties |
128 | result = ApiLayerInterface::GetInstanceExtensionProperties("xrEnumerateInstanceExtensionProperties" , layerName, |
129 | extension_properties); |
130 | if (XR_SUCCEEDED(result) && !just_layer_properties) { |
131 | // If not specific to a layer, get the runtime extension properties |
132 | result = RuntimeInterface::LoadRuntime("xrEnumerateInstanceExtensionProperties" ); |
133 | if (XR_SUCCEEDED(result)) { |
134 | RuntimeInterface::GetRuntime().GetInstanceExtensionProperties(extension_properties); |
135 | } else { |
136 | LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties" , |
137 | "Failed to find default runtime with RuntimeInterface::LoadRuntime()" ); |
138 | } |
139 | } |
140 | } |
141 | |
142 | if (XR_FAILED(result)) { |
143 | LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties" , "Failed querying extension properties" ); |
144 | return result; |
145 | } |
146 | |
147 | // If this is not in reference to a specific layer, then add the loader-specific extension properties as well. |
148 | // These are extensions that the loader directly supports. |
149 | if (!just_layer_properties) { |
150 | for (const XrExtensionProperties &loader_prop : LoaderInstance::LoaderSpecificExtensions()) { |
151 | bool found_prop = false; |
152 | for (XrExtensionProperties &existing_prop : extension_properties) { |
153 | if (0 == strcmp(existing_prop.extensionName, loader_prop.extensionName)) { |
154 | found_prop = true; |
155 | // Use the loader version if it is newer |
156 | if (existing_prop.extensionVersion < loader_prop.extensionVersion) { |
157 | existing_prop.extensionVersion = loader_prop.extensionVersion; |
158 | } |
159 | break; |
160 | } |
161 | } |
162 | // Only add extensions not supported by the loader |
163 | if (!found_prop) { |
164 | extension_properties.push_back(loader_prop); |
165 | } |
166 | } |
167 | } |
168 | |
169 | auto num_extension_properties = static_cast<uint32_t>(extension_properties.size()); |
170 | if (propertyCapacityInput == 0) { |
171 | *propertyCountOutput = num_extension_properties; |
172 | } else if (nullptr != properties) { |
173 | if (propertyCapacityInput < num_extension_properties) { |
174 | *propertyCountOutput = num_extension_properties; |
175 | LoaderLogger::LogValidationErrorMessage("VUID-xrEnumerateInstanceExtensionProperties-propertyCountOutput-parameter" , |
176 | "xrEnumerateInstanceExtensionProperties" , "insufficient space in array" ); |
177 | return XR_ERROR_SIZE_INSUFFICIENT; |
178 | } |
179 | |
180 | uint32_t num_to_copy = num_extension_properties; |
181 | // Determine how many extension properties we can copy over |
182 | if (propertyCapacityInput < num_to_copy) { |
183 | num_to_copy = propertyCapacityInput; |
184 | } |
185 | bool properties_valid = true; |
186 | for (uint32_t prop = 0; prop < propertyCapacityInput && prop < extension_properties.size(); ++prop) { |
187 | if (XR_TYPE_EXTENSION_PROPERTIES != properties[prop].type) { |
188 | properties_valid = false; |
189 | LoaderLogger::LogValidationErrorMessage("VUID-XrExtensionProperties-type-type" , |
190 | "xrEnumerateInstanceExtensionProperties" , "unknown type in properties" ); |
191 | } |
192 | if (properties_valid) { |
193 | properties[prop] = extension_properties[prop]; |
194 | } |
195 | } |
196 | if (!properties_valid) { |
197 | LoaderLogger::LogValidationErrorMessage("VUID-xrEnumerateInstanceExtensionProperties-properties-parameter" , |
198 | "xrEnumerateInstanceExtensionProperties" , "invalid properties" ); |
199 | return XR_ERROR_VALIDATION_FAILURE; |
200 | } |
201 | if (nullptr != propertyCountOutput) { |
202 | *propertyCountOutput = num_to_copy; |
203 | } |
204 | } else { |
205 | // incoming_count is not 0 BUT the properties is NULL |
206 | return XR_ERROR_VALIDATION_FAILURE; |
207 | } |
208 | LoaderLogger::LogVerboseMessage("xrEnumerateInstanceExtensionProperties" , "Completed loader trampoline" ); |
209 | return XR_SUCCESS; |
210 | } |
211 | XRLOADER_ABI_CATCH_FALLBACK |
212 | |
213 | static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrCreateInstance(const XrInstanceCreateInfo *info, |
214 | XrInstance *instance) XRLOADER_ABI_TRY { |
215 | LoaderLogger::LogVerboseMessage("xrCreateInstance" , "Entering loader trampoline" ); |
216 | if (nullptr == info) { |
217 | LoaderLogger::LogValidationErrorMessage("VUID-xrCreateInstance-info-parameter" , "xrCreateInstance" , "must be non-NULL" ); |
218 | return XR_ERROR_VALIDATION_FAILURE; |
219 | } |
220 | // If application requested OpenXR API version is higher than the loader version, then we need to throw |
221 | // an error. |
222 | uint16_t app_major = XR_VERSION_MAJOR(info->applicationInfo.apiVersion); // NOLINT |
223 | uint16_t app_minor = XR_VERSION_MINOR(info->applicationInfo.apiVersion); // NOLINT |
224 | uint16_t loader_major = XR_VERSION_MAJOR(XR_CURRENT_API_VERSION); // NOLINT |
225 | uint16_t loader_minor = XR_VERSION_MINOR(XR_CURRENT_API_VERSION); // NOLINT |
226 | if (app_major > loader_major || (app_major == loader_major && app_minor > loader_minor)) { |
227 | std::ostringstream oss; |
228 | oss << "xrCreateInstance called with invalid API version " << app_major << "." << app_minor |
229 | << ". Max supported version is " << loader_major << "." << loader_minor; |
230 | LoaderLogger::LogErrorMessage("xrCreateInstance" , oss.str()); |
231 | return XR_ERROR_API_VERSION_UNSUPPORTED; |
232 | } |
233 | |
234 | if (nullptr == instance) { |
235 | LoaderLogger::LogValidationErrorMessage("VUID-xrCreateInstance-instance-parameter" , "xrCreateInstance" , "must be non-NULL" ); |
236 | return XR_ERROR_VALIDATION_FAILURE; |
237 | } |
238 | |
239 | // Make sure the ActiveLoaderInstance::IsAvailable check is done atomically with RuntimeInterface::LoadRuntime. |
240 | std::unique_lock<std::mutex> instance_lock(GetGlobalLoaderMutex()); |
241 | |
242 | // Check if there is already an XrInstance that is alive. If so, another instance cannot be created. |
243 | // The loader does not support multiple simultaneous instances because the loader is intended to be |
244 | // usable by apps using future OpenXR APIs (through xrGetInstanceProcAddr). Because the loader would |
245 | // not be aware of new handle types, it would not be able to look up the appropriate dispatch table |
246 | // in some cases. |
247 | if (ActiveLoaderInstance::IsAvailable()) { // If there is an XrInstance already alive. |
248 | LoaderLogger::LogErrorMessage("xrCreateInstance" , "Loader does not support simultaneous XrInstances" ); |
249 | return XR_ERROR_LIMIT_REACHED; |
250 | } |
251 | |
252 | std::vector<std::unique_ptr<ApiLayerInterface>> api_layer_interfaces; |
253 | XrResult result; |
254 | |
255 | // Make sure only one thread is attempting to read the JSON files and use the instance. |
256 | { |
257 | // Load the available runtime |
258 | result = RuntimeInterface::LoadRuntime("xrCreateInstance" ); |
259 | if (XR_FAILED(result)) { |
260 | LoaderLogger::LogErrorMessage("xrCreateInstance" , "Failed loading runtime information" ); |
261 | } else { |
262 | // Load the appropriate layers |
263 | result = ApiLayerInterface::LoadApiLayers("xrCreateInstance" , info->enabledApiLayerCount, info->enabledApiLayerNames, |
264 | api_layer_interfaces); |
265 | if (XR_FAILED(result)) { |
266 | LoaderLogger::LogErrorMessage("xrCreateInstance" , "Failed loading layer information" ); |
267 | } |
268 | } |
269 | } |
270 | |
271 | // Create the loader instance (only send down first runtime interface) |
272 | LoaderInstance *loader_instance = nullptr; |
273 | if (XR_SUCCEEDED(result)) { |
274 | std::unique_ptr<LoaderInstance> owned_loader_instance; |
275 | result = LoaderInstance::CreateInstance(LoaderXrTermGetInstanceProcAddr, LoaderXrTermCreateInstance, |
276 | LoaderXrTermCreateApiLayerInstance, std::move(api_layer_interfaces), info, |
277 | &owned_loader_instance); |
278 | if (XR_SUCCEEDED(result)) { |
279 | loader_instance = owned_loader_instance.get(); |
280 | result = ActiveLoaderInstance::Set(std::move(owned_loader_instance), "xrCreateInstance" ); |
281 | } |
282 | } |
283 | |
284 | if (XR_SUCCEEDED(result)) { |
285 | // Create a debug utils messenger if the create structure is in the "next" chain |
286 | const auto * = reinterpret_cast<const XrBaseInStructure *>(info->next); |
287 | const XrDebugUtilsMessengerCreateInfoEXT *dbg_utils_create_info = nullptr; |
288 | while (next_header != nullptr) { |
289 | if (next_header->type == XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) { |
290 | LoaderLogger::LogInfoMessage("xrCreateInstance" , "Found XrDebugUtilsMessengerCreateInfoEXT in \'next\' chain." ); |
291 | dbg_utils_create_info = reinterpret_cast<const XrDebugUtilsMessengerCreateInfoEXT *>(next_header); |
292 | XrDebugUtilsMessengerEXT messenger; |
293 | result = LoaderTrampolineCreateDebugUtilsMessengerEXT(loader_instance->GetInstanceHandle(), dbg_utils_create_info, |
294 | &messenger); |
295 | if (XR_FAILED(result)) { |
296 | return XR_ERROR_VALIDATION_FAILURE; |
297 | } |
298 | loader_instance->SetDefaultDebugUtilsMessenger(messenger); |
299 | break; |
300 | } |
301 | next_header = reinterpret_cast<const XrBaseInStructure *>(next_header->next); |
302 | } |
303 | } |
304 | |
305 | if (XR_FAILED(result)) { |
306 | // Ensure the global loader instance and runtime are destroyed if something went wrong. |
307 | ActiveLoaderInstance::Remove(); |
308 | RuntimeInterface::UnloadRuntime("xrCreateInstance" ); |
309 | LoaderLogger::LogErrorMessage("xrCreateInstance" , "xrCreateInstance failed" ); |
310 | } else { |
311 | *instance = loader_instance->GetInstanceHandle(); |
312 | LoaderLogger::LogVerboseMessage("xrCreateInstance" , "Completed loader trampoline" ); |
313 | } |
314 | |
315 | return result; |
316 | } |
317 | XRLOADER_ABI_CATCH_FALLBACK |
318 | |
319 | static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrDestroyInstance(XrInstance instance) XRLOADER_ABI_TRY { |
320 | LoaderLogger::LogVerboseMessage("xrDestroyInstance" , "Entering loader trampoline" ); |
321 | // Runtimes may detect XR_NULL_HANDLE provided as a required handle parameter and return XR_ERROR_HANDLE_INVALID. - 2.9 |
322 | if (XR_NULL_HANDLE == instance) { |
323 | LoaderLogger::LogErrorMessage("xrDestroyInstance" , "Instance handle is XR_NULL_HANDLE." ); |
324 | return XR_ERROR_HANDLE_INVALID; |
325 | } |
326 | |
327 | // Make sure the runtime isn't unloaded while it is being used by xrEnumerateInstanceExtensionProperties. |
328 | std::unique_lock<std::mutex> loader_lock(GetGlobalLoaderMutex()); |
329 | |
330 | LoaderInstance *loader_instance; |
331 | XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroyInstance" ); |
332 | if (XR_FAILED(result)) { |
333 | return result; |
334 | } |
335 | |
336 | const std::unique_ptr<XrGeneratedDispatchTable> &dispatch_table = loader_instance->DispatchTable(); |
337 | |
338 | // If we allocated a default debug utils messenger, free it |
339 | XrDebugUtilsMessengerEXT messenger = loader_instance->DefaultDebugUtilsMessenger(); |
340 | if (messenger != XR_NULL_HANDLE) { |
341 | LoaderTrampolineDestroyDebugUtilsMessengerEXT(messenger); |
342 | } |
343 | |
344 | // Now destroy the instance |
345 | if (XR_FAILED(dispatch_table->DestroyInstance(instance))) { |
346 | LoaderLogger::LogErrorMessage("xrDestroyInstance" , "Unknown error occurred calling down chain" ); |
347 | } |
348 | |
349 | // Get rid of the loader instance. This will make it possible to create another instance in the future. |
350 | ActiveLoaderInstance::Remove(); |
351 | |
352 | // Lock the instance create/destroy mutex |
353 | LoaderLogger::LogVerboseMessage("xrDestroyInstance" , "Completed loader trampoline" ); |
354 | |
355 | // Finally, unload the runtime if necessary |
356 | RuntimeInterface::UnloadRuntime("xrDestroyInstance" ); |
357 | |
358 | return XR_SUCCESS; |
359 | } |
360 | XRLOADER_ABI_CATCH_FALLBACK |
361 | |
362 | // ---- Core 1.0 manual loader terminator functions |
363 | |
364 | // Validate that the applicationInfo structure in the XrInstanceCreateInfo is valid. |
365 | static XrResult ValidateApplicationInfo(const XrApplicationInfo &info) { |
366 | if (IsMissingNullTerminator<XR_MAX_APPLICATION_NAME_SIZE>(info.applicationName)) { |
367 | LoaderLogger::LogValidationErrorMessage("VUID-XrApplicationInfo-applicationName-parameter" , "xrCreateInstance" , |
368 | "application name missing NULL terminator." ); |
369 | return XR_ERROR_NAME_INVALID; |
370 | } |
371 | if (IsMissingNullTerminator<XR_MAX_ENGINE_NAME_SIZE>(info.engineName)) { |
372 | LoaderLogger::LogValidationErrorMessage("VUID-XrApplicationInfo-engineName-parameter" , "xrCreateInstance" , |
373 | "engine name missing NULL terminator." ); |
374 | return XR_ERROR_NAME_INVALID; |
375 | } |
376 | if (strlen(info.applicationName) == 0) { |
377 | LoaderLogger::LogErrorMessage("xrCreateInstance" , |
378 | "VUID-XrApplicationInfo-engineName-parameter: application name can not be empty." ); |
379 | return XR_ERROR_NAME_INVALID; |
380 | } |
381 | return XR_SUCCESS; |
382 | } |
383 | |
384 | // Validate that the XrInstanceCreateInfo is valid |
385 | static XrResult ValidateInstanceCreateInfo(const XrInstanceCreateInfo *info) { |
386 | // Should have a valid 'type' |
387 | if (XR_TYPE_INSTANCE_CREATE_INFO != info->type) { |
388 | LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-type-type" , "xrCreateInstance" , |
389 | "expected XR_TYPE_INSTANCE_CREATE_INFO." ); |
390 | return XR_ERROR_VALIDATION_FAILURE; |
391 | } |
392 | // Flags must be 0 |
393 | if (0 != info->createFlags) { |
394 | LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-createFlags-zerobitmask" , "xrCreateInstance" , |
395 | "flags must be 0." ); |
396 | return XR_ERROR_VALIDATION_FAILURE; |
397 | } |
398 | // ApplicationInfo struct must be valid |
399 | XrResult result = ValidateApplicationInfo(info->applicationInfo); |
400 | if (XR_FAILED(result)) { |
401 | LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-applicationInfo-parameter" , "xrCreateInstance" , |
402 | "info->applicationInfo is not valid." ); |
403 | return result; |
404 | } |
405 | // VUID-XrInstanceCreateInfo-enabledApiLayerNames-parameter already tested in LoadApiLayers() |
406 | if ((info->enabledExtensionCount != 0u) && nullptr == info->enabledExtensionNames) { |
407 | LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-enabledExtensionNames-parameter" , "xrCreateInstance" , |
408 | "enabledExtensionCount is non-0 but array is NULL" ); |
409 | return XR_ERROR_VALIDATION_FAILURE; |
410 | } |
411 | return XR_SUCCESS; |
412 | } |
413 | |
414 | static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateInstance(const XrInstanceCreateInfo *createInfo, |
415 | XrInstance *instance) XRLOADER_ABI_TRY { |
416 | LoaderLogger::LogVerboseMessage("xrCreateInstance" , "Entering loader terminator" ); |
417 | XrResult result = ValidateInstanceCreateInfo(createInfo); |
418 | if (XR_FAILED(result)) { |
419 | LoaderLogger::LogValidationErrorMessage("VUID-xrCreateInstance-info-parameter" , "xrCreateInstance" , |
420 | "something wrong with XrInstanceCreateInfo contents" ); |
421 | return result; |
422 | } |
423 | result = RuntimeInterface::GetRuntime().CreateInstance(createInfo, instance); |
424 | LoaderLogger::LogVerboseMessage("xrCreateInstance" , "Completed loader terminator" ); |
425 | return result; |
426 | } |
427 | XRLOADER_ABI_CATCH_FALLBACK |
428 | |
429 | static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateApiLayerInstance(const XrInstanceCreateInfo *info, |
430 | const struct XrApiLayerCreateInfo * /*apiLayerInfo*/, |
431 | XrInstance *instance) { |
432 | return LoaderXrTermCreateInstance(info, instance); |
433 | } |
434 | |
435 | static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermDestroyInstance(XrInstance instance) XRLOADER_ABI_TRY { |
436 | LoaderLogger::LogVerboseMessage("xrDestroyInstance" , "Entering loader terminator" ); |
437 | LoaderLogger::GetInstance().RemoveLogRecordersForXrInstance(instance); |
438 | XrResult result = RuntimeInterface::GetRuntime().DestroyInstance(instance); |
439 | LoaderLogger::LogVerboseMessage("xrDestroyInstance" , "Completed loader terminator" ); |
440 | return result; |
441 | } |
442 | XRLOADER_ABI_CATCH_FALLBACK |
443 | |
444 | static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermGetInstanceProcAddr(XrInstance instance, const char *name, |
445 | PFN_xrVoidFunction *function) XRLOADER_ABI_TRY { |
446 | // A few instance commands need to go through a loader terminator. |
447 | // Otherwise, go directly to the runtime version of the command if it exists. |
448 | // But first set the function pointer to NULL so that the fall-through below actually works. |
449 | *function = nullptr; |
450 | |
451 | // NOTE: ActiveLoaderInstance cannot be used in this function because it is called before an instance is made active. |
452 | |
453 | if (0 == strcmp(name, "xrGetInstanceProcAddr" )) { |
454 | *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermGetInstanceProcAddr); |
455 | } else if (0 == strcmp(name, "xrCreateInstance" )) { |
456 | *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermCreateInstance); |
457 | } else if (0 == strcmp(name, "xrDestroyInstance" )) { |
458 | *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermDestroyInstance); |
459 | } else if (0 == strcmp(name, "xrSetDebugUtilsObjectNameEXT" )) { |
460 | *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermSetDebugUtilsObjectNameEXT); |
461 | } else if (0 == strcmp(name, "xrCreateDebugUtilsMessengerEXT" )) { |
462 | *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermCreateDebugUtilsMessengerEXT); |
463 | } else if (0 == strcmp(name, "xrDestroyDebugUtilsMessengerEXT" )) { |
464 | *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermDestroyDebugUtilsMessengerEXT); |
465 | } else if (0 == strcmp(name, "xrSubmitDebugUtilsMessageEXT" )) { |
466 | *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermSubmitDebugUtilsMessageEXT); |
467 | } else if (0 == strcmp(name, "xrCreateApiLayerInstance" )) { |
468 | // Special layer version of xrCreateInstance terminator. If we get called this by a layer, |
469 | // we simply re-direct the information back into the standard xrCreateInstance terminator. |
470 | *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermCreateApiLayerInstance); |
471 | } |
472 | |
473 | if (nullptr != *function) { |
474 | return XR_SUCCESS; |
475 | } |
476 | |
477 | return RuntimeInterface::GetInstanceProcAddr(instance, name, function); |
478 | } |
479 | XRLOADER_ABI_CATCH_FALLBACK |
480 | |
481 | // ---- Extension manual loader trampoline functions |
482 | |
483 | static XRAPI_ATTR XrResult XRAPI_CALL |
484 | LoaderTrampolineCreateDebugUtilsMessengerEXT(XrInstance instance, const XrDebugUtilsMessengerCreateInfoEXT *createInfo, |
485 | XrDebugUtilsMessengerEXT *messenger) XRLOADER_ABI_TRY { |
486 | LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT" , "Entering loader trampoline" ); |
487 | |
488 | if (instance == XR_NULL_HANDLE) { |
489 | LoaderLogger::LogErrorMessage("xrCreateDebugUtilsMessengerEXT" , "Instance handle is XR_NULL_HANDLE." ); |
490 | return XR_ERROR_HANDLE_INVALID; |
491 | } |
492 | |
493 | LoaderInstance *loader_instance; |
494 | XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrCreateDebugUtilsMessengerEXT" ); |
495 | if (XR_FAILED(result)) { |
496 | return result; |
497 | } |
498 | |
499 | result = loader_instance->DispatchTable()->CreateDebugUtilsMessengerEXT(instance, createInfo, messenger); |
500 | LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT" , "Completed loader trampoline" ); |
501 | return result; |
502 | } |
503 | XRLOADER_ABI_CATCH_BAD_ALLOC_OOM XRLOADER_ABI_CATCH_FALLBACK |
504 | |
505 | static XRAPI_ATTR XrResult XRAPI_CALL |
506 | LoaderTrampolineDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger) XRLOADER_ABI_TRY { |
507 | // TODO: get instance from messenger in loader |
508 | // Also, is the loader really doing all this every call? |
509 | LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT" , "Entering loader trampoline" ); |
510 | |
511 | if (messenger == XR_NULL_HANDLE) { |
512 | LoaderLogger::LogErrorMessage("xrDestroyDebugUtilsMessengerEXT" , "Messenger handle is XR_NULL_HANDLE." ); |
513 | return XR_ERROR_HANDLE_INVALID; |
514 | } |
515 | |
516 | LoaderInstance *loader_instance; |
517 | XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroyDebugUtilsMessengerEXT" ); |
518 | if (XR_FAILED(result)) { |
519 | return result; |
520 | } |
521 | |
522 | result = loader_instance->DispatchTable()->DestroyDebugUtilsMessengerEXT(messenger); |
523 | LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT" , "Completed loader trampoline" ); |
524 | return result; |
525 | } |
526 | XRLOADER_ABI_CATCH_FALLBACK |
527 | |
528 | static XRAPI_ATTR XrResult XRAPI_CALL |
529 | LoaderTrampolineSessionBeginDebugUtilsLabelRegionEXT(XrSession session, const XrDebugUtilsLabelEXT *labelInfo) XRLOADER_ABI_TRY { |
530 | if (session == XR_NULL_HANDLE) { |
531 | LoaderLogger::LogErrorMessage("xrSessionBeginDebugUtilsLabelRegionEXT" , "Session handle is XR_NULL_HANDLE." ); |
532 | return XR_ERROR_HANDLE_INVALID; |
533 | } |
534 | |
535 | if (nullptr == labelInfo) { |
536 | LoaderLogger::LogValidationErrorMessage("VUID-xrSessionBeginDebugUtilsLabelRegionEXT-labelInfo-parameter" , |
537 | "xrSessionBeginDebugUtilsLabelRegionEXT" , "labelInfo must be non-NULL" , |
538 | {XrSdkLogObjectInfo{session, XR_OBJECT_TYPE_SESSION}}); |
539 | return XR_ERROR_VALIDATION_FAILURE; |
540 | } |
541 | |
542 | LoaderInstance *loader_instance; |
543 | XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSessionBeginDebugUtilsLabelRegionEXT" ); |
544 | if (XR_FAILED(result)) { |
545 | return result; |
546 | } |
547 | LoaderLogger::GetInstance().BeginLabelRegion(session, labelInfo); |
548 | const std::unique_ptr<XrGeneratedDispatchTable> &dispatch_table = loader_instance->DispatchTable(); |
549 | if (nullptr != dispatch_table->SessionBeginDebugUtilsLabelRegionEXT) { |
550 | return dispatch_table->SessionBeginDebugUtilsLabelRegionEXT(session, labelInfo); |
551 | } |
552 | return XR_SUCCESS; |
553 | } |
554 | XRLOADER_ABI_CATCH_FALLBACK |
555 | |
556 | static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineSessionEndDebugUtilsLabelRegionEXT(XrSession session) XRLOADER_ABI_TRY { |
557 | if (session == XR_NULL_HANDLE) { |
558 | LoaderLogger::LogErrorMessage("xrSessionEndDebugUtilsLabelRegionEXT" , "Session handle is XR_NULL_HANDLE." ); |
559 | return XR_ERROR_HANDLE_INVALID; |
560 | } |
561 | |
562 | LoaderInstance *loader_instance; |
563 | XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSessionEndDebugUtilsLabelRegionEXT" ); |
564 | if (XR_FAILED(result)) { |
565 | return result; |
566 | } |
567 | |
568 | LoaderLogger::GetInstance().EndLabelRegion(session); |
569 | const std::unique_ptr<XrGeneratedDispatchTable> &dispatch_table = loader_instance->DispatchTable(); |
570 | if (nullptr != dispatch_table->SessionEndDebugUtilsLabelRegionEXT) { |
571 | return dispatch_table->SessionEndDebugUtilsLabelRegionEXT(session); |
572 | } |
573 | return XR_SUCCESS; |
574 | } |
575 | XRLOADER_ABI_CATCH_FALLBACK |
576 | |
577 | static XRAPI_ATTR XrResult XRAPI_CALL |
578 | LoaderTrampolineSessionInsertDebugUtilsLabelEXT(XrSession session, const XrDebugUtilsLabelEXT *labelInfo) XRLOADER_ABI_TRY { |
579 | if (session == XR_NULL_HANDLE) { |
580 | LoaderLogger::LogErrorMessage("xrSessionInsertDebugUtilsLabelEXT" , "Session handle is XR_NULL_HANDLE." ); |
581 | return XR_ERROR_HANDLE_INVALID; |
582 | } |
583 | |
584 | LoaderInstance *loader_instance; |
585 | XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSessionInsertDebugUtilsLabelEXT" ); |
586 | if (XR_FAILED(result)) { |
587 | return result; |
588 | } |
589 | |
590 | if (nullptr == labelInfo) { |
591 | LoaderLogger::LogValidationErrorMessage("VUID-xrSessionInsertDebugUtilsLabelEXT-labelInfo-parameter" , |
592 | "xrSessionInsertDebugUtilsLabelEXT" , "labelInfo must be non-NULL" , |
593 | {XrSdkLogObjectInfo{session, XR_OBJECT_TYPE_SESSION}}); |
594 | return XR_ERROR_VALIDATION_FAILURE; |
595 | } |
596 | |
597 | LoaderLogger::GetInstance().InsertLabel(session, labelInfo); |
598 | |
599 | const std::unique_ptr<XrGeneratedDispatchTable> &dispatch_table = loader_instance->DispatchTable(); |
600 | if (nullptr != dispatch_table->SessionInsertDebugUtilsLabelEXT) { |
601 | return dispatch_table->SessionInsertDebugUtilsLabelEXT(session, labelInfo); |
602 | } |
603 | |
604 | return XR_SUCCESS; |
605 | } |
606 | XRLOADER_ABI_CATCH_FALLBACK |
607 | |
608 | // No-op trampoline needed for xrGetInstanceProcAddr. Work done in terminator. |
609 | static XRAPI_ATTR XrResult XRAPI_CALL |
610 | LoaderTrampolineSetDebugUtilsObjectNameEXT(XrInstance instance, const XrDebugUtilsObjectNameInfoEXT *nameInfo) XRLOADER_ABI_TRY { |
611 | LoaderInstance *loader_instance; |
612 | XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSetDebugUtilsObjectNameEXT" ); |
613 | if (XR_SUCCEEDED(result)) { |
614 | result = loader_instance->DispatchTable()->SetDebugUtilsObjectNameEXT(instance, nameInfo); |
615 | } |
616 | return result; |
617 | } |
618 | XRLOADER_ABI_CATCH_FALLBACK |
619 | |
620 | // No-op trampoline needed for xrGetInstanceProcAddr. Work done in terminator. |
621 | static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineSubmitDebugUtilsMessageEXT( |
622 | XrInstance instance, XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, XrDebugUtilsMessageTypeFlagsEXT messageTypes, |
623 | const XrDebugUtilsMessengerCallbackDataEXT *callbackData) XRLOADER_ABI_TRY { |
624 | LoaderInstance *loader_instance; |
625 | XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSubmitDebugUtilsMessageEXT" ); |
626 | if (XR_SUCCEEDED(result)) { |
627 | result = |
628 | loader_instance->DispatchTable()->SubmitDebugUtilsMessageEXT(instance, messageSeverity, messageTypes, callbackData); |
629 | } |
630 | return result; |
631 | } |
632 | XRLOADER_ABI_CATCH_FALLBACK |
633 | |
634 | // ---- Extension manual loader terminator functions |
635 | |
636 | XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateDebugUtilsMessengerEXT(XrInstance instance, |
637 | const XrDebugUtilsMessengerCreateInfoEXT *createInfo, |
638 | XrDebugUtilsMessengerEXT *messenger) XRLOADER_ABI_TRY { |
639 | LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT" , "Entering loader terminator" ); |
640 | if (nullptr == messenger) { |
641 | LoaderLogger::LogValidationErrorMessage("VUID-xrCreateDebugUtilsMessengerEXT-messenger-parameter" , |
642 | "xrCreateDebugUtilsMessengerEXT" , "invalid messenger pointer" ); |
643 | return XR_ERROR_VALIDATION_FAILURE; |
644 | } |
645 | const XrGeneratedDispatchTable *dispatch_table = RuntimeInterface::GetDispatchTable(instance); |
646 | XrResult result = XR_SUCCESS; |
647 | // This extension is supported entirely by the loader which means the runtime may or may not support it. |
648 | if (nullptr != dispatch_table->CreateDebugUtilsMessengerEXT) { |
649 | result = dispatch_table->CreateDebugUtilsMessengerEXT(instance, createInfo, messenger); |
650 | } else { |
651 | // Just allocate a character so we have a unique value |
652 | char *temp_mess_ptr = new char; |
653 | *messenger = reinterpret_cast<XrDebugUtilsMessengerEXT>(temp_mess_ptr); |
654 | } |
655 | if (XR_SUCCEEDED(result)) { |
656 | LoaderLogger::GetInstance().AddLogRecorderForXrInstance(instance, MakeDebugUtilsLoaderLogRecorder(createInfo, *messenger)); |
657 | RuntimeInterface::GetRuntime().TrackDebugMessenger(instance, *messenger); |
658 | } |
659 | LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT" , "Completed loader terminator" ); |
660 | return result; |
661 | } |
662 | XRLOADER_ABI_CATCH_FALLBACK |
663 | |
664 | XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger) XRLOADER_ABI_TRY { |
665 | LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT" , "Entering loader terminator" ); |
666 | const XrGeneratedDispatchTable *dispatch_table = RuntimeInterface::GetDebugUtilsMessengerDispatchTable(messenger); |
667 | XrResult result = XR_SUCCESS; |
668 | LoaderLogger::GetInstance().RemoveLogRecorder(MakeHandleGeneric(messenger)); |
669 | RuntimeInterface::GetRuntime().ForgetDebugMessenger(messenger); |
670 | // This extension is supported entirely by the loader which means the runtime may or may not support it. |
671 | if (nullptr != dispatch_table->DestroyDebugUtilsMessengerEXT) { |
672 | result = dispatch_table->DestroyDebugUtilsMessengerEXT(messenger); |
673 | } else { |
674 | // Delete the character we would've created |
675 | delete (reinterpret_cast<char *>(MakeHandleGeneric(messenger))); |
676 | } |
677 | LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT" , "Completed loader terminator" ); |
678 | return result; |
679 | } |
680 | XRLOADER_ABI_CATCH_FALLBACK |
681 | |
682 | XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermSubmitDebugUtilsMessageEXT( |
683 | XrInstance instance, XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, XrDebugUtilsMessageTypeFlagsEXT messageTypes, |
684 | const XrDebugUtilsMessengerCallbackDataEXT *callbackData) XRLOADER_ABI_TRY { |
685 | LoaderLogger::LogVerboseMessage("xrSubmitDebugUtilsMessageEXT" , "Entering loader terminator" ); |
686 | const XrGeneratedDispatchTable *dispatch_table = RuntimeInterface::GetDispatchTable(instance); |
687 | XrResult result = XR_SUCCESS; |
688 | if (nullptr != dispatch_table->SubmitDebugUtilsMessageEXT) { |
689 | result = dispatch_table->SubmitDebugUtilsMessageEXT(instance, messageSeverity, messageTypes, callbackData); |
690 | } else { |
691 | // Only log the message from the loader if the runtime doesn't support this extension. If we did, |
692 | // then the user would receive multiple instances of the same message. |
693 | LoaderLogger::GetInstance().LogDebugUtilsMessage(messageSeverity, messageTypes, callbackData); |
694 | } |
695 | LoaderLogger::LogVerboseMessage("xrSubmitDebugUtilsMessageEXT" , "Completed loader terminator" ); |
696 | return result; |
697 | } |
698 | XRLOADER_ABI_CATCH_FALLBACK |
699 | |
700 | XRAPI_ATTR XrResult XRAPI_CALL |
701 | LoaderXrTermSetDebugUtilsObjectNameEXT(XrInstance instance, const XrDebugUtilsObjectNameInfoEXT *nameInfo) XRLOADER_ABI_TRY { |
702 | LoaderLogger::LogVerboseMessage("xrSetDebugUtilsObjectNameEXT" , "Entering loader terminator" ); |
703 | const XrGeneratedDispatchTable *dispatch_table = RuntimeInterface::GetDispatchTable(instance); |
704 | XrResult result = XR_SUCCESS; |
705 | if (nullptr != dispatch_table->SetDebugUtilsObjectNameEXT) { |
706 | result = dispatch_table->SetDebugUtilsObjectNameEXT(instance, nameInfo); |
707 | } |
708 | LoaderLogger::GetInstance().AddObjectName(nameInfo->objectHandle, nameInfo->objectType, nameInfo->objectName); |
709 | LoaderLogger::LogVerboseMessage("xrSetDebugUtilsObjectNameEXT" , "Completed loader terminator" ); |
710 | return result; |
711 | } |
712 | XRLOADER_ABI_CATCH_FALLBACK |
713 | |
714 | XRAPI_ATTR XrResult XRAPI_CALL LoaderXrGetInstanceProcAddr(XrInstance instance, const char *name, |
715 | PFN_xrVoidFunction *function) XRLOADER_ABI_TRY { |
716 | if (nullptr == function) { |
717 | LoaderLogger::LogValidationErrorMessage("VUID-xrGetInstanceProcAddr-function-parameter" , "xrGetInstanceProcAddr" , |
718 | "Invalid Function pointer" ); |
719 | return XR_ERROR_VALIDATION_FAILURE; |
720 | } |
721 | |
722 | if (nullptr == name) { |
723 | LoaderLogger::LogValidationErrorMessage("VUID-xrGetInstanceProcAddr-function-parameter" , "xrGetInstanceProcAddr" , |
724 | "Invalid Name pointer" ); |
725 | return XR_ERROR_VALIDATION_FAILURE; |
726 | } |
727 | |
728 | // Initialize the function to nullptr in case it does not get caught in a known case |
729 | *function = nullptr; |
730 | |
731 | LoaderInstance *loader_instance = nullptr; |
732 | if (instance == XR_NULL_HANDLE) { |
733 | // Null instance is allowed for a few specific API entry points, otherwise return error |
734 | if (strcmp(name, "xrCreateInstance" ) != 0 && strcmp(name, "xrEnumerateApiLayerProperties" ) != 0 && |
735 | strcmp(name, "xrEnumerateInstanceExtensionProperties" ) != 0 && strcmp(name, "xrInitializeLoaderKHR" ) != 0) { |
736 | // TODO why is xrGetInstanceProcAddr not listed in here? |
737 | std::string error_str = "XR_NULL_HANDLE for instance but query for " ; |
738 | error_str += name; |
739 | error_str += " requires a valid instance" ; |
740 | LoaderLogger::LogValidationErrorMessage("VUID-xrGetInstanceProcAddr-instance-parameter" , "xrGetInstanceProcAddr" , |
741 | error_str); |
742 | return XR_ERROR_HANDLE_INVALID; |
743 | } |
744 | } else { |
745 | // non null instance passed in, it should be our current instance |
746 | XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetInstanceProcAddr" ); |
747 | if (XR_FAILED(result)) { |
748 | return result; |
749 | } |
750 | if (loader_instance->GetInstanceHandle() != instance) { |
751 | return XR_ERROR_HANDLE_INVALID; |
752 | } |
753 | } |
754 | |
755 | // These functions must always go through the loader's implementation (trampoline). |
756 | if (strcmp(name, "xrGetInstanceProcAddr" ) == 0) { |
757 | *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrGetInstanceProcAddr); |
758 | return XR_SUCCESS; |
759 | } else if (strcmp(name, "xrInitializeLoaderKHR" ) == 0) { |
760 | #ifdef XR_KHR_LOADER_INIT_SUPPORT |
761 | *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrInitializeLoaderKHR); |
762 | return XR_SUCCESS; |
763 | #else |
764 | return XR_ERROR_FUNCTION_UNSUPPORTED; |
765 | #endif |
766 | } else if (strcmp(name, "xrEnumerateApiLayerProperties" ) == 0) { |
767 | *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrEnumerateApiLayerProperties); |
768 | return XR_SUCCESS; |
769 | } else if (strcmp(name, "xrEnumerateInstanceExtensionProperties" ) == 0) { |
770 | *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrEnumerateInstanceExtensionProperties); |
771 | return XR_SUCCESS; |
772 | } else if (strcmp(name, "xrCreateInstance" ) == 0) { |
773 | *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrCreateInstance); |
774 | return XR_SUCCESS; |
775 | } else if (strcmp(name, "xrDestroyInstance" ) == 0) { |
776 | *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrDestroyInstance); |
777 | return XR_SUCCESS; |
778 | } |
779 | |
780 | // XR_EXT_debug_utils is built into the loader and handled partly through the xrGetInstanceProcAddress terminator, |
781 | // but the check to see if the extension is enabled must be done here where ActiveLoaderInstance is safe to use. |
782 | if (*function == nullptr) { |
783 | if (strcmp(name, "xrCreateDebugUtilsMessengerEXT" ) == 0) { |
784 | *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineCreateDebugUtilsMessengerEXT); |
785 | } else if (strcmp(name, "xrDestroyDebugUtilsMessengerEXT" ) == 0) { |
786 | *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineDestroyDebugUtilsMessengerEXT); |
787 | } else if (strcmp(name, "xrSessionBeginDebugUtilsLabelRegionEXT" ) == 0) { |
788 | *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSessionBeginDebugUtilsLabelRegionEXT); |
789 | } else if (strcmp(name, "xrSessionEndDebugUtilsLabelRegionEXT" ) == 0) { |
790 | *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSessionEndDebugUtilsLabelRegionEXT); |
791 | } else if (strcmp(name, "xrSessionInsertDebugUtilsLabelEXT" ) == 0) { |
792 | *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSessionInsertDebugUtilsLabelEXT); |
793 | } else if (strcmp(name, "xrSetDebugUtilsObjectNameEXT" ) == 0) { |
794 | *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSetDebugUtilsObjectNameEXT); |
795 | } else if (strcmp(name, "xrSubmitDebugUtilsMessageEXT" ) == 0) { |
796 | *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSubmitDebugUtilsMessageEXT); |
797 | } |
798 | |
799 | if (*function != nullptr && !loader_instance->ExtensionIsEnabled("XR_EXT_debug_utils" )) { |
800 | // The function matches one of the XR_EXT_debug_utils functions but the extension is not enabled. |
801 | *function = nullptr; |
802 | return XR_ERROR_FUNCTION_UNSUPPORTED; |
803 | } |
804 | } |
805 | |
806 | if (*function != nullptr) { |
807 | // The loader has a trampoline or implementation of this function. |
808 | return XR_SUCCESS; |
809 | } |
810 | |
811 | // If the function is not supported by the loader, call down to the next layer. |
812 | return loader_instance->GetInstanceProcAddr(name, function); |
813 | } |
814 | XRLOADER_ABI_CATCH_FALLBACK |
815 | |
816 | // Exported loader functions |
817 | // |
818 | // The application might override these by exporting the same symbols and so we can't use these |
819 | // symbols anywhere in the loader code, and instead the internal non exported functions that these |
820 | // stubs call should be used internally. |
821 | LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateApiLayerProperties(uint32_t propertyCapacityInput, |
822 | uint32_t *propertyCountOutput, |
823 | XrApiLayerProperties *properties) { |
824 | return LoaderXrEnumerateApiLayerProperties(propertyCapacityInput, propertyCountOutput, properties); |
825 | } |
826 | |
827 | LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateInstanceExtensionProperties(const char *layerName, |
828 | uint32_t propertyCapacityInput, |
829 | uint32_t *propertyCountOutput, |
830 | XrExtensionProperties *properties) { |
831 | return LoaderXrEnumerateInstanceExtensionProperties(layerName, propertyCapacityInput, propertyCountOutput, properties); |
832 | } |
833 | |
834 | LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateInstance(const XrInstanceCreateInfo *info, XrInstance *instance) { |
835 | return LoaderXrCreateInstance(info, instance); |
836 | } |
837 | |
838 | LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroyInstance(XrInstance instance) { return LoaderXrDestroyInstance(instance); } |
839 | |
840 | LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetInstanceProcAddr(XrInstance instance, const char *name, |
841 | PFN_xrVoidFunction *function) { |
842 | return LoaderXrGetInstanceProcAddr(instance, name, function); |
843 | } |
844 | |
845 | #ifdef XR_KHR_LOADER_INIT_SUPPORT |
846 | LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrInitializeLoaderKHR(const XrLoaderInitInfoBaseHeaderKHR *loaderInitInfo) { |
847 | return LoaderXrInitializeLoaderKHR(loaderInitInfo); |
848 | } |
849 | #endif |
850 | |