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.
This commit is contained in:
Morph
2022-09-25 21:20:36 -04:00
parent acc887cc34
commit 41e855bd42
5 changed files with 42 additions and 14 deletions

View File

@@ -22,6 +22,7 @@
#include "core/hle/service/nvflinger/ui/graphic_buffer.h"
#include "core/hle/service/vi/display/vi_display.h"
#include "core/hle/service/vi/layer/vi_layer.h"
#include "core/hle/service/vi/vi_results.h"
#include "video_core/gpu.h"
namespace Service::NVFlinger {
@@ -163,15 +164,15 @@ std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) {
return layer->GetBinderId();
}
Kernel::KReadableEvent* NVFlinger::FindVsyncEvent(u64 display_id) {
ResultVal<Kernel::KReadableEvent*> NVFlinger::FindVsyncEvent(u64 display_id) {
const auto lock_guard = Lock();
auto* const display = FindDisplay(display_id);
if (display == nullptr) {
return nullptr;
return VI::ResultNotFound;
}
return &display->GetVSyncEvent();
return display->GetVSyncEvent();
}
VI::Display* NVFlinger::FindDisplay(u64 display_id) {

View File

@@ -11,6 +11,7 @@
#include <vector>
#include "common/common_types.h"
#include "core/hle/result.h"
#include "core/hle/service/kernel_helpers.h"
namespace Common {
@@ -71,8 +72,9 @@ public:
/// Gets the vsync event for the specified display.
///
/// If an invalid display ID is provided, then nullptr is returned.
[[nodiscard]] Kernel::KReadableEvent* FindVsyncEvent(u64 display_id);
/// If an invalid display ID is provided, then VI::ResultNotFound is returned.
/// If the vsync event has already been retrieved, then VI::ResultPermissionDenied is returned.
[[nodiscard]] ResultVal<Kernel::KReadableEvent*> FindVsyncEvent(u64 display_id);
/// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when
/// finished.