Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/openxr/extensions/openxr_future_extension.cpp
10278 views
1
/**************************************************************************/
2
/* openxr_future_extension.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "openxr_future_extension.h"
32
33
#include "../openxr_api.h"
34
35
////////////////////////////////////////////////////////////////////////////
36
// OpenXRFutureResult
37
38
void OpenXRFutureResult::_bind_methods() {
39
ClassDB::bind_method(D_METHOD("get_status"), &OpenXRFutureResult::get_status);
40
ClassDB::bind_method(D_METHOD("get_future"), &OpenXRFutureResult::_get_future);
41
ClassDB::bind_method(D_METHOD("cancel_future"), &OpenXRFutureResult::cancel_future);
42
43
ClassDB::bind_method(D_METHOD("set_result_value", "result_value"), &OpenXRFutureResult::set_result_value);
44
ClassDB::bind_method(D_METHOD("get_result_value"), &OpenXRFutureResult::get_result_value);
45
46
ADD_SIGNAL(MethodInfo("completed", PropertyInfo(Variant::OBJECT, "result", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRFutureResult")));
47
48
BIND_ENUM_CONSTANT(RESULT_RUNNING);
49
BIND_ENUM_CONSTANT(RESULT_FINISHED);
50
BIND_ENUM_CONSTANT(RESULT_CANCELLED);
51
}
52
53
void OpenXRFutureResult::_mark_as_finished() {
54
// Update our status
55
status = RESULT_FINISHED;
56
57
// Perform our callback
58
on_success_callback.call(this); // Note, `this` will be converted to a variant that will be refcounted!
59
60
// Emit our signal, we assume our callback has provided us with the correct result value by calling set_result_value.
61
emit_signal(SNAME("completed"), result_value);
62
}
63
64
void OpenXRFutureResult::_mark_as_cancelled() {
65
// Update our status
66
status = RESULT_CANCELLED;
67
68
// There is no point in doing a callback for cancellation as its always user invoked.
69
70
// But we do emit our signal to make sure any await finishes.
71
Variant no_result;
72
emit_signal(SNAME("completed"), no_result);
73
}
74
75
OpenXRFutureResult::ResultStatus OpenXRFutureResult::get_status() const {
76
return status;
77
}
78
79
XrFutureEXT OpenXRFutureResult::get_future() const {
80
return future;
81
}
82
83
uint64_t OpenXRFutureResult::_get_future() const {
84
return (uint64_t)future;
85
}
86
87
void OpenXRFutureResult::set_result_value(const Variant &p_result_value) {
88
result_value = p_result_value;
89
}
90
91
Variant OpenXRFutureResult::get_result_value() const {
92
return result_value;
93
}
94
95
void OpenXRFutureResult::cancel_future() {
96
ERR_FAIL_COND(status != RESULT_RUNNING);
97
98
OpenXRFutureExtension *future_extension = OpenXRFutureExtension::get_singleton();
99
ERR_FAIL_NULL(future_extension);
100
101
future_extension->cancel_future(future);
102
}
103
104
OpenXRFutureResult::OpenXRFutureResult(XrFutureEXT p_future, const Callable &p_on_success) {
105
future = p_future;
106
on_success_callback = p_on_success;
107
}
108
109
////////////////////////////////////////////////////////////////////////////
110
// OpenXRFutureExtension
111
112
OpenXRFutureExtension *OpenXRFutureExtension::singleton = nullptr;
113
114
OpenXRFutureExtension *OpenXRFutureExtension::get_singleton() {
115
return singleton;
116
}
117
118
OpenXRFutureExtension::OpenXRFutureExtension() {
119
singleton = this;
120
}
121
122
OpenXRFutureExtension::~OpenXRFutureExtension() {
123
singleton = nullptr;
124
}
125
126
void OpenXRFutureExtension::_bind_methods() {
127
ClassDB::bind_method(D_METHOD("is_active"), &OpenXRFutureExtension::is_active);
128
ClassDB::bind_method(D_METHOD("register_future", "future", "on_success"), &OpenXRFutureExtension::_register_future, DEFVAL(Callable()));
129
ClassDB::bind_method(D_METHOD("cancel_future", "future"), &OpenXRFutureExtension::_cancel_future);
130
}
131
132
HashMap<String, bool *> OpenXRFutureExtension::get_requested_extensions() {
133
HashMap<String, bool *> request_extensions;
134
135
request_extensions[XR_EXT_FUTURE_EXTENSION_NAME] = &future_ext;
136
137
return request_extensions;
138
}
139
140
void OpenXRFutureExtension::on_instance_created(const XrInstance p_instance) {
141
if (future_ext) {
142
EXT_INIT_XR_FUNC(xrPollFutureEXT);
143
EXT_INIT_XR_FUNC(xrCancelFutureEXT);
144
145
future_ext = xrPollFutureEXT_ptr && xrCancelFutureEXT_ptr;
146
}
147
}
148
149
void OpenXRFutureExtension::on_instance_destroyed() {
150
xrPollFutureEXT_ptr = nullptr;
151
xrCancelFutureEXT_ptr = nullptr;
152
}
153
154
void OpenXRFutureExtension::on_session_destroyed() {
155
if (!is_active()) {
156
return;
157
}
158
159
OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
160
ERR_FAIL_NULL(openxr_api);
161
162
// Cancel any running futures.
163
for (const KeyValue<XrFutureEXT, Ref<OpenXRFutureResult>> &element : futures) {
164
XrFutureCancelInfoEXT cancel_info = {
165
XR_TYPE_FUTURE_CANCEL_INFO_EXT, // type
166
nullptr, // next
167
element.key // future
168
};
169
XrResult result = xrCancelFutureEXT_ptr(openxr_api->get_instance(), &cancel_info);
170
if (XR_FAILED(result)) {
171
WARN_PRINT("OpenXR: Failed to cancel future [" + openxr_api->get_error_string(result) + "]");
172
}
173
174
// Make sure we mark our future result as cancelled
175
element.value->_mark_as_cancelled();
176
}
177
futures.clear();
178
}
179
180
bool OpenXRFutureExtension::is_active() const {
181
return future_ext;
182
}
183
184
Ref<OpenXRFutureResult> OpenXRFutureExtension::register_future(XrFutureEXT p_future, const Callable &p_on_success) {
185
ERR_FAIL_COND_V(futures.has(p_future), nullptr);
186
187
Ref<OpenXRFutureResult> future_result;
188
future_result.instantiate(p_future, p_on_success);
189
190
futures[p_future] = future_result;
191
192
return future_result;
193
}
194
195
Ref<OpenXRFutureResult> OpenXRFutureExtension::_register_future(uint64_t p_future, const Callable &p_on_success) {
196
return register_future((XrFutureEXT)p_future, p_on_success);
197
}
198
199
void OpenXRFutureExtension::cancel_future(XrFutureEXT p_future) {
200
ERR_FAIL_COND(!futures.has(p_future));
201
202
OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
203
ERR_FAIL_NULL(openxr_api);
204
205
XrFutureCancelInfoEXT cancel_info = {
206
XR_TYPE_FUTURE_CANCEL_INFO_EXT, // type
207
nullptr, // next
208
p_future // future
209
};
210
XrResult result = xrCancelFutureEXT_ptr(openxr_api->get_instance(), &cancel_info);
211
if (XR_FAILED(result)) {
212
WARN_PRINT("OpenXR: Failed to cancel future [" + openxr_api->get_error_string(result) + "]");
213
}
214
215
// Make sure we mark our future result as cancelled
216
futures[p_future]->_mark_as_cancelled();
217
218
// And erase it from the futures we track
219
futures.erase(p_future);
220
}
221
222
void OpenXRFutureExtension::_cancel_future(uint64_t p_future) {
223
cancel_future((XrFutureEXT)p_future);
224
}
225
226
void OpenXRFutureExtension::on_process() {
227
if (!is_active()) {
228
return;
229
}
230
231
OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
232
ERR_FAIL_NULL(openxr_api);
233
234
// Process futures
235
Vector<XrFutureEXT> completed;
236
for (const KeyValue<XrFutureEXT, Ref<OpenXRFutureResult>> &element : futures) {
237
XrFuturePollInfoEXT poll_info = {
238
XR_TYPE_FUTURE_POLL_INFO_EXT, // type
239
nullptr, // next
240
element.key // future
241
};
242
XrFuturePollResultEXT poll_result = {
243
XR_TYPE_FUTURE_POLL_RESULT_EXT, // type
244
nullptr, // next
245
XR_FUTURE_STATE_MAX_ENUM_EXT // state
246
};
247
XrResult result = xrPollFutureEXT_ptr(openxr_api->get_instance(), &poll_info, &poll_result);
248
if (XR_FAILED(result)) {
249
ERR_PRINT("OpenXR: Failed to obtain future status [" + openxr_api->get_error_string(result) + "]");
250
// Maybe remove this depending on the error?
251
continue;
252
}
253
if (poll_result.state == XR_FUTURE_STATE_READY_EXT) {
254
// Mark our future result as finished (this will invoke our callback).
255
element.value->_mark_as_finished();
256
257
// Queue removing this
258
completed.push_back(element.key);
259
}
260
}
261
262
// Now clean up completed futures.
263
for (const XrFutureEXT &future : completed) {
264
futures.erase(future);
265
}
266
}
267
268