Merge pull request #99407 from devloglogan/rec-resolution

Allow using custom `Rect2i` for rendering with OpenXR
This commit is contained in:
Rémi Verschelde 2025-01-10 23:05:46 +01:00
commit 3014eec40d
25 changed files with 215 additions and 19 deletions

View file

@ -23,6 +23,9 @@
<member name="vrs_min_radius" type="float" setter="set_vrs_min_radius" getter="get_vrs_min_radius" default="20.0"> <member name="vrs_min_radius" type="float" setter="set_vrs_min_radius" getter="get_vrs_min_radius" default="20.0">
The minimum radius around the focal point where full quality is guaranteed if VRS is used as a percentage of screen size. The minimum radius around the focal point where full quality is guaranteed if VRS is used as a percentage of screen size.
</member> </member>
<member name="vrs_render_region" type="Rect2i" setter="set_vrs_render_region" getter="get_vrs_render_region" default="Rect2i(0, 0, 0, 0)">
The render region that the VRS texture will be scaled to when generated.
</member>
<member name="vrs_strength" type="float" setter="set_vrs_strength" getter="get_vrs_strength" default="1.0"> <member name="vrs_strength" type="float" setter="set_vrs_strength" getter="get_vrs_strength" default="1.0">
The strength used to calculate the VRS density map. The greater this value, the more noticeable VRS is. The strength used to calculate the VRS density map. The greater this value, the more noticeable VRS is.
</member> </member>

View file

