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:
parent
acc887cc34
commit
41e855bd42
5 changed files with 42 additions and 14 deletions
|
@ -19,6 +19,7 @@
|
|||
#include "core/hle/service/nvflinger/hos_binder_driver_server.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"
|
||||
|
||||
namespace Service::VI {
|
||||
|
||||
|
@ -55,8 +56,18 @@ const Layer& Display::GetLayer(std::size_t index) const {
|
|||
return *layers.at(index);
|
||||
}
|
||||
|
||||
Kernel::KReadableEvent& Display::GetVSyncEvent() {
|
||||
return vsync_event->GetReadableEvent();
|
||||
ResultVal<Kernel::KReadableEvent*> Display::GetVSyncEvent() {
|
||||
if (got_vsync_event) {
|
||||
return ResultPermissionDenied;
|
||||
}
|
||||
|
||||
got_vsync_event = true;
|
||||
|
||||
return GetVSyncEventUnchecked();
|
||||
}
|
||||
|
||||
Kernel::KReadableEvent* Display::GetVSyncEventUnchecked() {
|
||||
return &vsync_event->GetReadableEvent();
|
||||
}
|
||||
|
||||
void Display::SignalVSyncEvent() {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Kernel {
|
||||
class KEvent;
|
||||
|
@ -73,8 +74,16 @@ public:
|
|||
return layers.size();
|
||||
}
|
||||
|
||||
/// Gets the readable vsync event.
|
||||
Kernel::KReadableEvent& GetVSyncEvent();
|
||||
/**
|
||||
* Gets the internal vsync event.
|
||||
*
|
||||
* @returns The internal Vsync event if it has not yet been retrieved,
|
||||
* VI::ResultPermissionDenied otherwise.
|
||||
*/
|
||||
[[nodiscard]] ResultVal<Kernel::KReadableEvent*> GetVSyncEvent();
|
||||
|
||||
/// Gets the internal vsync event.
|
||||
Kernel::KReadableEvent* GetVSyncEventUnchecked();
|
||||
|
||||
/// Signals the internal vsync event.
|
||||
void SignalVSyncEvent();
|
||||
|
@ -118,6 +127,7 @@ private:
|
|||
|
||||
std::vector<std::unique_ptr<Layer>> layers;
|
||||
Kernel::KEvent* vsync_event{};
|
||||
bool got_vsync_event{false};
|
||||
};
|
||||
|
||||
} // namespace Service::VI
|
||||
|
|
|
@ -671,19 +671,23 @@ private:
|
|||
IPC::RequestParser rp{ctx};
|
||||
const u64 display_id = rp.Pop<u64>();
|
||||
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called. display_id=0x{:016X}", display_id);
|
||||
LOG_DEBUG(Service_VI, "called. display_id={}", display_id);
|
||||
|
||||
const auto vsync_event = nv_flinger.FindVsyncEvent(display_id);
|
||||
if (!vsync_event) {
|
||||
LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id);
|
||||
if (vsync_event.Failed()) {
|
||||
const auto result = vsync_event.Code();
|
||||
if (result == ResultNotFound) {
|
||||
LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultNotFound);
|
||||
rb.Push(result);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(vsync_event);
|
||||
rb.PushCopyObjects(*vsync_event);
|
||||
}
|
||||
|
||||
void ConvertScalingMode(Kernel::HLERequestContext& ctx) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue