diff options
| author | 2022-09-25 21:20:36 -0400 | |
|---|---|---|
| committer | 2022-09-25 21:33:36 -0400 | |
| commit | 41e855bd427e07ade6b9292e12bbe5a7c4e76a69 (patch) | |
| tree | a270ca94eabc45a52af899e70c1d72e8ab5b18be | |
| parent | service: vi: Move VI results into its own file (diff) | |
| download | yuzu-41e855bd427e07ade6b9292e12bbe5a7c4e76a69.tar.gz yuzu-41e855bd427e07ade6b9292e12bbe5a7c4e76a69.tar.xz yuzu-41e855bd427e07ade6b9292e12bbe5a7c4e76a69.zip | |
service: vi: Retrieve vsync event once per display
The display vsync event can only be retrieved once per display. Returns VI::ResultPermissionDenied if we attempt to retrieve the vsync event for the same display.
Prevents games such as .hack//G.U. Last Recode from consuming all the handles in the handle table by spamming vsync event retrievals and allows it to go in game.
| -rw-r--r-- | src/core/hle/service/nvflinger/nvflinger.cpp | 7 | ||||
| -rw-r--r-- | src/core/hle/service/nvflinger/nvflinger.h | 6 | ||||
| -rw-r--r-- | src/core/hle/service/vi/display/vi_display.cpp | 15 | ||||
| -rw-r--r-- | src/core/hle/service/vi/display/vi_display.h | 14 | ||||
| -rw-r--r-- | src/core/hle/service/vi/vi.cpp | 14 |
5 files changed, 42 insertions, 14 deletions
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 9b382bf56..93057e800 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include "core/hle/service/nvflinger/ui/graphic_buffer.h" | 22 | #include "core/hle/service/nvflinger/ui/graphic_buffer.h" |
| 23 | #include "core/hle/service/vi/display/vi_display.h" | 23 | #include "core/hle/service/vi/display/vi_display.h" |
| 24 | #include "core/hle/service/vi/layer/vi_layer.h" | 24 | #include "core/hle/service/vi/layer/vi_layer.h" |
| 25 | #include "core/hle/service/vi/vi_results.h" | ||
| 25 | #include "video_core/gpu.h" | 26 | #include "video_core/gpu.h" |
| 26 | 27 | ||
| 27 | namespace Service::NVFlinger { | 28 | namespace Service::NVFlinger { |
| @@ -163,15 +164,15 @@ std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) { | |||
| 163 | return layer->GetBinderId(); | 164 | return layer->GetBinderId(); |
| 164 | } | 165 | } |
| 165 | 166 | ||
| 166 | Kernel::KReadableEvent* NVFlinger::FindVsyncEvent(u64 display_id) { | 167 | ResultVal<Kernel::KReadableEvent*> NVFlinger::FindVsyncEvent(u64 display_id) { |
| 167 | const auto lock_guard = Lock(); | 168 | const auto lock_guard = Lock(); |
| 168 | auto* const display = FindDisplay(display_id); | 169 | auto* const display = FindDisplay(display_id); |
| 169 | 170 | ||
| 170 | if (display == nullptr) { | 171 | if (display == nullptr) { |
| 171 | return nullptr; | 172 | return VI::ResultNotFound; |
| 172 | } | 173 | } |
| 173 | 174 | ||
| 174 | return &display->GetVSyncEvent(); | 175 | return display->GetVSyncEvent(); |
| 175 | } | 176 | } |
| 176 | 177 | ||
| 177 | VI::Display* NVFlinger::FindDisplay(u64 display_id) { | 178 | VI::Display* NVFlinger::FindDisplay(u64 display_id) { |
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 044ac6ac8..3bbe5d92b 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include <vector> | 11 | #include <vector> |
| 12 | 12 | ||
| 13 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 14 | #include "core/hle/result.h" | ||
| 14 | #include "core/hle/service/kernel_helpers.h" | 15 | #include "core/hle/service/kernel_helpers.h" |
| 15 | 16 | ||
| 16 | namespace Common { | 17 | namespace Common { |
| @@ -71,8 +72,9 @@ public: | |||
| 71 | 72 | ||
| 72 | /// Gets the vsync event for the specified display. | 73 | /// Gets the vsync event for the specified display. |
| 73 | /// | 74 | /// |
| 74 | /// If an invalid display ID is provided, then nullptr is returned. | 75 | /// If an invalid display ID is provided, then VI::ResultNotFound is returned. |
| 75 | [[nodiscard]] Kernel::KReadableEvent* FindVsyncEvent(u64 display_id); | 76 | /// If the vsync event has already been retrieved, then VI::ResultPermissionDenied is returned. |
| 77 | [[nodiscard]] ResultVal<Kernel::KReadableEvent*> FindVsyncEvent(u64 display_id); | ||
| 76 | 78 | ||
| 77 | /// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when | 79 | /// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when |
| 78 | /// finished. | 80 | /// finished. |
diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp index b34febb50..aa49aa775 100644 --- a/src/core/hle/service/vi/display/vi_display.cpp +++ b/src/core/hle/service/vi/display/vi_display.cpp | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include "core/hle/service/nvflinger/hos_binder_driver_server.h" | 19 | #include "core/hle/service/nvflinger/hos_binder_driver_server.h" |
| 20 | #include "core/hle/service/vi/display/vi_display.h" | 20 | #include "core/hle/service/vi/display/vi_display.h" |
| 21 | #include "core/hle/service/vi/layer/vi_layer.h" | 21 | #include "core/hle/service/vi/layer/vi_layer.h" |
| 22 | #include "core/hle/service/vi/vi_results.h" | ||
| 22 | 23 | ||
| 23 | namespace Service::VI { | 24 | namespace Service::VI { |
| 24 | 25 | ||
| @@ -55,8 +56,18 @@ const Layer& Display::GetLayer(std::size_t index) const { | |||
| 55 | return *layers.at(index); | 56 | return *layers.at(index); |
| 56 | } | 57 | } |
| 57 | 58 | ||
| 58 | Kernel::KReadableEvent& Display::GetVSyncEvent() { | 59 | ResultVal<Kernel::KReadableEvent*> Display::GetVSyncEvent() { |
| 59 | return vsync_event->GetReadableEvent(); | 60 | if (got_vsync_event) { |
| 61 | return ResultPermissionDenied; | ||
| 62 | } | ||
| 63 | |||
| 64 | got_vsync_event = true; | ||
| 65 | |||
| 66 | return GetVSyncEventUnchecked(); | ||
| 67 | } | ||
| 68 | |||
| 69 | Kernel::KReadableEvent* Display::GetVSyncEventUnchecked() { | ||
| 70 | return &vsync_event->GetReadableEvent(); | ||
| 60 | } | 71 | } |
| 61 | 72 | ||
| 62 | void Display::SignalVSyncEvent() { | 73 | void Display::SignalVSyncEvent() { |
diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h index 3838bb599..8dbb0ef80 100644 --- a/src/core/hle/service/vi/display/vi_display.h +++ b/src/core/hle/service/vi/display/vi_display.h | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | 9 | ||
| 10 | #include "common/common_funcs.h" | 10 | #include "common/common_funcs.h" |
| 11 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | #include "core/hle/result.h" | ||
| 12 | 13 | ||
| 13 | namespace Kernel { | 14 | namespace Kernel { |
| 14 | class KEvent; | 15 | class KEvent; |
| @@ -73,8 +74,16 @@ public: | |||
| 73 | return layers.size(); | 74 | return layers.size(); |
| 74 | } | 75 | } |
| 75 | 76 | ||
| 76 | /// Gets the readable vsync event. | 77 | /** |
| 77 | Kernel::KReadableEvent& GetVSyncEvent(); | 78 | * Gets the internal vsync event. |
| 79 | * | ||
| 80 | * @returns The internal Vsync event if it has not yet been retrieved, | ||
| 81 | * VI::ResultPermissionDenied otherwise. | ||
| 82 | */ | ||
| 83 | [[nodiscard]] ResultVal<Kernel::KReadableEvent*> GetVSyncEvent(); | ||
| 84 | |||
| 85 | /// Gets the internal vsync event. | ||
| 86 | Kernel::KReadableEvent* GetVSyncEventUnchecked(); | ||
| 78 | 87 | ||
| 79 | /// Signals the internal vsync event. | 88 | /// Signals the internal vsync event. |
| 80 | void SignalVSyncEvent(); | 89 | void SignalVSyncEvent(); |
| @@ -118,6 +127,7 @@ private: | |||
| 118 | 127 | ||
| 119 | std::vector<std::unique_ptr<Layer>> layers; | 128 | std::vector<std::unique_ptr<Layer>> layers; |
| 120 | Kernel::KEvent* vsync_event{}; | 129 | Kernel::KEvent* vsync_event{}; |
| 130 | bool got_vsync_event{false}; | ||
| 121 | }; | 131 | }; |
| 122 | 132 | ||
| 123 | } // namespace Service::VI | 133 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 0a347a0e9..f083811ec 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp | |||
| @@ -671,19 +671,23 @@ private: | |||
| 671 | IPC::RequestParser rp{ctx}; | 671 | IPC::RequestParser rp{ctx}; |
| 672 | const u64 display_id = rp.Pop<u64>(); | 672 | const u64 display_id = rp.Pop<u64>(); |
| 673 | 673 | ||
| 674 | LOG_WARNING(Service_VI, "(STUBBED) called. display_id=0x{:016X}", display_id); | 674 | LOG_DEBUG(Service_VI, "called. display_id={}", display_id); |
| 675 | 675 | ||
| 676 | const auto vsync_event = nv_flinger.FindVsyncEvent(display_id); | 676 | const auto vsync_event = nv_flinger.FindVsyncEvent(display_id); |
| 677 | if (!vsync_event) { | 677 | if (vsync_event.Failed()) { |
| 678 | LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id); | 678 | const auto result = vsync_event.Code(); |
| 679 | if (result == ResultNotFound) { | ||
| 680 | LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id); | ||
| 681 | } | ||
| 682 | |||
| 679 | IPC::ResponseBuilder rb{ctx, 2}; | 683 | IPC::ResponseBuilder rb{ctx, 2}; |
| 680 | rb.Push(ResultNotFound); | 684 | rb.Push(result); |
| 681 | return; | 685 | return; |
| 682 | } | 686 | } |
| 683 | 687 | ||
| 684 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 688 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 685 | rb.Push(ResultSuccess); | 689 | rb.Push(ResultSuccess); |
| 686 | rb.PushCopyObjects(vsync_event); | 690 | rb.PushCopyObjects(*vsync_event); |
| 687 | } | 691 | } |
| 688 | 692 | ||
| 689 | void ConvertScalingMode(Kernel::HLERequestContext& ctx) { | 693 | void ConvertScalingMode(Kernel::HLERequestContext& ctx) { |