summaryrefslogtreecommitdiff
path: root/servers/rendering/renderer_viewport.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'servers/rendering/renderer_viewport.cpp')
-rw-r--r--servers/rendering/renderer_viewport.cpp261
1 files changed, 168 insertions, 93 deletions
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index 0e26de8bcb..55653b5945 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -72,11 +72,48 @@ static Transform2D _canvas_get_transform(RendererViewport::Viewport *p_viewport,
return xf;
}
+Vector<RendererViewport::Viewport *> RendererViewport::_sort_active_viewports() {
+ // We need to sort the viewports in a "topological order", children first and
+ // parents last. We also need to keep sibling viewports in the original order
+ // from top to bottom.
+
+ Vector<Viewport *> result;
+ List<Viewport *> nodes;
+
+ for (int i = active_viewports.size() - 1; i >= 0; --i) {
+ Viewport *viewport = active_viewports[i];
+ if (viewport->parent.is_valid()) {
+ continue;
+ }
+
+ nodes.push_back(viewport);
+ result.insert(0, viewport);
+ }
+
+ while (!nodes.is_empty()) {
+ const Viewport *node = nodes[0];
+ nodes.pop_front();
+
+ for (int i = active_viewports.size() - 1; i >= 0; --i) {
+ Viewport *child = active_viewports[i];
+ if (child->parent != node->self) {
+ continue;
+ }
+
+ if (!nodes.find(child)) {
+ nodes.push_back(child);
+ result.insert(0, child);
+ }
+ }
+ }
+
+ return result;
+}
+
void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) {
if (p_viewport->render_buffers.is_valid()) {
if (p_viewport->size.width == 0 || p_viewport->size.height == 0) {
- RSG::scene->free(p_viewport->render_buffers);
- p_viewport->render_buffers = RID();
+ p_viewport->render_buffers.unref();
} else {
const float scaling_3d_scale = p_viewport->scaling_3d_scale;
RS::ViewportScaling3DMode scaling_3d_mode = p_viewport->scaling_3d_mode;
@@ -138,7 +175,11 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) {
p_viewport->internal_size = Size2(render_width, render_height);
- RSG::scene->render_buffers_configure(p_viewport->render_buffers, p_viewport->render_target, render_width, render_height, width, height, p_viewport->fsr_sharpness, p_viewport->fsr_mipmap_bias, p_viewport->msaa, p_viewport->screen_space_aa, p_viewport->use_taa, p_viewport->use_debanding, p_viewport->get_view_count());
+ // At resolution scales lower than 1.0, use negative texture mipmap bias
+ // to compensate for the loss of sharpness.
+ const float texture_mipmap_bias = log2f(MIN(scaling_3d_scale, 1.0)) + p_viewport->texture_mipmap_bias;
+
+ p_viewport->render_buffers->configure(p_viewport->render_target, Size2i(render_width, render_height), Size2(width, height), p_viewport->fsr_sharpness, texture_mipmap_bias, p_viewport->msaa_3d, p_viewport->screen_space_aa, p_viewport->use_taa, p_viewport->use_debanding, p_viewport->view_count);
}
}
}
@@ -179,7 +220,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) {
timestamp_vp_map[rt_id] = p_viewport->self;
}
- if (OS::get_singleton()->get_current_rendering_driver_name() == "opengl3") {
+ if (OS::get_singleton()->get_current_rendering_method() == "gl_compatibility") {
// This is currently needed for GLES to keep the current window being rendered to up to date
DisplayServer::get_singleton()->gl_window_make_current(p_viewport->viewport_to_screen);
}
@@ -544,8 +585,10 @@ void RendererViewport::draw_viewports() {
set_default_clear_color(GLOBAL_GET("rendering/environment/defaults/default_clear_color"));
}
- //sort viewports
- active_viewports.sort_custom<ViewportSort>();
+ if (sorted_active_viewports_dirty) {
+ sorted_active_viewports = _sort_active_viewports();
+ sorted_active_viewports_dirty = false;
+ }
HashMap<DisplayServer::WindowID, Vector<BlitToScreen>> blit_to_screen_list;
//draw viewports
@@ -554,9 +597,9 @@ void RendererViewport::draw_viewports() {
//determine what is visible
draw_viewports_pass++;
- for (int i = active_viewports.size() - 1; i >= 0; i--) { //to compute parent dependency, must go in reverse draw order
+ for (int i = sorted_active_viewports.size() - 1; i >= 0; i--) { //to compute parent dependency, must go in reverse draw order
- Viewport *vp = active_viewports[i];
+ Viewport *vp = sorted_active_viewports[i];
if (vp->update_mode == RS::VIEWPORT_UPDATE_DISABLED) {
continue;
@@ -571,39 +614,32 @@ void RendererViewport::draw_viewports() {
if (vp->use_xr) {
if (xr_interface.is_valid()) {
+ // Ignore update mode we have to commit frames to our XR interface
+ visible = true;
+
// Override our size, make sure it matches our required size and is created as a stereo target
Size2 xr_size = xr_interface->get_render_target_size();
-
- // Would have been nice if we could call viewport_set_size here,
- // but alas that takes our RID and we now have our pointer,
- // also we only check if view_count changes in render_target_set_size so we need to call that for this to reliably change
- vp->occlusion_buffer_dirty = vp->occlusion_buffer_dirty || (vp->size != xr_size);
- vp->size = xr_size;
- uint32_t view_count = xr_interface->get_view_count();
- RSG::texture_storage->render_target_set_size(vp->render_target, vp->size.x, vp->size.y, view_count);
-
- // Inform xr interface we're about to render its viewport, if this returns false we don't render
- visible = xr_interface->pre_draw_viewport(vp->render_target);
+ _viewport_set_size(vp, xr_size.width, xr_size.height, xr_interface->get_view_count());
} else {
// don't render anything
visible = false;
vp->size = Size2();
}
- }
-
- if (vp->update_mode == RS::VIEWPORT_UPDATE_ALWAYS || vp->update_mode == RS::VIEWPORT_UPDATE_ONCE) {
- visible = true;
- }
-
- if (vp->update_mode == RS::VIEWPORT_UPDATE_WHEN_VISIBLE && RSG::texture_storage->render_target_was_used(vp->render_target)) {
- visible = true;
- }
+ } else {
+ if (vp->update_mode == RS::VIEWPORT_UPDATE_ALWAYS || vp->update_mode == RS::VIEWPORT_UPDATE_ONCE) {
+ visible = true;
+ }
- if (vp->update_mode == RS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE) {
- Viewport *parent = viewport_owner.get_or_null(vp->parent);
- if (parent && parent->last_pass == draw_viewports_pass) {
+ if (vp->update_mode == RS::VIEWPORT_UPDATE_WHEN_VISIBLE && RSG::texture_storage->render_target_was_used(vp->render_target)) {
visible = true;
}
+
+ if (vp->update_mode == RS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE) {
+ Viewport *parent = viewport_owner.get_or_null(vp->parent);
+ if (parent && parent->last_pass == draw_viewports_pass) {
+ visible = true;
+ }
+ }
}
visible = visible && vp->size.x > 1 && vp->size.y > 1;
@@ -617,8 +653,8 @@ void RendererViewport::draw_viewports() {
int objects_drawn = 0;
int draw_calls_used = 0;
- for (int i = 0; i < active_viewports.size(); i++) {
- Viewport *vp = active_viewports[i];
+ for (int i = 0; i < sorted_active_viewports.size(); i++) {
+ Viewport *vp = sorted_active_viewports[i];
if (vp->last_pass != draw_viewports_pass) {
continue; //should not draw
@@ -628,31 +664,44 @@ void RendererViewport::draw_viewports() {
RSG::texture_storage->render_target_set_as_unused(vp->render_target);
if (vp->use_xr && xr_interface.is_valid()) {
- // check for an external texture destination (disabled for now, not yet supported)
- // RSG::texture_storage->render_target_set_external_texture(vp->render_target, xr_interface->get_external_texture_for_eye(leftOrMono));
- RSG::texture_storage->render_target_set_external_texture(vp->render_target, 0);
-
- // render...
- RSG::scene->set_debug_draw_mode(vp->debug_draw);
-
- // and draw viewport
- _draw_viewport(vp);
-
- // measure
-
- // commit our eyes
- Vector<BlitToScreen> blits = xr_interface->post_draw_viewport(vp->render_target, vp->viewport_to_screen_rect);
- if (vp->viewport_to_screen != DisplayServer::INVALID_WINDOW_ID && blits.size() > 0) {
- if (!blit_to_screen_list.has(vp->viewport_to_screen)) {
- blit_to_screen_list[vp->viewport_to_screen] = Vector<BlitToScreen>();
- }
+ // Inform XR interface we're about to render its viewport,
+ // if this returns false we don't render.
+ // This usually is a result of the player taking off their headset and OpenXR telling us to skip
+ // rendering frames.
+ if (xr_interface->pre_draw_viewport(vp->render_target)) {
+ RSG::texture_storage->render_target_set_override_color(vp->render_target, xr_interface->get_color_texture());
+ RSG::texture_storage->render_target_set_override_depth(vp->render_target, xr_interface->get_depth_texture());
+ RSG::texture_storage->render_target_set_override_velocity(vp->render_target, xr_interface->get_velocity_texture());
+
+ // render...
+ RSG::scene->set_debug_draw_mode(vp->debug_draw);
+
+ // and draw viewport
+ _draw_viewport(vp);
+
+ // commit our eyes
+ Vector<BlitToScreen> blits = xr_interface->post_draw_viewport(vp->render_target, vp->viewport_to_screen_rect);
+ if (vp->viewport_to_screen != DisplayServer::INVALID_WINDOW_ID) {
+ if (OS::get_singleton()->get_current_rendering_driver_name() == "opengl3") {
+ if (blits.size() > 0) {
+ RSG::rasterizer->blit_render_targets_to_screen(vp->viewport_to_screen, blits.ptr(), blits.size());
+ }
+ RSG::rasterizer->end_frame(true);
+ } else if (blits.size() > 0) {
+ if (!blit_to_screen_list.has(vp->viewport_to_screen)) {
+ blit_to_screen_list[vp->viewport_to_screen] = Vector<BlitToScreen>();
+ }
- for (int b = 0; b < blits.size(); b++) {
- blit_to_screen_list[vp->viewport_to_screen].push_back(blits[b]);
+ for (int b = 0; b < blits.size(); b++) {
+ blit_to_screen_list[vp->viewport_to_screen].push_back(blits[b]);
+ }
+ }
}
}
} else {
- RSG::texture_storage->render_target_set_external_texture(vp->render_target, 0);
+ RSG::texture_storage->render_target_set_override_color(vp->render_target, RID()); // TODO if fullscreen output, we can set this to our texture chain
+ RSG::texture_storage->render_target_set_override_depth(vp->render_target, RID());
+ RSG::texture_storage->render_target_set_override_velocity(vp->render_target, RID());
RSG::scene->set_debug_draw_mode(vp->debug_draw);
@@ -674,7 +723,14 @@ void RendererViewport::draw_viewports() {
blit_to_screen_list[vp->viewport_to_screen] = Vector<BlitToScreen>();
}
- blit_to_screen_list[vp->viewport_to_screen].push_back(blit);
+ if (OS::get_singleton()->get_current_rendering_driver_name() == "opengl3") {
+ Vector<BlitToScreen> blit_to_screen_vec;
+ blit_to_screen_vec.push_back(blit);
+ RSG::rasterizer->blit_render_targets_to_screen(vp->viewport_to_screen, blit_to_screen_vec.ptr(), 1);
+ RSG::rasterizer->end_frame(true);
+ } else {
+ blit_to_screen_list[vp->viewport_to_screen].push_back(blit);
+ }
}
}
@@ -712,7 +768,7 @@ void RendererViewport::viewport_initialize(RID p_rid) {
Viewport *viewport = viewport_owner.get_or_null(p_rid);
viewport->self = p_rid;
viewport->render_target = RSG::texture_storage->render_target_create();
- viewport->shadow_atlas = RSG::scene->shadow_atlas_create();
+ viewport->shadow_atlas = RSG::light_storage->shadow_atlas_create();
viewport->viewport_render_direct_to_screen = false;
viewport->fsr_enabled = !RSG::rasterizer->is_low_end() && !viewport->disable_3d;
@@ -727,7 +783,13 @@ void RendererViewport::viewport_set_use_xr(RID p_viewport, bool p_use_xr) {
}
viewport->use_xr = p_use_xr;
- _configure_3d_render_buffers(viewport);
+
+ // Re-configure the 3D render buffers when disabling XR. They'll get
+ // re-configured when enabling XR in draw_viewports().
+ if (!p_use_xr) {
+ viewport->view_count = 1;
+ _configure_3d_render_buffers(viewport);
+ }
}
void RendererViewport::viewport_set_scaling_3d_mode(RID p_viewport, RS::ViewportScaling3DMode p_mode) {
@@ -743,15 +805,19 @@ void RendererViewport::viewport_set_fsr_sharpness(RID p_viewport, float p_sharpn
ERR_FAIL_COND(!viewport);
viewport->fsr_sharpness = p_sharpness;
- _configure_3d_render_buffers(viewport);
+ if (viewport->render_buffers.is_valid()) {
+ viewport->render_buffers->set_fsr_sharpness(p_sharpness);
+ }
}
-void RendererViewport::viewport_set_fsr_mipmap_bias(RID p_viewport, float p_mipmap_bias) {
+void RendererViewport::viewport_set_texture_mipmap_bias(RID p_viewport, float p_mipmap_bias) {
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
- viewport->fsr_mipmap_bias = p_mipmap_bias;
- _configure_3d_render_buffers(viewport);
+ viewport->texture_mipmap_bias = p_mipmap_bias;
+ if (viewport->render_buffers.is_valid()) {
+ viewport->render_buffers->set_texture_mipmap_bias(p_mipmap_bias);
+ }
}
void RendererViewport::viewport_set_scaling_3d_scale(RID p_viewport, float p_scaling_3d_scale) {
@@ -769,34 +835,27 @@ void RendererViewport::viewport_set_scaling_3d_scale(RID p_viewport, float p_sca
_configure_3d_render_buffers(viewport);
}
-uint32_t RendererViewport::Viewport::get_view_count() {
- uint32_t view_count = 1;
-
- if (use_xr && XRServer::get_singleton() != nullptr) {
- Ref<XRInterface> xr_interface;
-
- xr_interface = XRServer::get_singleton()->get_primary_interface();
- if (xr_interface.is_valid()) {
- view_count = xr_interface->get_view_count();
- }
- }
-
- return view_count;
-}
-
void RendererViewport::viewport_set_size(RID p_viewport, int p_width, int p_height) {
ERR_FAIL_COND(p_width < 0 && p_height < 0);
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
+ ERR_FAIL_COND_MSG(viewport->use_xr, "Cannot set viewport size when using XR");
+
+ _viewport_set_size(viewport, p_width, p_height, 1);
+}
- viewport->size = Size2(p_width, p_height);
+void RendererViewport::_viewport_set_size(Viewport *p_viewport, int p_width, int p_height, uint32_t p_view_count) {
+ Size2i new_size(p_width, p_height);
+ if (p_viewport->size != new_size || p_viewport->view_count != p_view_count) {
+ p_viewport->size = new_size;
+ p_viewport->view_count = p_view_count;
- uint32_t view_count = viewport->get_view_count();
- RSG::texture_storage->render_target_set_size(viewport->render_target, p_width, p_height, view_count);
- _configure_3d_render_buffers(viewport);
+ RSG::texture_storage->render_target_set_size(p_viewport->render_target, p_width, p_height, p_view_count);
+ _configure_3d_render_buffers(p_viewport);
- viewport->occlusion_buffer_dirty = true;
+ p_viewport->occlusion_buffer_dirty = true;
+ }
}
void RendererViewport::viewport_set_active(RID p_viewport, bool p_active) {
@@ -810,6 +869,8 @@ void RendererViewport::viewport_set_active(RID p_viewport, bool p_active) {
} else {
active_viewports.erase(viewport);
}
+
+ sorted_active_viewports_dirty = true;
}
void RendererViewport::viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport) {
@@ -834,7 +895,7 @@ void RendererViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_
// If using OpenGL we can optimize this operation by rendering directly to system_fbo
// instead of rendering to fbo and copying to system_fbo after
if (RSG::rasterizer->is_low_end() && viewport->viewport_render_direct_to_screen) {
- RSG::texture_storage->render_target_set_size(viewport->render_target, p_rect.size.x, p_rect.size.y, viewport->get_view_count());
+ RSG::texture_storage->render_target_set_size(viewport->render_target, p_rect.size.x, p_rect.size.y, viewport->view_count);
RSG::texture_storage->render_target_set_position(viewport->render_target, p_rect.position.x, p_rect.position.y);
}
@@ -844,7 +905,7 @@ void RendererViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_
// if render_direct_to_screen was used, reset size and position
if (RSG::rasterizer->is_low_end() && viewport->viewport_render_direct_to_screen) {
RSG::texture_storage->render_target_set_position(viewport->render_target, 0, 0);
- RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->get_view_count());
+ RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->view_count);
}
viewport->viewport_to_screen_rect = Rect2();
@@ -863,7 +924,7 @@ void RendererViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool
// if disabled, reset render_target size and position
if (!p_enable) {
RSG::texture_storage->render_target_set_position(viewport->render_target, 0, 0);
- RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->get_view_count());
+ RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->view_count);
}
RSG::texture_storage->render_target_set_direct_to_screen(viewport->render_target, p_enable);
@@ -871,7 +932,7 @@ void RendererViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool
// if attached to screen already, setup screen size and position, this needs to happen after setting flag to avoid an unnecessary buffer allocation
if (RSG::rasterizer->is_low_end() && viewport->viewport_to_screen_rect != Rect2() && p_enable) {
- RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->viewport_to_screen_rect.size.x, viewport->viewport_to_screen_rect.size.y, viewport->get_view_count());
+ RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->viewport_to_screen_rect.size.x, viewport->viewport_to_screen_rect.size.y, viewport->view_count);
RSG::texture_storage->render_target_set_position(viewport->render_target, viewport->viewport_to_screen_rect.position.x, viewport->viewport_to_screen_rect.position.y);
}
}
@@ -1023,24 +1084,35 @@ void RendererViewport::viewport_set_positional_shadow_atlas_size(RID p_viewport,
viewport->shadow_atlas_size = p_size;
viewport->shadow_atlas_16_bits = p_16_bits;
- RSG::scene->shadow_atlas_set_size(viewport->shadow_atlas, viewport->shadow_atlas_size, viewport->shadow_atlas_16_bits);
+ RSG::light_storage->shadow_atlas_set_size(viewport->shadow_atlas, viewport->shadow_atlas_size, viewport->shadow_atlas_16_bits);
}
void RendererViewport::viewport_set_positional_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv) {
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
- RSG::scene->shadow_atlas_set_quadrant_subdivision(viewport->shadow_atlas, p_quadrant, p_subdiv);
+ RSG::light_storage->shadow_atlas_set_quadrant_subdivision(viewport->shadow_atlas, p_quadrant, p_subdiv);
+}
+
+void RendererViewport::viewport_set_msaa_2d(RID p_viewport, RS::ViewportMSAA p_msaa) {
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ if (viewport->msaa_2d == p_msaa) {
+ return;
+ }
+ viewport->msaa_2d = p_msaa;
+ RSG::texture_storage->render_target_set_msaa(viewport->render_target, p_msaa);
}
-void RendererViewport::viewport_set_msaa(RID p_viewport, RS::ViewportMSAA p_msaa) {
+void RendererViewport::viewport_set_msaa_3d(RID p_viewport, RS::ViewportMSAA p_msaa) {
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
- if (viewport->msaa == p_msaa) {
+ if (viewport->msaa_3d == p_msaa) {
return;
}
- viewport->msaa = p_msaa;
+ viewport->msaa_3d = p_msaa;
_configure_3d_render_buffers(viewport);
}
@@ -1074,7 +1146,9 @@ void RendererViewport::viewport_set_use_debanding(RID p_viewport, bool p_use_deb
return;
}
viewport->use_debanding = p_use_debanding;
- _configure_3d_render_buffers(viewport);
+ if (viewport->render_buffers.is_valid()) {
+ viewport->render_buffers->set_use_debanding(p_use_debanding);
+ }
}
void RendererViewport::viewport_set_use_occlusion_culling(RID p_viewport, bool p_use_occlusion_culling) {
@@ -1228,9 +1302,9 @@ bool RendererViewport::free(RID p_rid) {
Viewport *viewport = viewport_owner.get_or_null(p_rid);
RSG::texture_storage->render_target_free(viewport->render_target);
- RSG::scene->free(viewport->shadow_atlas);
+ RSG::light_storage->shadow_atlas_free(viewport->shadow_atlas);
if (viewport->render_buffers.is_valid()) {
- RSG::scene->free(viewport->render_buffers);
+ viewport->render_buffers.unref();
}
while (viewport->canvas_map.begin()) {
@@ -1239,6 +1313,7 @@ bool RendererViewport::free(RID p_rid) {
viewport_set_scenario(p_rid, RID());
active_viewports.erase(viewport);
+ sorted_active_viewports_dirty = true;
if (viewport->use_occlusion_culling) {
RendererSceneOcclusionCull::get_singleton()->remove_buffer(p_rid);