diff options
Diffstat (limited to 'servers')
-rw-r--r-- | servers/rendering/rendering_server_default.h | 4 | ||||
-rw-r--r-- | servers/rendering_server.cpp | 1 | ||||
-rw-r--r-- | servers/rendering_server.h | 29 | ||||
-rw-r--r-- | servers/xr/xr_interface.h | 10 | ||||
-rw-r--r-- | servers/xr_server.cpp | 146 | ||||
-rw-r--r-- | servers/xr_server.h | 39 |
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; |