@ -2254,7 +2254,12 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
RenderDataGLES3 render_data; RenderDataGLES3 render_data;
{ {
render_data.render_buffers = rb; 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 // Our first camera is used by default
render_data.cam_transform = p_camera_data->main_transform; render_data.cam_transform = p_camera_data->main_transform;
render_data.inv_cam_transform = render_data.cam_transform.affine_inverse(); render_data.inv_cam_transform = render_data.cam_transform.affine_inverse();
@ -2493,6 +2498,10 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
RENDER_TIMESTAMP("Depth Prepass"); RENDER_TIMESTAMP("Depth Prepass");
//pre z pass //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_test(true);
scene_state.enable_gl_depth_draw(true); scene_state.enable_gl_depth_draw(true);
scene_state.enable_gl_blend(false); scene_state.enable_gl_blend(false);
@ -2572,6 +2581,10 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
RENDER_TIMESTAMP("Render Opaque Pass"); RENDER_TIMESTAMP("Render Opaque Pass");
uint64_t spec_constant_base_flags = 0; 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. // Specialization Constants that apply for entire rendering pass.
if (render_data.directional_light_count == 0) { if (render_data.directional_light_count == 0) {

View file

@ -98,6 +98,7 @@ enum SkyUniformLocation {
struct RenderDataGLES3 { struct RenderDataGLES3 {
Ref<RenderSceneBuffersGLES3> render_buffers; Ref<RenderSceneBuffersGLES3> render_buffers;
bool transparent_bg = false; bool transparent_bg = false;
Rect2i render_region;
Transform3D cam_transform; Transform3D cam_transform;
Transform3D inv_cam_transform; Transform3D inv_cam_transform;

View file

@ -2568,6 +2568,20 @@ RID TextureStorage::render_target_get_override_velocity(RID p_render_target) con
return rt->overridden.velocity; 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) { RID TextureStorage::render_target_get_texture(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target); RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_NULL_V(rt, RID()); ERR_FAIL_NULL_V(rt, RID());

View file

@ -372,6 +372,8 @@ struct RenderTarget {
RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED; RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;
bool reattach_textures = false; bool reattach_textures = false;
Rect2i render_region;
struct RTOverridden { struct RTOverridden {
bool is_overridden = false; bool is_overridden = false;
RID color; 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(RID p_render_target) const override;
virtual RID render_target_get_override_velocity_depth(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;
virtual RID render_target_get_texture(RID p_render_target) 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 {} virtual void render_target_set_velocity_target_size(RID p_render_target, const Size2i &p_target_size) override {}

View file

@ -82,6 +82,13 @@
Returns the predicted display timing for the current frame. Returns the predicted display timing for the current frame.
</description> </description>
</method> </method>
<method name="get_projection_layer">
<return type="int" />
<description>
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.
</description>
</method>
<method name="get_render_state_z_far"> <method name="get_render_state_z_far">
<return type="float" /> <return type="float" />
<description> <description>
@ -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. 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.
</description> </description>
</method> </method>
<method name="set_render_region">
<return type="void" />
<param index="0" name="render_region" type="Rect2i" />
<description>
Sets the render region to [param render_region], overriding the normal render target's rect.
</description>
</method>
<method name="set_velocity_depth_texture"> <method name="set_velocity_depth_texture">
<return type="void" /> <return type="void" />
<param index="0" name="render_target" type="RID" /> <param index="0" name="render_target" type="RID" />

View file

@ -2167,6 +2167,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; 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() { bool OpenXRAPI::process() {
ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false); ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false);
@ -2399,6 +2407,12 @@ Size2i OpenXRAPI::get_velocity_target_size() {
return 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) { void OpenXRAPI::post_draw_viewport(RID p_render_target) {
// Must be called from rendering thread! // Must be called from rendering thread!
ERR_NOT_ON_RENDER_THREAD; ERR_NOT_ON_RENDER_THREAD;
@ -2432,6 +2446,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: // must have:
// - should_render set to true // - should_render set to true
// - a valid view pose for projection_views[eye].pose to submit layer // - a valid view pose for projection_views[eye].pose to submit layer
@ -2496,14 +2527,10 @@ void OpenXRAPI::end_frame() {
layer_flags |= XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT; layer_flags |= XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
} }
XrCompositionLayerProjection projection_layer = { render_state.projection_layer.layerFlags = layer_flags;
XR_TYPE_COMPOSITION_LAYER_PROJECTION, // type render_state.projection_layer.space = render_state.play_space;
nullptr, // next render_state.projection_layer.viewCount = render_state.view_count;
layer_flags, // layerFlags render_state.projection_layer.views = render_state.projection_views;
render_state.play_space, // space
render_state.view_count, // viewCount
render_state.projection_views, // views
};
if (projection_views_extensions.size() > 0) { if (projection_views_extensions.size() > 0) {
for (uint32_t v = 0; v < render_state.view_count; v++) { for (uint32_t v = 0; v < render_state.view_count; v++) {
@ -2518,7 +2545,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. // Sort our layers.
ordered_layers_list.sort_custom<OrderedCompositionLayer>(); ordered_layers_list.sort_custom<OrderedCompositionLayer>();
@ -2580,6 +2607,15 @@ void OpenXRAPI::set_render_target_size_multiplier(double multiplier) {
set_render_state_multiplier(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 { bool OpenXRAPI::is_foveation_supported() const {
OpenXRFBFoveationExtension *fov_ext = OpenXRFBFoveationExtension::get_singleton(); OpenXRFBFoveationExtension *fov_ext = OpenXRFBFoveationExtension::get_singleton();
return fov_ext != nullptr && fov_ext->is_enabled(); return fov_ext != nullptr && fov_ext->is_enabled();

View file

@ -143,6 +143,7 @@ private:
bool running = false; bool running = false;
XrFrameState frame_state = { XR_TYPE_FRAME_STATE, nullptr, 0, 0, false }; XrFrameState frame_state = { XR_TYPE_FRAME_STATE, nullptr, 0, 0, false };
double render_target_size_multiplier = 1.0; double render_target_size_multiplier = 1.0;
Rect2i render_region;
OpenXRGraphicsExtensionWrapper *graphics_extension = nullptr; OpenXRGraphicsExtensionWrapper *graphics_extension = nullptr;
XrSystemGraphicsProperties graphics_properties; XrSystemGraphicsProperties graphics_properties;
@ -341,6 +342,7 @@ private:
XrSpace play_space = XR_NULL_HANDLE; XrSpace play_space = XR_NULL_HANDLE;
double render_target_size_multiplier = 1.0; double render_target_size_multiplier = 1.0;
uint64_t frame = 0; uint64_t frame = 0;
Rect2i render_region;
uint32_t view_count = 0; uint32_t view_count = 0;
XrView *views = nullptr; XrView *views = nullptr;
@ -352,6 +354,15 @@ private:
double z_near = 0.0; double z_near = 0.0;
double z_far = 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; Size2i main_swapchain_size;
OpenXRSwapChainInfo main_swapchains[OPENXR_SWAPCHAIN_MAX]; OpenXRSwapChainInfo main_swapchains[OPENXR_SWAPCHAIN_MAX];
} render_state; } render_state;
@ -361,6 +372,7 @@ private:
static void _set_render_display_info(XrTime p_predicted_display_time, bool p_should_render); 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_play_space(uint64_t p_play_space);
static void _set_render_state_multiplier(double p_render_target_size_multiplier); 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) { _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... // If we're rendering on a separate thread, we may still be processing the last frame, don't communicate this till we're ready...
@ -402,6 +414,13 @@ private:
rendering_server->call_on_render_thread(callable_mp_static(&OpenXRAPI::_set_render_state_multiplier).bind(p_render_target_size_multiplier)); 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: public:
XrInstance get_instance() const { return instance; } XrInstance get_instance() const { return instance; }
XrSystemId get_system_id() const { return system_id; } XrSystemId get_system_id() const { return system_id; }
@ -491,6 +510,7 @@ public:
RID get_velocity_depth_texture(); RID get_velocity_depth_texture();
void set_velocity_target_size(const Size2i &p_target_size); void set_velocity_target_size(const Size2i &p_target_size);
Size2i get_velocity_target_size(); Size2i get_velocity_target_size();
const XrCompositionLayerProjection *get_projection_layer() const;
void post_draw_viewport(RID p_render_target); void post_draw_viewport(RID p_render_target);
void end_frame(); void end_frame();
@ -503,6 +523,9 @@ public:
double get_render_target_size_multiplier() const; double get_render_target_size_multiplier() const;
void set_render_target_size_multiplier(double multiplier); void set_render_target_size_multiplier(double multiplier);
Rect2i get_render_region() const;
void set_render_region(const Rect2i &p_render_region);
// Foveation settings // Foveation settings
bool is_foveation_supported() const; bool is_foveation_supported() const;

View file

@ -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_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("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("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); 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(); 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) { void OpenXRAPIExtension::set_emulate_environment_blend_mode_alpha_blend(bool p_enabled) {
ERR_FAIL_NULL(OpenXRAPI::get_singleton()); ERR_FAIL_NULL(OpenXRAPI::get_singleton());
OpenXRAPI::get_singleton()->set_emulate_environment_blend_mode_alpha_blend(p_enabled); OpenXRAPI::get_singleton()->set_emulate_environment_blend_mode_alpha_blend(p_enabled);

View file

@ -100,6 +100,10 @@ public:
RID openxr_swapchain_get_image(uint64_t p_swapchain_info); RID openxr_swapchain_get_image(uint64_t p_swapchain_info);
void openxr_swapchain_release(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 { enum OpenXRAlphaBlendModeSupport {
OPENXR_ALPHA_BLEND_MODE_SUPPORT_NONE = 0, OPENXR_ALPHA_BLEND_MODE_SUPPORT_NONE = 0,
OPENXR_ALPHA_BLEND_MODE_SUPPORT_REAL = 1, OPENXR_ALPHA_BLEND_MODE_SUPPORT_REAL = 1,

View file

@ -1055,6 +1055,14 @@ Projection OpenXRInterface::get_projection_for_view(uint32_t p_view, double p_as
return cm; return cm;
} }
Rect2i OpenXRInterface::get_render_region() {
if (openxr_api) {
return openxr_api->get_render_region();
} else {
return Rect2i();
}
}
RID OpenXRInterface::get_color_texture() { RID OpenXRInterface::get_color_texture() {
if (openxr_api) { if (openxr_api) {
return openxr_api->get_color_texture(); 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)); 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); return xr_vrs.make_vrs_texture(target_size, eye_foci);
} }

View file

@ -183,6 +183,8 @@ public:
virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) override; 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 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_color_texture() override;
virtual RID get_depth_texture() override; virtual RID get_depth_texture() override;
virtual RID get_velocity_texture() override; virtual RID get_velocity_texture() override;

View file

@ -205,6 +205,9 @@ public:
virtual RID render_target_get_override_velocity(RID p_render_target) const override { return RID(); } 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 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 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 {} virtual void render_target_set_velocity_target_size(RID p_render_target, const Size2i &p_target_size) override {}

View file

@ -2074,7 +2074,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; 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); 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(); RD::get_singleton()->draw_command_end_label();
@ -2153,7 +2153,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; 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; 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); 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(); RD::get_singleton()->draw_command_end_label();
@ -2229,7 +2229,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RENDER_TIMESTAMP("Render Sky"); RENDER_TIMESTAMP("Render Sky");
RD::get_singleton()->draw_command_begin_label("Draw 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<Color>(), 1.0f, 0u, p_render_data->render_region);
sky.draw_sky(draw_list, rb, p_render_data->environment, color_only_framebuffer, time, sky_luminance_multiplier, sky_brightness_multiplier); sky.draw_sky(draw_list, rb, p_render_data->environment, color_only_framebuffer, time, sky_luminance_multiplier, sky_brightness_multiplier);
@ -2358,7 +2358,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; 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); 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<Color>(), 0.0f, 0u, p_render_data->render_region);
} }
RD::get_singleton()->draw_command_end_label(); RD::get_singleton()->draw_command_end_label();

View file

@ -1099,7 +1099,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); RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
if (copy_canvas) { if (copy_canvas) {
@ -1196,7 +1196,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
render_list_params.framebuffer_format = fb_format; render_list_params.framebuffer_format = fb_format;
render_list_params.subpass = RD::get_singleton()->draw_list_get_current_pass(); // Should now always be 0. 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<Color>(), 1.0f, 0, Rect2(), breadcrumb); draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::DRAW_DEFAULT_ALL, Vector<Color>(), 1.0f, 0, p_render_data->render_region, breadcrumb);
_render_list(draw_list, fb_format, &render_list_params, 0, render_list_params.element_count); _render_list(draw_list, fb_format, &render_list_params, 0, render_list_params.element_count);
RD::get_singleton()->draw_list_end(); RD::get_singleton()->draw_list_end();

View file

@ -1228,6 +1228,7 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render
if (p_render_buffers.is_valid() && p_reflection_probe.is_null()) { 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.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());
} }
} }

View file

@ -79,6 +79,7 @@ public:
/* Viewport data */ /* Viewport data */
bool transparent_bg = false; bool transparent_bg = false;
Rect2i render_region;
/* Shadow data */ /* Shadow data */
const RendererSceneRender::RenderShadowData *render_shadows = nullptr; const RendererSceneRender::RenderShadowData *render_shadows = nullptr;

View file

@ -3525,6 +3525,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) { 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); RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_NULL(rt); ERR_FAIL_NULL(rt);

View file

@ -388,6 +388,8 @@ private:
RS::ViewportVRSUpdateMode vrs_update_mode = RS::VIEWPORT_VRS_UPDATE_ONCE; RS::ViewportVRSUpdateMode vrs_update_mode = RS::VIEWPORT_VRS_UPDATE_ONCE;
RID vrs_texture; RID vrs_texture;
Rect2i render_region;
// overridden textures // overridden textures
struct RTOverridden { struct RTOverridden {
RID color; RID color;
@ -786,6 +788,9 @@ public:
RID render_target_get_override_velocity_slice(RID p_render_target, const uint32_t p_layer) const; 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 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 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 {} virtual void render_target_set_velocity_target_size(RID p_render_target, const Size2i &p_target_size) override {}

View file

@ -832,6 +832,8 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) {
viewport_set_force_motion_vectors(vp->self, false); 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... // render...
RSG::scene->set_debug_draw_mode(vp->debug_draw); RSG::scene->set_debug_draw_mode(vp->debug_draw);

View file

@ -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(RID p_render_target) const = 0;
virtual RID render_target_get_override_velocity_depth(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 // get textures
virtual RID render_target_get_texture(RID p_render_target) = 0; virtual RID render_target_get_texture(RID p_render_target) = 0;

View file

@ -194,6 +194,10 @@ Size2i XRInterface::get_velocity_target_size() {
return Size2i(); return Size2i();
} }
Rect2i XRInterface::get_render_region() {
return Rect2i();
}
PackedStringArray XRInterface::get_suggested_tracker_names() const { PackedStringArray XRInterface::get_suggested_tracker_names() const {
PackedStringArray arr; PackedStringArray arr;

View file

@ -139,6 +139,7 @@ public:
virtual RID get_velocity_texture(); /* obtain velocity output texture (if applicable, used for spacewarp) */ virtual RID get_velocity_texture(); /* obtain velocity output texture (if applicable, used for spacewarp) */
virtual RID get_velocity_depth_texture(); virtual RID get_velocity_depth_texture();
virtual Size2i get_velocity_target_size(); virtual Size2i get_velocity_target_size();
virtual Rect2i get_render_region();
virtual void pre_render() {} 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 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 */ 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 */

View file

@ -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("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("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_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::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); 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) { 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()); 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; target_size = vrs_sizei;
eye_foci = p_eye_foci; 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++) { for (int i = 0; i < eye_foci.size() && i < RendererSceneRender::MAX_RENDER_VIEWS; i++) {
PackedByteArray data; PackedByteArray data;
data.resize(vrs_sizei.x * vrs_sizei.y * 2); data.resize(vrs_sizei.x * vrs_sizei.y * 2);
uint8_t *data_ptr = data.ptrw(); uint8_t *data_ptr = data.ptrw();
Vector2i view_center; Vector2i view_center;
view_center.x = int(vrs_size.x * (eye_foci[i].x + 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) * 0.5); view_center.y = int(vrs_size.y * (eye_foci[i].y + 1.0) * region_ratio.y * 0.5) + region_offset.y;
int d = 0; int d = 0;
for (int y = 0; y < vrs_sizei.y; y++) { for (int y = 0; y < vrs_sizei.y; y++) {
for (int x = 0; x < vrs_sizei.x; x++) { 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); real_t density = 255.0 * MAX(0.0, (Math::abs(offset.x) - min_radius) / outer_radius);
data_ptr[d++] = MIN(255, density); data_ptr[d++] = MIN(255, density);
density = 255.0 * MAX(0.0, (Math::abs(offset.y) - min_radius) / outer_radius); density = 255.0 * MAX(0.0, (Math::abs(offset.y) - min_radius) / outer_radius);

View file

@ -44,6 +44,7 @@ class XRVRS : public Object {
private: private:
float vrs_min_radius = 20.0; float vrs_min_radius = 20.0;
float vrs_strength = 1.0; float vrs_strength = 1.0;
Rect2i vrs_render_region;
bool vrs_dirty = true; bool vrs_dirty = true;
RID vrs_texture; RID vrs_texture;
@ -60,6 +61,8 @@ public:
void set_vrs_min_radius(float p_vrs_min_radius); void set_vrs_min_radius(float p_vrs_min_radius);
float get_vrs_strength() const; float get_vrs_strength() const;
void set_vrs_strength(float p_vrs_strength); 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); RID make_vrs_texture(const Size2 &p_target_size, const PackedVector2Array &p_eye_foci);
}; };