From e7f6b7ea0b9ff83e1b152f127d68fd905f503b4b Mon Sep 17 00:00:00 2001 From: devloglogan Date: Fri, 20 Sep 2024 15:57:19 -0500 Subject: [PATCH] Allow using custom Rect2i for rendering with OpenXR --- doc/classes/XRVRS.xml | 3 ++ drivers/gles3/rasterizer_scene_gles3.cpp | 15 +++++- drivers/gles3/rasterizer_scene_gles3.h | 1 + drivers/gles3/storage/texture_storage.cpp | 14 +++++ drivers/gles3/storage/texture_storage.h | 5 ++ .../openxr/doc_classes/OpenXRAPIExtension.xml | 14 +++++ modules/openxr/openxr_api.cpp | 54 +++++++++++++++---- modules/openxr/openxr_api.h | 23 ++++++++ modules/openxr/openxr_api_extension.cpp | 14 +++++ modules/openxr/openxr_api_extension.h | 4 ++ modules/openxr/openxr_interface.cpp | 10 ++++ modules/openxr/openxr_interface.h | 2 + .../rendering/dummy/storage/texture_storage.h | 3 ++ .../render_forward_clustered.cpp | 8 +-- .../forward_mobile/render_forward_mobile.cpp | 4 +- .../renderer_rd/renderer_scene_render_rd.cpp | 1 + .../renderer_rd/storage_rd/render_data_rd.h | 1 + .../storage_rd/texture_storage.cpp | 14 +++++ .../renderer_rd/storage_rd/texture_storage.h | 5 ++ servers/rendering/renderer_viewport.cpp | 2 + servers/rendering/storage/texture_storage.h | 3 ++ servers/xr/xr_interface.cpp | 4 ++ servers/xr/xr_interface.h | 1 + servers/xr/xr_vrs.cpp | 26 +++++++-- servers/xr/xr_vrs.h | 3 ++ 25 files changed, 215 insertions(+), 19 deletions(-) diff --git a/doc/classes/XRVRS.xml b/doc/classes/XRVRS.xml index b19b461fab6..ec92d4a667a 100644 --- a/doc/classes/XRVRS.xml +++ b/doc/classes/XRVRS.xml @@ -23,6 +23,9 @@ The minimum radius around the focal point where full quality is guaranteed if VRS is used as a percentage of screen size. + + The render region that the VRS texture will be scaled to when generated. + The strength used to calculate the VRS density map. The greater this value, the more noticeable VRS is. diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 8c05dff79a1..8c2e059e1e4 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -2250,7 +2250,12 @@ void RasterizerSceneGLES3::render_scene(const Ref &p_render_ RenderDataGLES3 render_data; { render_data.render_buffers = rb; - render_data.transparent_bg = rt ? rt->is_transparent : false; + + if (rt) { + render_data.transparent_bg = rt->is_transparent; + render_data.render_region = rt->render_region; + } + // Our first camera is used by default render_data.cam_transform = p_camera_data->main_transform; render_data.inv_cam_transform = render_data.cam_transform.affine_inverse(); @@ -2487,6 +2492,10 @@ void RasterizerSceneGLES3::render_scene(const Ref &p_render_ RENDER_TIMESTAMP("Depth Prepass"); //pre z pass + if (render_data.render_region != Rect2i()) { + glViewport(render_data.render_region.position.x, render_data.render_region.position.y, render_data.render_region.size.width, render_data.render_region.size.height); + } + scene_state.enable_gl_depth_test(true); scene_state.enable_gl_depth_draw(true); scene_state.enable_gl_blend(false); @@ -2562,6 +2571,10 @@ void RasterizerSceneGLES3::render_scene(const Ref &p_render_ RENDER_TIMESTAMP("Render Opaque Pass"); uint64_t spec_constant_base_flags = 0; + if (render_data.render_region != Rect2i()) { + glViewport(render_data.render_region.position.x, render_data.render_region.position.y, render_data.render_region.size.width, render_data.render_region.size.height); + } + { // Specialization Constants that apply for entire rendering pass. if (render_data.directional_light_count == 0) { diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 4f088a0e7de..801f55b4eb1 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -98,6 +98,7 @@ enum SkyUniformLocation { struct RenderDataGLES3 { Ref render_buffers; bool transparent_bg = false; + Rect2i render_region; Transform3D cam_transform; Transform3D inv_cam_transform; diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp index 4531dacbb53..526d9d49e08 100644 --- a/drivers/gles3/storage/texture_storage.cpp +++ b/drivers/gles3/storage/texture_storage.cpp @@ -2568,6 +2568,20 @@ RID TextureStorage::render_target_get_override_velocity(RID p_render_target) con return rt->overridden.velocity; } +void TextureStorage::render_target_set_render_region(RID p_render_target, const Rect2i &p_render_region) { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_NULL(rt); + + rt->render_region = p_render_region; +} + +Rect2i TextureStorage::render_target_get_render_region(RID p_render_target) const { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_NULL_V(rt, Rect2i()); + + return rt->render_region; +} + RID TextureStorage::render_target_get_texture(RID p_render_target) { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_NULL_V(rt, RID()); diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h index 1fecb2e5bb3..492ad450d82 100644 --- a/drivers/gles3/storage/texture_storage.h +++ b/drivers/gles3/storage/texture_storage.h @@ -372,6 +372,8 @@ struct RenderTarget { RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED; bool reattach_textures = false; + Rect2i render_region; + struct RTOverridden { bool is_overridden = false; RID color; @@ -691,6 +693,9 @@ public: virtual RID render_target_get_override_velocity(RID p_render_target) const override; virtual RID render_target_get_override_velocity_depth(RID p_render_target) const override { return RID(); } + virtual void render_target_set_render_region(RID p_render_target, const Rect2i &p_render_region) override; + virtual Rect2i render_target_get_render_region(RID p_render_target) const override; + virtual RID render_target_get_texture(RID p_render_target) override; virtual void render_target_set_velocity_target_size(RID p_render_target, const Size2i &p_target_size) override {} diff --git a/modules/openxr/doc_classes/OpenXRAPIExtension.xml b/modules/openxr/doc_classes/OpenXRAPIExtension.xml index d244b4219d1..b0ee44267b7 100644 --- a/modules/openxr/doc_classes/OpenXRAPIExtension.xml +++ b/modules/openxr/doc_classes/OpenXRAPIExtension.xml @@ -82,6 +82,13 @@ Returns the predicted display timing for the current frame. + + + + Returns a pointer to the render state's [code]XrCompositionLayerProjection[/code] struct. + [b]Note:[/b] This method should only be called from the rendering thread. + + @@ -231,6 +238,13 @@ Set the object name of an OpenXR object, used for debug output. [param object_type] must be a valid OpenXR [code]XrObjectType[/code] enum and [param object_handle] must be a valid OpenXR object handle. + + + + + Sets the render region to [param render_region], overriding the normal render target's rect. + + diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index 484becba8de..5e616445b87 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -2171,6 +2171,14 @@ void OpenXRAPI::_set_render_state_multiplier(double p_render_target_size_multipl openxr_api->render_state.render_target_size_multiplier = p_render_target_size_multiplier; } +void OpenXRAPI::_set_render_state_render_region(const Rect2i &p_render_region) { + ERR_NOT_ON_RENDER_THREAD; + + OpenXRAPI *openxr_api = OpenXRAPI::get_singleton(); + ERR_FAIL_NULL(openxr_api); + openxr_api->render_state.render_region = p_render_region; +} + bool OpenXRAPI::process() { ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false); @@ -2403,6 +2411,12 @@ Size2i OpenXRAPI::get_velocity_target_size() { return velocity_target_size; } +const XrCompositionLayerProjection *OpenXRAPI::get_projection_layer() const { + ERR_NOT_ON_RENDER_THREAD_V(nullptr); + + return &render_state.projection_layer; +} + void OpenXRAPI::post_draw_viewport(RID p_render_target) { // Must be called from rendering thread! ERR_NOT_ON_RENDER_THREAD; @@ -2436,6 +2450,23 @@ void OpenXRAPI::end_frame() { } } + Rect2i new_render_region = (render_state.render_region != Rect2i()) ? render_state.render_region : Rect2i(Point2i(0, 0), render_state.main_swapchain_size); + + for (uint32_t i = 0; i < render_state.view_count; i++) { + render_state.projection_views[i].subImage.imageRect.offset.x = new_render_region.position.x; + render_state.projection_views[i].subImage.imageRect.offset.y = new_render_region.position.y; + render_state.projection_views[i].subImage.imageRect.extent.width = new_render_region.size.width; + render_state.projection_views[i].subImage.imageRect.extent.height = new_render_region.size.height; + } + if (render_state.submit_depth_buffer && OpenXRCompositionLayerDepthExtension::get_singleton()->is_available() && render_state.depth_views) { + for (uint32_t i = 0; i < render_state.view_count; i++) { + render_state.depth_views[i].subImage.imageRect.offset.x = new_render_region.position.x; + render_state.depth_views[i].subImage.imageRect.offset.y = new_render_region.position.y; + render_state.depth_views[i].subImage.imageRect.extent.width = new_render_region.size.width; + render_state.depth_views[i].subImage.imageRect.extent.height = new_render_region.size.height; + } + } + // must have: // - should_render set to true // - a valid view pose for projection_views[eye].pose to submit layer @@ -2500,14 +2531,10 @@ void OpenXRAPI::end_frame() { layer_flags |= XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT; } - XrCompositionLayerProjection projection_layer = { - XR_TYPE_COMPOSITION_LAYER_PROJECTION, // type - nullptr, // next - layer_flags, // layerFlags - render_state.play_space, // space - render_state.view_count, // viewCount - render_state.projection_views, // views - }; + render_state.projection_layer.layerFlags = layer_flags; + render_state.projection_layer.space = render_state.play_space; + render_state.projection_layer.viewCount = render_state.view_count; + render_state.projection_layer.views = render_state.projection_views; if (projection_views_extensions.size() > 0) { for (uint32_t v = 0; v < render_state.view_count; v++) { @@ -2522,7 +2549,7 @@ void OpenXRAPI::end_frame() { } } - ordered_layers_list.push_back({ (const XrCompositionLayerBaseHeader *)&projection_layer, 0 }); + ordered_layers_list.push_back({ (const XrCompositionLayerBaseHeader *)&render_state.projection_layer, 0 }); // Sort our layers. ordered_layers_list.sort_custom(); @@ -2584,6 +2611,15 @@ void OpenXRAPI::set_render_target_size_multiplier(double multiplier) { set_render_state_multiplier(multiplier); } +Rect2i OpenXRAPI::get_render_region() const { + return render_region; +} + +void OpenXRAPI::set_render_region(const Rect2i &p_render_region) { + render_region = p_render_region; + set_render_state_render_region(p_render_region); +} + bool OpenXRAPI::is_foveation_supported() const { OpenXRFBFoveationExtension *fov_ext = OpenXRFBFoveationExtension::get_singleton(); return fov_ext != nullptr && fov_ext->is_enabled(); diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h index e47c99b8fbc..7448fb55300 100644 --- a/modules/openxr/openxr_api.h +++ b/modules/openxr/openxr_api.h @@ -146,6 +146,7 @@ private: bool running = false; XrFrameState frame_state = { XR_TYPE_FRAME_STATE, nullptr, 0, 0, false }; double render_target_size_multiplier = 1.0; + Rect2i render_region; OpenXRGraphicsExtensionWrapper *graphics_extension = nullptr; XrSystemGraphicsProperties graphics_properties; @@ -344,6 +345,7 @@ private: XrSpace play_space = XR_NULL_HANDLE; double render_target_size_multiplier = 1.0; uint64_t frame = 0; + Rect2i render_region; uint32_t view_count = 0; XrView *views = nullptr; @@ -355,6 +357,15 @@ private: double z_near = 0.0; double z_far = 0.0; + XrCompositionLayerProjection projection_layer = { + XR_TYPE_COMPOSITION_LAYER_PROJECTION, // type + nullptr, // next + 0, // layerFlags + XR_NULL_HANDLE, // space + 0, // viewCount + nullptr // views + }; + Size2i main_swapchain_size; OpenXRSwapChainInfo main_swapchains[OPENXR_SWAPCHAIN_MAX]; } render_state; @@ -364,6 +375,7 @@ private: static void _set_render_display_info(XrTime p_predicted_display_time, bool p_should_render); static void _set_render_play_space(uint64_t p_play_space); static void _set_render_state_multiplier(double p_render_target_size_multiplier); + static void _set_render_state_render_region(const Rect2i &p_render_region); _FORCE_INLINE_ void allocate_view_buffers(uint32_t p_view_count, bool p_submit_depth_buffer) { // If we're rendering on a separate thread, we may still be processing the last frame, don't communicate this till we're ready... @@ -405,6 +417,13 @@ private: rendering_server->call_on_render_thread(callable_mp_static(&OpenXRAPI::_set_render_state_multiplier).bind(p_render_target_size_multiplier)); } + _FORCE_INLINE_ void set_render_state_render_region(const Rect2i &p_render_region) { + RenderingServer *rendering_server = RenderingServer::get_singleton(); + ERR_FAIL_NULL(rendering_server); + + rendering_server->call_on_render_thread(callable_mp_static(&OpenXRAPI::_set_render_state_render_region).bind(p_render_region)); + } + public: XrInstance get_instance() const { return instance; } XrSystemId get_system_id() const { return system_id; } @@ -494,6 +513,7 @@ public: RID get_velocity_depth_texture(); void set_velocity_target_size(const Size2i &p_target_size); Size2i get_velocity_target_size(); + const XrCompositionLayerProjection *get_projection_layer() const; void post_draw_viewport(RID p_render_target); void end_frame(); @@ -506,6 +526,9 @@ public: double get_render_target_size_multiplier() const; void set_render_target_size_multiplier(double multiplier); + Rect2i get_render_region() const; + void set_render_region(const Rect2i &p_render_region); + // Foveation settings bool is_foveation_supported() const; diff --git a/modules/openxr/openxr_api_extension.cpp b/modules/openxr/openxr_api_extension.cpp index 506e1fc64d3..378b9308e00 100644 --- a/modules/openxr/openxr_api_extension.cpp +++ b/modules/openxr/openxr_api_extension.cpp @@ -80,6 +80,10 @@ void OpenXRAPIExtension::_bind_methods() { ClassDB::bind_method(D_METHOD("openxr_swapchain_get_image", "swapchain"), &OpenXRAPIExtension::openxr_swapchain_get_image); ClassDB::bind_method(D_METHOD("openxr_swapchain_release", "swapchain"), &OpenXRAPIExtension::openxr_swapchain_release); + ClassDB::bind_method(D_METHOD("get_projection_layer"), &OpenXRAPIExtension::get_projection_layer); + + ClassDB::bind_method(D_METHOD("set_render_region", "render_region"), &OpenXRAPIExtension::set_render_region); + ClassDB::bind_method(D_METHOD("set_emulate_environment_blend_mode_alpha_blend", "enabled"), &OpenXRAPIExtension::set_emulate_environment_blend_mode_alpha_blend); ClassDB::bind_method(D_METHOD("is_environment_blend_mode_alpha_supported"), &OpenXRAPIExtension::is_environment_blend_mode_alpha_blend_supported); @@ -300,6 +304,16 @@ void OpenXRAPIExtension::openxr_swapchain_release(uint64_t p_swapchain_info) { swapchain_info->release(); } +uint64_t OpenXRAPIExtension::get_projection_layer() { + ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), 0); + return (uint64_t)OpenXRAPI::get_singleton()->get_projection_layer(); +} + +void OpenXRAPIExtension::set_render_region(const Rect2i &p_render_region) { + ERR_FAIL_NULL(OpenXRAPI::get_singleton()); + OpenXRAPI::get_singleton()->set_render_region(p_render_region); +} + void OpenXRAPIExtension::set_emulate_environment_blend_mode_alpha_blend(bool p_enabled) { ERR_FAIL_NULL(OpenXRAPI::get_singleton()); OpenXRAPI::get_singleton()->set_emulate_environment_blend_mode_alpha_blend(p_enabled); diff --git a/modules/openxr/openxr_api_extension.h b/modules/openxr/openxr_api_extension.h index 6519aea7f1a..9784b45ae31 100644 --- a/modules/openxr/openxr_api_extension.h +++ b/modules/openxr/openxr_api_extension.h @@ -101,6 +101,10 @@ public: RID openxr_swapchain_get_image(uint64_t p_swapchain_info); void openxr_swapchain_release(uint64_t p_swapchain_info); + uint64_t get_projection_layer(); + + void set_render_region(const Rect2i &p_render_region); + enum OpenXRAlphaBlendModeSupport { OPENXR_ALPHA_BLEND_MODE_SUPPORT_NONE = 0, OPENXR_ALPHA_BLEND_MODE_SUPPORT_REAL = 1, diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp index f79dba72b8f..561c30103b1 100644 --- a/modules/openxr/openxr_interface.cpp +++ b/modules/openxr/openxr_interface.cpp @@ -1055,6 +1055,14 @@ Projection OpenXRInterface::get_projection_for_view(uint32_t p_view, double p_as return cm; } +Rect2i OpenXRInterface::get_render_region() { + if (openxr_api) { + return openxr_api->get_render_region(); + } else { + return Rect2i(); + } +} + RID OpenXRInterface::get_color_texture() { if (openxr_api) { return openxr_api->get_color_texture(); @@ -1528,6 +1536,8 @@ RID OpenXRInterface::get_vrs_texture() { eye_foci.push_back(openxr_api->get_eye_focus(v, aspect_ratio)); } + xr_vrs.set_vrs_render_region(get_render_region()); + return xr_vrs.make_vrs_texture(target_size, eye_foci); } diff --git a/modules/openxr/openxr_interface.h b/modules/openxr/openxr_interface.h index b37c2eda290..8909d183b97 100644 --- a/modules/openxr/openxr_interface.h +++ b/modules/openxr/openxr_interface.h @@ -183,6 +183,8 @@ public: virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) override; virtual Projection get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) override; + virtual Rect2i get_render_region() override; + virtual RID get_color_texture() override; virtual RID get_depth_texture() override; virtual RID get_velocity_texture() override; diff --git a/servers/rendering/dummy/storage/texture_storage.h b/servers/rendering/dummy/storage/texture_storage.h index 35135ce860e..0788c6d26f7 100644 --- a/servers/rendering/dummy/storage/texture_storage.h +++ b/servers/rendering/dummy/storage/texture_storage.h @@ -206,6 +206,9 @@ public: virtual RID render_target_get_override_velocity(RID p_render_target) const override { return RID(); } virtual RID render_target_get_override_velocity_depth(RID p_render_target) const override { return RID(); } + virtual void render_target_set_render_region(RID p_render_target, const Rect2i &p_render_region) override {} + virtual Rect2i render_target_get_render_region(RID p_render_target) const override { return Rect2i(); } + virtual RID render_target_get_texture(RID p_render_target) override { return RID(); } virtual void render_target_set_velocity_target_size(RID p_render_target, const Size2i &p_target_size) override {} diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index 1a48e462054..8b4871f337c 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -2023,7 +2023,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co bool finish_depth = using_ssao || using_ssil || using_sdfgi || using_voxelgi || ce_pre_opaque_resolved_depth || ce_post_opaque_resolved_depth; RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, depth_pass_mode, 0, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count, 0, base_specialization); - _render_list_with_draw_list(&render_list_params, depth_framebuffer, RD::DrawFlags(needs_pre_resolve ? RD::DRAW_DEFAULT_ALL : RD::DRAW_CLEAR_ALL), depth_pass_clear, 0.0f); + _render_list_with_draw_list(&render_list_params, depth_framebuffer, RD::DrawFlags(needs_pre_resolve ? RD::DRAW_DEFAULT_ALL : RD::DRAW_CLEAR_ALL), depth_pass_clear, 0.0f, 0u, p_render_data->render_region); RD::get_singleton()->draw_command_end_label(); @@ -2102,7 +2102,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co uint32_t opaque_color_pass_flags = using_motion_pass ? (color_pass_flags & ~uint32_t(COLOR_PASS_FLAG_MOTION_VECTORS)) : color_pass_flags; RID opaque_framebuffer = using_motion_pass ? rb_data->get_color_pass_fb(opaque_color_pass_flags) : color_framebuffer; RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, opaque_color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count, 0, base_specialization); - _render_list_with_draw_list(&render_list_params, opaque_framebuffer, RD::DrawFlags(load_color ? RD::DRAW_DEFAULT_ALL : RD::DRAW_CLEAR_COLOR_ALL) | (depth_pre_pass ? RD::DRAW_DEFAULT_ALL : RD::DRAW_CLEAR_DEPTH), c, 0.0f); + _render_list_with_draw_list(&render_list_params, opaque_framebuffer, RD::DrawFlags(load_color ? RD::DRAW_DEFAULT_ALL : RD::DRAW_CLEAR_COLOR_ALL) | (depth_pre_pass ? RD::DRAW_DEFAULT_ALL : RD::DRAW_CLEAR_DEPTH), c, 0.0f, 0u, p_render_data->render_region); } RD::get_singleton()->draw_command_end_label(); @@ -2172,7 +2172,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co RENDER_TIMESTAMP("Render Sky"); RD::get_singleton()->draw_command_begin_label("Draw Sky"); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(color_only_framebuffer); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(color_only_framebuffer, RD::DRAW_DEFAULT_ALL, Vector(), 1.0f, 0u, p_render_data->render_region); sky.draw_sky(draw_list, rb, p_render_data->environment, color_only_framebuffer, time, sky_energy_multiplier); @@ -2301,7 +2301,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co RID alpha_framebuffer = rb_data.is_valid() ? rb_data->get_color_pass_fb(transparent_color_pass_flags) : color_only_framebuffer; RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, transparent_color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count, 0, base_specialization); - _render_list_with_draw_list(&render_list_params, alpha_framebuffer); + _render_list_with_draw_list(&render_list_params, alpha_framebuffer, RD::DRAW_DEFAULT_ALL, Vector(), 0.0f, 0u, p_render_data->render_region); } RD::get_singleton()->draw_command_end_label(); diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 41027ea7773..482c61767ab 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -1089,7 +1089,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color } } - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, load_color ? RD::DRAW_CLEAR_DEPTH : (RD::DRAW_CLEAR_COLOR_0 | RD::DRAW_CLEAR_DEPTH), c, 0.0f, 0, Rect2(), breadcrumb); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, load_color ? RD::DRAW_CLEAR_DEPTH : (RD::DRAW_CLEAR_COLOR_0 | RD::DRAW_CLEAR_DEPTH), c, 0.0f, 0, p_render_data->render_region, breadcrumb); RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer); if (copy_canvas) { @@ -1186,7 +1186,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color render_list_params.framebuffer_format = fb_format; render_list_params.subpass = RD::get_singleton()->draw_list_get_current_pass(); // Should now always be 0. - draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::DRAW_DEFAULT_ALL, Vector(), 1.0f, 0, Rect2(), breadcrumb); + draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::DRAW_DEFAULT_ALL, Vector(), 1.0f, 0, p_render_data->render_region, breadcrumb); _render_list(draw_list, fb_format, &render_list_params, 0, render_list_params.element_count); RD::get_singleton()->draw_list_end(); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 23685473fea..b6dc5daeadc 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -1219,6 +1219,7 @@ void RendererSceneRenderRD::render_scene(const Ref &p_render if (p_render_buffers.is_valid() && p_reflection_probe.is_null()) { render_data.transparent_bg = texture_storage->render_target_get_transparent(rb->get_render_target()); + render_data.render_region = texture_storage->render_target_get_render_region(rb->get_render_target()); } } diff --git a/servers/rendering/renderer_rd/storage_rd/render_data_rd.h b/servers/rendering/renderer_rd/storage_rd/render_data_rd.h index 888527e1ef8..ddb77a5fc59 100644 --- a/servers/rendering/renderer_rd/storage_rd/render_data_rd.h +++ b/servers/rendering/renderer_rd/storage_rd/render_data_rd.h @@ -79,6 +79,7 @@ public: /* Viewport data */ bool transparent_bg = false; + Rect2i render_region; /* Shadow data */ const RendererSceneRender::RenderShadowData *render_shadows = nullptr; diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index 163ad40d78b..daf376b8c7a 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -3515,6 +3515,20 @@ RID TextureStorage::render_target_get_override_velocity_slice(RID p_render_targe } } +void RendererRD::TextureStorage::render_target_set_render_region(RID p_render_target, const Rect2i &p_render_region) { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_NULL(rt); + + rt->render_region = p_render_region; +} + +Rect2i RendererRD::TextureStorage::render_target_get_render_region(RID p_render_target) const { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_NULL_V(rt, Rect2i()); + + return rt->render_region; +} + void TextureStorage::render_target_set_transparent(RID p_render_target, bool p_is_transparent) { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_NULL(rt); diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h index cfd85b28167..f47b5db2260 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h @@ -389,6 +389,8 @@ private: RS::ViewportVRSUpdateMode vrs_update_mode = RS::VIEWPORT_VRS_UPDATE_ONCE; RID vrs_texture; + Rect2i render_region; + // overridden textures struct RTOverridden { RID color; @@ -787,6 +789,9 @@ public: RID render_target_get_override_velocity_slice(RID p_render_target, const uint32_t p_layer) const; virtual RID render_target_get_override_velocity_depth(RID p_render_target) const override { return RID(); } + virtual void render_target_set_render_region(RID p_render_target, const Rect2i &p_render_region) override; + virtual Rect2i render_target_get_render_region(RID p_render_target) const override; + virtual RID render_target_get_texture(RID p_render_target) override; virtual void render_target_set_velocity_target_size(RID p_render_target, const Size2i &p_target_size) override {} diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index cdb055f1f0c..938b660a16e 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -800,6 +800,8 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) { viewport_set_force_motion_vectors(vp->self, false); } + RSG::texture_storage->render_target_set_render_region(vp->render_target, xr_interface->get_render_region()); + // render... RSG::scene->set_debug_draw_mode(vp->debug_draw); diff --git a/servers/rendering/storage/texture_storage.h b/servers/rendering/storage/texture_storage.h index 45e21a70556..fc4709547fa 100644 --- a/servers/rendering/storage/texture_storage.h +++ b/servers/rendering/storage/texture_storage.h @@ -184,6 +184,9 @@ public: virtual RID render_target_get_override_velocity(RID p_render_target) const = 0; virtual RID render_target_get_override_velocity_depth(RID p_render_target) const = 0; + virtual void render_target_set_render_region(RID p_render_target, const Rect2i &p_render_region) = 0; + virtual Rect2i render_target_get_render_region(RID p_render_target) const = 0; + // get textures virtual RID render_target_get_texture(RID p_render_target) = 0; diff --git a/servers/xr/xr_interface.cpp b/servers/xr/xr_interface.cpp index c7fc017d781..56834ddf52d 100644 --- a/servers/xr/xr_interface.cpp +++ b/servers/xr/xr_interface.cpp @@ -195,6 +195,10 @@ Size2i XRInterface::get_velocity_target_size() { return Size2i(); } +Rect2i XRInterface::get_render_region() { + return Rect2i(); +} + PackedStringArray XRInterface::get_suggested_tracker_names() const { PackedStringArray arr; diff --git a/servers/xr/xr_interface.h b/servers/xr/xr_interface.h index 883eb9cbc5f..38e44247641 100644 --- a/servers/xr/xr_interface.h +++ b/servers/xr/xr_interface.h @@ -139,6 +139,7 @@ public: virtual RID get_velocity_texture(); /* obtain velocity output texture (if applicable, used for spacewarp) */ virtual RID get_velocity_depth_texture(); virtual Size2i get_velocity_target_size(); + virtual Rect2i get_render_region(); 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 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/xr_vrs.cpp b/servers/xr/xr_vrs.cpp index 3e283a42f06..8edefda889c 100644 --- a/servers/xr/xr_vrs.cpp +++ b/servers/xr/xr_vrs.cpp @@ -40,8 +40,12 @@ void XRVRS::_bind_methods() { ClassDB::bind_method(D_METHOD("get_vrs_strength"), &XRVRS::get_vrs_strength); ClassDB::bind_method(D_METHOD("set_vrs_strength", "strength"), &XRVRS::set_vrs_strength); + ClassDB::bind_method(D_METHOD("get_vrs_render_region"), &XRVRS::get_vrs_render_region); + ClassDB::bind_method(D_METHOD("set_vrs_render_region", "render_region"), &XRVRS::set_vrs_render_region); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "vrs_min_radius", PROPERTY_HINT_RANGE, "1.0,100.0,1.0"), "set_vrs_min_radius", "get_vrs_min_radius"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "vrs_strength", PROPERTY_HINT_RANGE, "0.1,10.0,0.1"), "set_vrs_strength", "get_vrs_strength"); + ADD_PROPERTY(PropertyInfo(Variant::RECT2I, "vrs_render_region"), "set_vrs_render_region", "get_vrs_render_region"); ClassDB::bind_method(D_METHOD("make_vrs_texture", "target_size", "eye_foci"), &XRVRS::make_vrs_texture); } @@ -88,6 +92,15 @@ void XRVRS::set_vrs_strength(float p_vrs_strength) { } } +Rect2i XRVRS::get_vrs_render_region() const { + return vrs_render_region; +} + +void XRVRS::set_vrs_render_region(const Rect2i &p_vrs_render_region) { + vrs_render_region = p_vrs_render_region; + vrs_dirty = true; +} + RID XRVRS::make_vrs_texture(const Size2 &p_target_size, const PackedVector2Array &p_eye_foci) { ERR_FAIL_COND_V(p_eye_foci.is_empty(), RID()); @@ -123,19 +136,26 @@ RID XRVRS::make_vrs_texture(const Size2 &p_target_size, const PackedVector2Array target_size = vrs_sizei; eye_foci = p_eye_foci; + Size2 region_ratio = Size2(1.0, 1.0); + Point2i region_offset; + if (vrs_render_region != Rect2i()) { + region_ratio = (Size2)vrs_render_region.size / p_target_size; + region_offset = (Point2)vrs_render_region.position / p_target_size * vrs_sizei; + } + for (int i = 0; i < eye_foci.size() && i < RendererSceneRender::MAX_RENDER_VIEWS; i++) { PackedByteArray data; data.resize(vrs_sizei.x * vrs_sizei.y * 2); uint8_t *data_ptr = data.ptrw(); Vector2i view_center; - view_center.x = int(vrs_size.x * (eye_foci[i].x + 1.0) * 0.5); - view_center.y = int(vrs_size.y * (eye_foci[i].y + 1.0) * 0.5); + view_center.x = int(vrs_size.x * (eye_foci[i].x + 1.0) * region_ratio.x * 0.5) + region_offset.x; + view_center.y = int(vrs_size.y * (eye_foci[i].y + 1.0) * region_ratio.y * 0.5) + region_offset.y; int d = 0; for (int y = 0; y < vrs_sizei.y; y++) { for (int x = 0; x < vrs_sizei.x; x++) { - Vector2 offset = Vector2(x - view_center.x, y - view_center.y); + Vector2 offset = Vector2(x - view_center.x, y - view_center.y) / region_ratio; real_t density = 255.0 * MAX(0.0, (Math::abs(offset.x) - min_radius) / outer_radius); data_ptr[d++] = MIN(255, density); density = 255.0 * MAX(0.0, (Math::abs(offset.y) - min_radius) / outer_radius); diff --git a/servers/xr/xr_vrs.h b/servers/xr/xr_vrs.h index 35dfe55620d..b3b22537f3e 100644 --- a/servers/xr/xr_vrs.h +++ b/servers/xr/xr_vrs.h @@ -44,6 +44,7 @@ class XRVRS : public Object { private: float vrs_min_radius = 20.0; float vrs_strength = 1.0; + Rect2i vrs_render_region; bool vrs_dirty = true; RID vrs_texture; @@ -60,6 +61,8 @@ public: void set_vrs_min_radius(float p_vrs_min_radius); float get_vrs_strength() const; void set_vrs_strength(float p_vrs_strength); + Rect2i get_vrs_render_region() const; + void set_vrs_render_region(const Rect2i &p_vrs_render_region); RID make_vrs_texture(const Size2 &p_target_size, const PackedVector2Array &p_eye_foci); };