summaryrefslogtreecommitdiffstats
path: root/servers
diff options
context:
space:
mode:
Diffstat (limited to 'servers')
-rw-r--r--servers/rendering/rendering_server_default.h4
-rw-r--r--servers/rendering_server.cpp1
-rw-r--r--servers/rendering_server.h29
-rw-r--r--servers/xr/xr_interface.h10
-rw-r--r--servers/xr_server.cpp146
-rw-r--r--servers/xr_server.h39
6 files changed, 180 insertions, 49 deletions
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index 8de76c7dbc..e0049e3fa4 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -1048,6 +1048,10 @@ public:
virtual void init() override;
virtual void finish() override;
+ virtual bool is_on_render_thread() override {
+ return Thread::get_caller_id() == server_thread;
+ }
+
virtual void call_on_render_thread(const Callable &p_callable) override {
if (Thread::get_caller_id() == server_thread) {
command_queue.flush_if_pending();
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index bbe6b1ad0d..48b6632364 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -3426,6 +3426,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_rendering_device"), &RenderingServer::get_rendering_device);
ClassDB::bind_method(D_METHOD("create_local_rendering_device"), &RenderingServer::create_local_rendering_device);
+ ClassDB::bind_method(D_METHOD("is_on_render_thread"), &RenderingServer::is_on_render_thread);
ClassDB::bind_method(D_METHOD("call_on_render_thread", "callable"), &RenderingServer::call_on_render_thread);
#ifndef DISABLE_DEPRECATED
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index 8f0150f180..240d82c90b 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -41,6 +41,32 @@
#include "servers/display_server.h"
#include "servers/rendering/rendering_device.h"
+// Helper macros for code outside of the rendering server, but that is
+// called by the rendering server.
+#ifdef DEBUG_ENABLED
+#define ERR_ON_RENDER_THREAD \
+ RenderingServer *rendering_server = RenderingServer::get_singleton(); \
+ ERR_FAIL_NULL(rendering_server); \
+ ERR_FAIL_COND(rendering_server->is_on_render_thread());
+#define ERR_ON_RENDER_THREAD_V(m_ret) \
+ RenderingServer *rendering_server = RenderingServer::get_singleton(); \
+ ERR_FAIL_NULL_V(rendering_server, m_ret); \
+ ERR_FAIL_COND_V(rendering_server->is_on_render_thread(), m_ret);
+#define ERR_NOT_ON_RENDER_THREAD \
+ RenderingServer *rendering_server = RenderingServer::get_singleton(); \
+ ERR_FAIL_NULL(rendering_server); \
+ ERR_FAIL_COND(!rendering_server->is_on_render_thread());
+#define ERR_NOT_ON_RENDER_THREAD_V(m_ret) \
+ RenderingServer *rendering_server = RenderingServer::get_singleton(); \
+ ERR_FAIL_NULL_V(rendering_server, m_ret); \
+ ERR_FAIL_COND_V(!rendering_server->is_on_render_thread(), m_ret);
+#else
+#define ERR_ON_RENDER_THREAD
+#define ERR_ON_RENDER_THREAD_V(m_ret)
+#define ERR_NOT_ON_RENDER_THREAD
+#define ERR_NOT_ON_RENDER_THREAD_V(m_ret)
+#endif
+
template <typename T>
class TypedArray;
@@ -1684,7 +1710,7 @@ public:
#ifndef DISABLE_DEPRECATED
// Never actually used, should be removed when we can break compatibility.
- enum Features {
+ enum Features{
FEATURE_SHADERS,
FEATURE_MULTITHREADED,
};
@@ -1708,6 +1734,7 @@ public:
bool is_render_loop_enabled() const;
void set_render_loop_enabled(bool p_enabled);
+ virtual bool is_on_render_thread() = 0;
virtual void call_on_render_thread(const Callable &p_callable) = 0;
#ifdef TOOLS_ENABLED
diff --git a/servers/xr/xr_interface.h b/servers/xr/xr_interface.h
index d7bd212449..809800d8b9 100644
--- a/servers/xr/xr_interface.h
+++ b/servers/xr/xr_interface.h
@@ -122,17 +122,21 @@ public:
/** rendering and internal **/
+ // These methods are called from the main thread.
+ virtual Transform3D get_camera_transform() = 0; /* returns the position of our camera, only used for updating reference frame. For monoscopic this is equal to the views transform, for stereoscopic this should be an average */
+ virtual void process() = 0;
+
+ // These methods can be called from both main and render thread.
virtual Size2 get_render_target_size() = 0; /* returns the recommended render target size per eye for this device */
virtual uint32_t get_view_count() = 0; /* returns the view count we need (1 is monoscopic, 2 is stereoscopic but can be more) */
- virtual Transform3D get_camera_transform() = 0; /* returns the position of our camera for updating our camera node. For monoscopic this is equal to the views transform, for stereoscopic this should be an average */
+
+ // These methods are called from the rendering thread.
virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) = 0; /* get each views transform */
virtual Projection get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) = 0; /* get each view projection matrix */
virtual RID get_vrs_texture(); /* obtain VRS texture */
virtual RID get_color_texture(); /* obtain color output texture (if applicable) */
virtual RID get_depth_texture(); /* obtain depth output texture (if applicable, used for reprojection) */
virtual RID get_velocity_texture(); /* obtain velocity output texture (if applicable, used for spacewarp) */
-
- virtual void process() = 0;
virtual void pre_render(){};
virtual bool pre_draw_viewport(RID p_render_target) { return true; }; /* inform XR interface we are about to start our viewport draw process */
virtual Vector<BlitToScreen> post_draw_viewport(RID p_render_target, const Rect2 &p_screen_rect) = 0; /* inform XR interface we finished our viewport draw process */
diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp
index f1105a650d..2cfe98ea1e 100644
--- a/servers/xr_server.cpp
+++ b/servers/xr_server.cpp
@@ -51,7 +51,7 @@ XRServer *XRServer::singleton = nullptr;
XRServer *XRServer::get_singleton() {
return singleton;
-};
+}
void XRServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_world_scale"), &XRServer::get_world_scale);
@@ -59,7 +59,7 @@ void XRServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_world_origin"), &XRServer::get_world_origin);
ClassDB::bind_method(D_METHOD("set_world_origin", "world_origin"), &XRServer::set_world_origin);
ClassDB::bind_method(D_METHOD("get_reference_frame"), &XRServer::get_reference_frame);
- ClassDB::bind_method(D_METHOD("clear_reference_frame"), &XRServer::get_reference_frame);
+ ClassDB::bind_method(D_METHOD("clear_reference_frame"), &XRServer::clear_reference_frame);
ClassDB::bind_method(D_METHOD("center_on_hmd", "rotation_mode", "keep_height"), &XRServer::center_on_hmd);
ClassDB::bind_method(D_METHOD("get_hmd_transform"), &XRServer::get_hmd_transform);
@@ -104,11 +104,20 @@ void XRServer::_bind_methods() {
ADD_SIGNAL(MethodInfo("tracker_added", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::INT, "type")));
ADD_SIGNAL(MethodInfo("tracker_updated", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::INT, "type")));
ADD_SIGNAL(MethodInfo("tracker_removed", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::INT, "type")));
-};
+}
double XRServer::get_world_scale() const {
- return world_scale;
-};
+ RenderingServer *rendering_server = RenderingServer::get_singleton();
+
+ if (rendering_server && rendering_server->is_on_render_thread()) {
+ // Return the value with which we're currently rendering,
+ // if we're on the render thread
+ return render_state.world_scale;
+ } else {
+ // Return our current value
+ return world_scale;
+ }
+}
void XRServer::set_world_scale(double p_world_scale) {
if (p_world_scale < 0.01) {
@@ -118,19 +127,58 @@ void XRServer::set_world_scale(double p_world_scale) {
}
world_scale = p_world_scale;
-};
+ set_render_world_scale(world_scale);
+}
+
+void XRServer::_set_render_world_scale(double p_world_scale) {
+ // Must be called from rendering thread!
+ ERR_NOT_ON_RENDER_THREAD;
+
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
+ xr_server->render_state.world_scale = p_world_scale;
+}
Transform3D XRServer::get_world_origin() const {
- return world_origin;
-};
+ RenderingServer *rendering_server = RenderingServer::get_singleton();
+
+ if (rendering_server && rendering_server->is_on_render_thread()) {
+ // Return the value with which we're currently rendering,
+ // if we're on the render thread
+ return render_state.world_origin;
+ } else {
+ // Return our current value
+ return world_origin;
+ }
+}
void XRServer::set_world_origin(const Transform3D &p_world_origin) {
world_origin = p_world_origin;
-};
+ set_render_world_origin(world_origin);
+}
+
+void XRServer::_set_render_world_origin(const Transform3D &p_world_origin) {
+ // Must be called from rendering thread!
+ ERR_NOT_ON_RENDER_THREAD;
+
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
+ xr_server->render_state.world_origin = p_world_origin;
+}
Transform3D XRServer::get_reference_frame() const {
- return reference_frame;
-};
+ RenderingServer *rendering_server = RenderingServer::get_singleton();
+ ERR_FAIL_NULL_V(rendering_server, reference_frame);
+
+ if (rendering_server->is_on_render_thread()) {
+ // Return the value with which we're currently rendering,
+ // if we're on the render thread
+ return render_state.reference_frame;
+ } else {
+ // Return our current value
+ return reference_frame;
+ }
+}
void XRServer::center_on_hmd(RotationMode p_rotation_mode, bool p_keep_height) {
if (primary_interface == nullptr) {
@@ -156,27 +204,38 @@ void XRServer::center_on_hmd(RotationMode p_rotation_mode, bool p_keep_height) {
} else if (p_rotation_mode == 2) {
// remove our rotation, we're only interesting in centering on position
new_reference_frame.basis = Basis();
- };
+ }
// don't negate our height
if (p_keep_height) {
new_reference_frame.origin.y = 0.0;
- };
+ }
reference_frame = new_reference_frame.inverse();
-};
+ set_render_reference_frame(reference_frame);
+}
void XRServer::clear_reference_frame() {
reference_frame = Transform3D();
+ set_render_reference_frame(reference_frame);
+}
+
+void XRServer::_set_render_reference_frame(const Transform3D &p_reference_frame) {
+ // Must be called from rendering thread!
+ ERR_NOT_ON_RENDER_THREAD;
+
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
+ xr_server->render_state.reference_frame = p_reference_frame;
}
Transform3D XRServer::get_hmd_transform() {
Transform3D hmd_transform;
if (primary_interface != nullptr) {
hmd_transform = primary_interface->get_camera_transform();
- };
+ }
return hmd_transform;
-};
+}
void XRServer::add_interface(const Ref<XRInterface> &p_interface) {
ERR_FAIL_COND(p_interface.is_null());
@@ -185,12 +244,12 @@ void XRServer::add_interface(const Ref<XRInterface> &p_interface) {
if (interfaces[i] == p_interface) {
ERR_PRINT("Interface was already added");
return;
- };
- };
+ }
+ }
interfaces.push_back(p_interface);
emit_signal(SNAME("interface_added"), p_interface->get_name());
-};
+}
void XRServer::remove_interface(const Ref<XRInterface> &p_interface) {
ERR_FAIL_COND(p_interface.is_null());
@@ -200,33 +259,33 @@ void XRServer::remove_interface(const Ref<XRInterface> &p_interface) {
if (interfaces[i] == p_interface) {
idx = i;
break;
- };
- };
+ }
+ }
ERR_FAIL_COND_MSG(idx == -1, "Interface not found.");
print_verbose("XR: Removed interface \"" + p_interface->get_name() + "\"");
emit_signal(SNAME("interface_removed"), p_interface->get_name());
interfaces.remove_at(idx);
-};
+}
int XRServer::get_interface_count() const {
return interfaces.size();
-};
+}
Ref<XRInterface> XRServer::get_interface(int p_index) const {
ERR_FAIL_INDEX_V(p_index, interfaces.size(), nullptr);
return interfaces[p_index];
-};
+}
Ref<XRInterface> XRServer::find_interface(const String &p_name) const {
for (int i = 0; i < interfaces.size(); i++) {
if (interfaces[i]->get_name() == p_name) {
return interfaces[i];
- };
- };
+ }
+ }
return Ref<XRInterface>();
-};
+}
TypedArray<Dictionary> XRServer::get_interfaces() const {
Array ret;
@@ -238,14 +297,14 @@ TypedArray<Dictionary> XRServer::get_interfaces() const {
iface_info["name"] = interfaces[i]->get_name();
ret.push_back(iface_info);
- };
+ }
return ret;
-};
+}
Ref<XRInterface> XRServer::get_primary_interface() const {
return primary_interface;
-};
+}
void XRServer::set_primary_interface(const Ref<XRInterface> &p_primary_interface) {
if (p_primary_interface.is_null()) {
@@ -256,7 +315,7 @@ void XRServer::set_primary_interface(const Ref<XRInterface> &p_primary_interface
print_verbose("XR: Primary interface set to: " + primary_interface->get_name());
}
-};
+}
void XRServer::add_tracker(const Ref<XRTracker> &p_tracker) {
ERR_FAIL_COND(p_tracker.is_null());
@@ -272,7 +331,7 @@ void XRServer::add_tracker(const Ref<XRTracker> &p_tracker) {
trackers[tracker_name] = p_tracker;
emit_signal(SNAME("tracker_added"), tracker_name, p_tracker->get_tracker_type());
}
-};
+}
void XRServer::remove_tracker(const Ref<XRTracker> &p_tracker) {
ERR_FAIL_COND(p_tracker.is_null());
@@ -285,7 +344,7 @@ void XRServer::remove_tracker(const Ref<XRTracker> &p_tracker) {
// and remove it
trackers.erase(tracker_name);
}
-};
+}
Dictionary XRServer::get_trackers(int p_tracker_types) {
Dictionary res;
@@ -307,7 +366,7 @@ Ref<XRTracker> XRServer::get_tracker(const StringName &p_name) const {
// tracker hasn't been registered yet, which is fine, no need to spam the error log...
return Ref<XRTracker>();
}
-};
+}
PackedStringArray XRServer::get_suggested_tracker_names() const {
PackedStringArray arr;
@@ -369,9 +428,9 @@ void XRServer::_process() {
// ignore, not a valid reference
} else if (interfaces[i]->is_initialized()) {
interfaces.write[i]->process();
- };
- };
-};
+ }
+ }
+}
void XRServer::pre_render() {
// called from RendererViewport.draw_viewports right before we start drawing our viewports
@@ -383,8 +442,8 @@ void XRServer::pre_render() {
// ignore, not a valid reference
} else if (interfaces[i]->is_initialized()) {
interfaces.write[i]->pre_render();
- };
- };
+ }
+ }
}
void XRServer::end_frame() {
@@ -396,14 +455,13 @@ void XRServer::end_frame() {
// ignore, not a valid reference
} else if (interfaces[i]->is_initialized()) {
interfaces.write[i]->end_frame();
- };
- };
+ }
+ }
}
XRServer::XRServer() {
singleton = this;
- world_scale = 1.0;
-};
+}
XRServer::~XRServer() {
primary_interface.unref();
@@ -412,4 +470,4 @@ XRServer::~XRServer() {
trackers.clear();
singleton = nullptr;
-};
+}
diff --git a/servers/xr_server.h b/servers/xr_server.h
index 717728171a..cd9c241bb0 100644
--- a/servers/xr_server.h
+++ b/servers/xr_server.h
@@ -36,6 +36,7 @@
#include "core/os/thread_safe.h"
#include "core/templates/rid.h"
#include "core/variant/variant.h"
+#include "rendering_server.h"
class XRInterface;
class XRTracker;
@@ -92,10 +93,46 @@ private:
Ref<XRInterface> primary_interface; /* we'll identify one interface as primary, this will be used by our viewports */
- double world_scale; /* scale by which we multiply our tracker positions */
+ double world_scale = 1.0; /* scale by which we multiply our tracker positions */
Transform3D world_origin; /* our world origin point, maps a location in our virtual world to the origin point in our real world tracking volume */
Transform3D reference_frame; /* our reference frame */
+ // As we may be updating our main state for our next frame while we're still rendering our previous frame,
+ // we need to keep copies around.
+ struct RenderState {
+ double world_scale = 1.0; /* scale by which we multiply our tracker positions */
+ Transform3D world_origin; /* our world origin point, maps a location in our virtual world to the origin point in our real world tracking volume */
+ Transform3D reference_frame; /* our reference frame */
+ } render_state;
+
+ static void _set_render_world_scale(double p_world_scale);
+ static void _set_render_world_origin(const Transform3D &p_world_origin);
+ static void _set_render_reference_frame(const Transform3D &p_reference_frame);
+
+ _FORCE_INLINE_ void set_render_world_scale(double p_world_scale) {
+ // If we're rendering on a separate thread, we may still be processing the last frame, don't communicate this till we're ready...
+ RenderingServer *rendering_server = RenderingServer::get_singleton();
+ ERR_FAIL_NULL(rendering_server);
+
+ rendering_server->call_on_render_thread(callable_mp_static(&XRServer::_set_render_world_scale).bind(p_world_scale));
+ }
+
+ _FORCE_INLINE_ void set_render_world_origin(const Transform3D &p_world_origin) {
+ // If we're rendering on a separate thread, we may still be processing the last frame, don't communicate this till we're ready...
+ RenderingServer *rendering_server = RenderingServer::get_singleton();
+ ERR_FAIL_NULL(rendering_server);
+
+ rendering_server->call_on_render_thread(callable_mp_static(&XRServer::_set_render_world_origin).bind(p_world_origin));
+ }
+
+ _FORCE_INLINE_ void set_render_reference_frame(const Transform3D &p_reference_frame) {
+ // If we're rendering on a separate thread, we may still be processing the last frame, don't communicate this till we're ready...
+ RenderingServer *rendering_server = RenderingServer::get_singleton();
+ ERR_FAIL_NULL(rendering_server);
+
+ rendering_server->call_on_render_thread(callable_mp_static(&XRServer::_set_render_reference_frame).bind(p_reference_frame));
+ }
+
protected:
static XRServer *singleton;