diff options
Diffstat (limited to 'servers/rendering/renderer_viewport.cpp')
-rw-r--r-- | servers/rendering/renderer_viewport.cpp | 261 |
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); |