mirror of
				https://git.tardis.systems/mirrors/yuzu
				synced 2025-10-31 10:44:49 +01:00 
			
		
		
		
	hardware_composer: implement speed limit extensions
This commit is contained in:
		
							parent
							
								
									a595e9e8a7
								
							
						
					
					
						commit
						2c421a7046
					
				| @ -40,7 +40,7 @@ public: | ||||
|     bool is_droppable{}; | ||||
|     bool acquire_called{}; | ||||
|     bool transform_to_display_inverse{}; | ||||
|     u32 swap_interval{}; | ||||
|     s32 swap_interval{}; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Service::android
 | ||||
|  | ||||
| @ -16,11 +16,37 @@ | ||||
| 
 | ||||
| namespace Service::Nvnflinger { | ||||
| 
 | ||||
| namespace { | ||||
| 
 | ||||
| s32 NormalizeSwapInterval(f32* out_speed_scale, s32 swap_interval) { | ||||
|     if (swap_interval <= 0) { | ||||
|         // As an extension, treat nonpositive swap interval as speed multiplier.
 | ||||
|         if (out_speed_scale) { | ||||
|             *out_speed_scale = 2.f * static_cast<f32>(1 - swap_interval); | ||||
|         } | ||||
| 
 | ||||
|         swap_interval = 1; | ||||
|     } | ||||
| 
 | ||||
|     if (swap_interval >= 5) { | ||||
|         // As an extension, treat high swap interval as precise speed control.
 | ||||
|         if (out_speed_scale) { | ||||
|             *out_speed_scale = static_cast<f32>(swap_interval) / 100.f; | ||||
|         } | ||||
| 
 | ||||
|         swap_interval = 1; | ||||
|     } | ||||
| 
 | ||||
|     return swap_interval; | ||||
| } | ||||
| 
 | ||||
| } // namespace
 | ||||
| 
 | ||||
| HardwareComposer::HardwareComposer() = default; | ||||
| HardwareComposer::~HardwareComposer() = default; | ||||
| 
 | ||||
| u32 HardwareComposer::ComposeLocked(VI::Display& display, Nvidia::Devices::nvdisp_disp0& nvdisp, | ||||
|                                     u32 frame_advance) { | ||||
| u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display, | ||||
|                                     Nvidia::Devices::nvdisp_disp0& nvdisp, u32 frame_advance) { | ||||
|     boost::container::small_vector<HwcLayer, 2> composition_stack; | ||||
| 
 | ||||
|     m_frame_number += frame_advance; | ||||
| @ -45,8 +71,11 @@ u32 HardwareComposer::ComposeLocked(VI::Display& display, Nvidia::Devices::nvdis | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Set default speed limit to 100%.
 | ||||
|     *out_speed_scale = 1.0f; | ||||
| 
 | ||||
|     // Determine the number of vsync periods to wait before composing again.
 | ||||
|     std::optional<u32> swap_interval{}; | ||||
|     std::optional<s32> swap_interval{}; | ||||
|     bool has_acquired_buffer{}; | ||||
| 
 | ||||
|     // Acquire all necessary framebuffers.
 | ||||
| @ -87,14 +116,15 @@ u32 HardwareComposer::ComposeLocked(VI::Display& display, Nvidia::Devices::nvdis | ||||
| 
 | ||||
|         // We need to compose again either before this frame is supposed to
 | ||||
|         // be released, or exactly on the vsync period it should be released.
 | ||||
|         //
 | ||||
|         const s32 item_swap_interval = NormalizeSwapInterval(out_speed_scale, item.swap_interval); | ||||
| 
 | ||||
|         // TODO: handle cases where swap intervals are relatively prime. So far,
 | ||||
|         // only swap intervals of 0, 1 and 2 have been observed, but if 3 were
 | ||||
|         // to be introduced, this would cause an issue.
 | ||||
|         if (swap_interval) { | ||||
|             swap_interval = std::min(*swap_interval, item.swap_interval); | ||||
|             swap_interval = std::min(*swap_interval, item_swap_interval); | ||||
|         } else { | ||||
|             swap_interval = item.swap_interval; | ||||
|             swap_interval = item_swap_interval; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -111,13 +141,8 @@ u32 HardwareComposer::ComposeLocked(VI::Display& display, Nvidia::Devices::nvdis | ||||
|     // Render MicroProfile.
 | ||||
|     MicroProfileFlip(); | ||||
| 
 | ||||
|     // If we advanced, then advance by at least 1 frame.
 | ||||
|     if (swap_interval) { | ||||
|         return std::max(*swap_interval, 1U); | ||||
|     } | ||||
| 
 | ||||
|     // Otherwise, advance by exactly one frame.
 | ||||
|     return 1U; | ||||
|     // Advance by at least one frame.
 | ||||
|     return swap_interval.value_or(1); | ||||
| } | ||||
| 
 | ||||
| void HardwareComposer::RemoveLayerLocked(VI::Display& display, LayerId layer_id) { | ||||
| @ -146,7 +171,7 @@ bool HardwareComposer::TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer | ||||
| 
 | ||||
|     // We succeeded, so set the new release frame info.
 | ||||
|     framebuffer.release_frame_number = | ||||
|         m_frame_number + std::max(1U, framebuffer.item.swap_interval); | ||||
|         NormalizeSwapInterval(nullptr, framebuffer.item.swap_interval); | ||||
|     framebuffer.is_acquired = true; | ||||
| 
 | ||||
|     return true; | ||||
|  | ||||
| @ -26,8 +26,8 @@ public: | ||||
|     explicit HardwareComposer(); | ||||
|     ~HardwareComposer(); | ||||
| 
 | ||||
|     u32 ComposeLocked(VI::Display& display, Nvidia::Devices::nvdisp_disp0& nvdisp, | ||||
|                       u32 frame_advance); | ||||
|     u32 ComposeLocked(f32* out_speed_scale, VI::Display& display, | ||||
|                       Nvidia::Devices::nvdisp_disp0& nvdisp, u32 frame_advance); | ||||
|     void RemoveLayerLocked(VI::Display& display, LayerId layer_id); | ||||
| 
 | ||||
| private: | ||||
|  | ||||
| @ -291,7 +291,8 @@ void Nvnflinger::Compose() { | ||||
|         auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd); | ||||
|         ASSERT(nvdisp); | ||||
| 
 | ||||
|         swap_interval = display.GetComposer().ComposeLocked(display, *nvdisp, swap_interval); | ||||
|         swap_interval = display.GetComposer().ComposeLocked(&compose_speed_scale, display, *nvdisp, | ||||
|                                                             swap_interval); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -308,15 +309,16 @@ s64 Nvnflinger::GetNextTicks() const { | ||||
|             speed_scale = 0.01f; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Adjust by speed limit determined during composition.
 | ||||
|     speed_scale /= compose_speed_scale; | ||||
| 
 | ||||
|     if (system.GetNVDECActive() && settings.use_video_framerate.GetValue()) { | ||||
|         // Run at intended presentation rate during video playback.
 | ||||
|         speed_scale = 1.f; | ||||
|     } | ||||
| 
 | ||||
|     // As an extension, treat nonpositive swap interval as framerate multiplier.
 | ||||
|     const f32 effective_fps = swap_interval <= 0 ? 120.f * static_cast<f32>(1 - swap_interval) | ||||
|                                                  : 60.f / static_cast<f32>(swap_interval); | ||||
| 
 | ||||
|     const f32 effective_fps = 60.f / static_cast<f32>(swap_interval); | ||||
|     return static_cast<s64>(speed_scale * (1000000000.f / effective_fps)); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -144,6 +144,7 @@ private: | ||||
|     u32 next_buffer_queue_id = 1; | ||||
| 
 | ||||
|     s32 swap_interval = 1; | ||||
|     f32 compose_speed_scale = 1.0f; | ||||
| 
 | ||||
|     bool is_abandoned = false; | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user