diff --git a/main/main.cpp b/main/main.cpp index 0b3dcc3f5bd..93551555e65 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -4441,15 +4441,20 @@ bool Main::iteration() { RenderingServer::get_singleton()->sync(); //sync if still drawing from previous frames. - if ((DisplayServer::get_singleton()->can_any_window_draw() || DisplayServer::get_singleton()->has_additional_outputs()) && - RenderingServer::get_singleton()->is_render_loop_enabled()) { + const bool has_pending_resources_for_processing = RD::get_singleton() && RD::get_singleton()->has_pending_resources_for_processing(); + bool wants_present = (DisplayServer::get_singleton()->can_any_window_draw() || + DisplayServer::get_singleton()->has_additional_outputs()) && + RenderingServer::get_singleton()->is_render_loop_enabled(); + + if (wants_present || has_pending_resources_for_processing) { + wants_present |= force_redraw_requested; if ((!force_redraw_requested) && OS::get_singleton()->is_in_low_processor_usage_mode()) { if (RenderingServer::get_singleton()->has_changed()) { - RenderingServer::get_singleton()->draw(true, scaled_step); // flush visual commands + RenderingServer::get_singleton()->draw(wants_present, scaled_step); // flush visual commands Engine::get_singleton()->increment_frames_drawn(); } } else { - RenderingServer::get_singleton()->draw(true, scaled_step); // flush visual commands + RenderingServer::get_singleton()->draw(wants_present, scaled_step); // flush visual commands Engine::get_singleton()->increment_frames_drawn(); force_redraw_requested = false; } diff --git a/servers/rendering/dummy/rasterizer_dummy.h b/servers/rendering/dummy/rasterizer_dummy.h index 6205193d9a9..33b4c38018b 100644 --- a/servers/rendering/dummy/rasterizer_dummy.h +++ b/servers/rendering/dummy/rasterizer_dummy.h @@ -90,8 +90,8 @@ public: void gl_end_frame(bool p_swap_buffers) override {} - void end_frame(bool p_swap_buffers) override { - if (p_swap_buffers) { + void end_frame(bool p_present) override { + if (p_present) { DisplayServer::get_singleton()->swap_buffers(); } } diff --git a/servers/rendering/renderer_compositor.h b/servers/rendering/renderer_compositor.h index dbc8f155bfb..e52cab740e0 100644 --- a/servers/rendering/renderer_compositor.h +++ b/servers/rendering/renderer_compositor.h @@ -99,7 +99,7 @@ public: virtual void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) = 0; virtual void gl_end_frame(bool p_swap_buffers) = 0; - virtual void end_frame(bool p_swap_buffers) = 0; + virtual void end_frame(bool p_present) = 0; virtual void finalize() = 0; virtual uint64_t get_frame_number() const = 0; virtual double get_frame_delta_time() const = 0; diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index dbaa6ac7b2e..fae7f11d915 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -112,10 +112,8 @@ void RendererCompositorRD::begin_frame(double frame_step) { scene->set_time(time, frame_step); } -void RendererCompositorRD::end_frame(bool p_swap_buffers) { - if (p_swap_buffers) { - RD::get_singleton()->swap_buffers(); - } +void RendererCompositorRD::end_frame(bool p_present) { + RD::get_singleton()->swap_buffers(p_present); } void RendererCompositorRD::initialize() { @@ -267,7 +265,7 @@ void RendererCompositorRD::set_boot_image(const Ref &p_image, const Color RD::get_singleton()->draw_list_end(); - RD::get_singleton()->swap_buffers(); + RD::get_singleton()->swap_buffers(true); texture_storage->texture_free(texture); RD::get_singleton()->free(sampler); diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h index 6821fa737e4..41c11113fef 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.h +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h @@ -128,7 +128,7 @@ public: void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount); void gl_end_frame(bool p_swap_buffers) {} - void end_frame(bool p_swap_buffers); + void end_frame(bool p_present); void finalize(); _ALWAYS_INLINE_ uint64_t get_frame_number() const { return frame; } diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 78e30f3dea0..263e808ebd4 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -6029,6 +6029,8 @@ void RenderingDevice::_free_internal(RID p_id) { ERR_PRINT("Attempted to free invalid ID: " + itos(p_id.get_id())); #endif } + + frames_pending_resources_for_processing = uint32_t(frames.size()); } // The full list of resources that can be named is in the VkObjectType enum. @@ -6131,11 +6133,11 @@ String RenderingDevice::get_device_pipeline_cache_uuid() const { return driver->get_pipeline_cache_uuid(); } -void RenderingDevice::swap_buffers() { +void RenderingDevice::swap_buffers(bool p_present) { ERR_RENDER_THREAD_GUARD(); _end_frame(); - _execute_frame(true); + _execute_frame(p_present); // Advance to the next frame and begin recording again. frame = (frame + 1) % frames.size(); @@ -6238,6 +6240,10 @@ void RenderingDevice::_free_pending_resources(int p_frame) { frames[p_frame].buffers_to_dispose_of.pop_front(); } + + if (frames_pending_resources_for_processing > 0u) { + --frames_pending_resources_for_processing; + } } uint32_t RenderingDevice::get_frame_delay() const { diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index 98b9cd21801..bbfd0abd715 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -1469,6 +1469,17 @@ private: TightLocalVector frames; uint64_t frames_drawn = 0; + // Whenever logic/physics request a graphics operation (not just deleting a resource) that requires + // us to flush all graphics commands, we must set frames_pending_resources_for_processing = frames.size(). + // This is important for when the user requested for the logic loop to still be updated while + // graphics should not (e.g. headless Multiplayer servers, minimized windows that need to still + // process something on the background). + uint32_t frames_pending_resources_for_processing = 0u; + +public: + bool has_pending_resources_for_processing() const { return frames_pending_resources_for_processing != 0u; } + +private: void _free_pending_resources(int p_frame); uint64_t texture_memory = 0; @@ -1520,7 +1531,7 @@ public: uint64_t limit_get(Limit p_limit) const; - void swap_buffers(); + void swap_buffers(bool p_present); uint32_t get_frame_delay() const; diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp index 2ec693cbbfe..b5d0d014791 100644 --- a/servers/rendering/rendering_server_default.cpp +++ b/servers/rendering/rendering_server_default.cpp @@ -406,15 +406,15 @@ void RenderingServerDefault::sync() { } } -void RenderingServerDefault::draw(bool p_swap_buffers, double frame_step) { +void RenderingServerDefault::draw(bool p_present, double frame_step) { ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Manually triggering the draw function from the RenderingServer can only be done on the main thread. Call this function from the main thread or use call_deferred()."); // Needs to be done before changes is reset to 0, to not force the editor to redraw. RS::get_singleton()->emit_signal(SNAME("frame_pre_draw")); changes = 0; if (create_thread) { - command_queue.push(this, &RenderingServerDefault::_draw, p_swap_buffers, frame_step); + command_queue.push(this, &RenderingServerDefault::_draw, p_present, frame_step); } else { - _draw(p_swap_buffers, frame_step); + _draw(p_present, frame_step); } } diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index 29b1e163c78..4a0df4a0cf3 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -1124,7 +1124,7 @@ public: virtual void request_frame_drawn_callback(const Callable &p_callable) override; - virtual void draw(bool p_swap_buffers, double frame_step) override; + virtual void draw(bool p_present, double frame_step) override; virtual void sync() override; virtual bool has_changed() const override; virtual void init() override;