mirror of
https://github.com/yuzu-mirror/yuzu
synced 2024-12-01 12:29:09 +00:00
NVServices: Address Feedback
This commit is contained in:
parent
d20ede40b1
commit
f3a39e0c9c
8 changed files with 38 additions and 21 deletions
|
@ -36,9 +36,8 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3
|
||||||
addr, offset, width, height, stride, static_cast<PixelFormat>(format),
|
addr, offset, width, height, stride, static_cast<PixelFormat>(format),
|
||||||
transform, crop_rect};
|
transform, crop_rect};
|
||||||
|
|
||||||
auto& instance = system;
|
system.GetPerfStats().EndGameFrame();
|
||||||
instance.GetPerfStats().EndGameFrame();
|
system.GPU().SwapBuffers(framebuffer);
|
||||||
instance.GPU().SwapBuffers(framebuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::Nvidia::Devices
|
} // namespace Service::Nvidia::Devices
|
||||||
|
|
|
@ -87,13 +87,19 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>&
|
||||||
u32 event_id;
|
u32 event_id;
|
||||||
if (is_async) {
|
if (is_async) {
|
||||||
event_id = params.value & 0x00FF;
|
event_id = params.value & 0x00FF;
|
||||||
if (event_id >= 64) {
|
if (event_id >= MaxNvEvents) {
|
||||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||||
return NvResult::BadParameter;
|
return NvResult::BadParameter;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (ctrl.fresh_call) {
|
if (ctrl.fresh_call) {
|
||||||
event_id = events_interface.GetFreeEvent();
|
const auto result = events_interface.GetFreeEvent();
|
||||||
|
if (result) {
|
||||||
|
event_id = *result;
|
||||||
|
} else {
|
||||||
|
LOG_CRITICAL(Service_NVDRV, "No Free Events available!");
|
||||||
|
event_id = params.value & 0x00FF;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
event_id = ctrl.event_id;
|
event_id = ctrl.event_id;
|
||||||
}
|
}
|
||||||
|
@ -129,6 +135,7 @@ u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<
|
||||||
IocCtrlEventRegisterParams params{};
|
IocCtrlEventRegisterParams params{};
|
||||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||||
const u32 event_id = params.user_event_id & 0x00FF;
|
const u32 event_id = params.user_event_id & 0x00FF;
|
||||||
|
LOG_DEBUG(Service_NVDRV, " called, user_event_id: {:X}", event_id);
|
||||||
if (event_id >= MaxNvEvents) {
|
if (event_id >= MaxNvEvents) {
|
||||||
return NvResult::BadParameter;
|
return NvResult::BadParameter;
|
||||||
}
|
}
|
||||||
|
@ -143,6 +150,7 @@ u32 nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, std::vecto
|
||||||
IocCtrlEventUnregisterParams params{};
|
IocCtrlEventUnregisterParams params{};
|
||||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||||
const u32 event_id = params.user_event_id & 0x00FF;
|
const u32 event_id = params.user_event_id & 0x00FF;
|
||||||
|
LOG_DEBUG(Service_NVDRV, " called, user_event_id: {:X}", event_id);
|
||||||
if (event_id >= MaxNvEvents) {
|
if (event_id >= MaxNvEvents) {
|
||||||
return NvResult::BadParameter;
|
return NvResult::BadParameter;
|
||||||
}
|
}
|
||||||
|
@ -159,7 +167,7 @@ u32 nvhost_ctrl::IocCtrlEventSignal(const std::vector<u8>& input, std::vector<u8
|
||||||
// TODO(Blinkhawk): This is normally called when an NvEvents timeout on WaitSynchronization
|
// TODO(Blinkhawk): This is normally called when an NvEvents timeout on WaitSynchronization
|
||||||
// It is believed from RE to cancel the GPU Event. However, better research is required
|
// It is believed from RE to cancel the GPU Event. However, better research is required
|
||||||
u32 event_id = params.user_event_id & 0x00FF;
|
u32 event_id = params.user_event_id & 0x00FF;
|
||||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, user_event_id: {:X}", event_id);
|
LOG_DEBUG(Service_NVDRV, " called, user_event_id: {:X}", event_id);
|
||||||
if (event_id >= MaxNvEvents) {
|
if (event_id >= MaxNvEvents) {
|
||||||
return NvResult::BadParameter;
|
return NvResult::BadParameter;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
#include "core/hle/service/nvdrv/devices/nvdevice.h"
|
#include "core/hle/service/nvdrv/devices/nvdevice.h"
|
||||||
|
#include "core/hle/service/nvdrv/nvdata.h"
|
||||||
|
|
||||||
namespace Service::Nvidia::Devices {
|
namespace Service::Nvidia::Devices {
|
||||||
|
|
||||||
|
@ -114,10 +115,6 @@ private:
|
||||||
static_assert(sizeof(IoctlGetErrorNotification) == 16,
|
static_assert(sizeof(IoctlGetErrorNotification) == 16,
|
||||||
"IoctlGetErrorNotification is incorrect size");
|
"IoctlGetErrorNotification is incorrect size");
|
||||||
|
|
||||||
struct Fence {
|
|
||||||
u32_le id;
|
|
||||||
u32_le value;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(Fence) == 8, "Fence is incorrect size");
|
static_assert(sizeof(Fence) == 8, "Fence is incorrect size");
|
||||||
|
|
||||||
struct IoctlAllocGpfifoEx {
|
struct IoctlAllocGpfifoEx {
|
||||||
|
|
|
@ -103,7 +103,7 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3, 1};
|
IPC::ResponseBuilder rb{ctx, 3, 1};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
if (event_id < 64) {
|
if (event_id < MaxNvEvents) {
|
||||||
rb.PushCopyObjects(nvdrv->GetEvent(event_id));
|
rb.PushCopyObjects(nvdrv->GetEvent(event_id));
|
||||||
rb.Push<u32>(NvResult::Success);
|
rb.Push<u32>(NvResult::Success);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -35,9 +35,13 @@ enum class EventState {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IoctlCtrl {
|
struct IoctlCtrl {
|
||||||
|
// First call done to the servioce for services that call itself again after a call.
|
||||||
bool fresh_call{true};
|
bool fresh_call{true};
|
||||||
|
// Tells the Ioctl Wrapper that it must delay the IPC response and send the thread to sleep
|
||||||
bool must_delay{};
|
bool must_delay{};
|
||||||
|
// Timeout for the delay
|
||||||
s64 timeout{};
|
s64 timeout{};
|
||||||
|
// NV Event Id
|
||||||
s32 event_id{-1};
|
s32 event_id{-1};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -27,25 +27,34 @@ class nvdevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EventInterface {
|
struct EventInterface {
|
||||||
|
// Mask representing currently busy events
|
||||||
u64 events_mask{};
|
u64 events_mask{};
|
||||||
|
// Each kernel event associated to an NV event
|
||||||
std::array<Kernel::EventPair, MaxNvEvents> events;
|
std::array<Kernel::EventPair, MaxNvEvents> events;
|
||||||
|
// The status of the current NVEvent
|
||||||
std::array<EventState, MaxNvEvents> status{};
|
std::array<EventState, MaxNvEvents> status{};
|
||||||
|
// Tells if an NVEvent is registered or not
|
||||||
std::array<bool, MaxNvEvents> registered{};
|
std::array<bool, MaxNvEvents> registered{};
|
||||||
|
// When an NVEvent is waiting on GPU interrupt, this is the sync_point
|
||||||
|
// associated with it.
|
||||||
std::array<u32, MaxNvEvents> assigned_syncpt{};
|
std::array<u32, MaxNvEvents> assigned_syncpt{};
|
||||||
|
// This is the value of the GPU interrupt for which the NVEvent is waiting
|
||||||
|
// for.
|
||||||
std::array<u32, MaxNvEvents> assigned_value{};
|
std::array<u32, MaxNvEvents> assigned_value{};
|
||||||
static constexpr u32 null_event = 0xFFFFFFFF;
|
// Constant to denote an unasigned syncpoint.
|
||||||
u32 GetFreeEvent() const {
|
static constexpr u32 unassigned_syncpt = 0xFFFFFFFF;
|
||||||
|
std::optional<u32> GetFreeEvent() const {
|
||||||
u64 mask = events_mask;
|
u64 mask = events_mask;
|
||||||
for (u32 i = 0; i < MaxNvEvents; i++) {
|
for (u32 i = 0; i < MaxNvEvents; i++) {
|
||||||
const bool is_free = (mask & 0x1) == 0;
|
const bool is_free = (mask & 0x1) == 0;
|
||||||
if (is_free) {
|
if (is_free) {
|
||||||
if (status[i] == EventState::Registered || status[i] == EventState::Free) {
|
if (status[i] == EventState::Registered || status[i] == EventState::Free) {
|
||||||
return i;
|
return {i};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mask = mask >> 1;
|
mask = mask >> 1;
|
||||||
}
|
}
|
||||||
return null_event;
|
return {};
|
||||||
}
|
}
|
||||||
void SetEventStatus(const u32 event_id, EventState new_status) {
|
void SetEventStatus(const u32 event_id, EventState new_status) {
|
||||||
EventState old_status = status[event_id];
|
EventState old_status = status[event_id];
|
||||||
|
@ -57,7 +66,7 @@ struct EventInterface {
|
||||||
registered[event_id] = true;
|
registered[event_id] = true;
|
||||||
}
|
}
|
||||||
if (new_status == EventState::Waiting || new_status == EventState::Busy) {
|
if (new_status == EventState::Waiting || new_status == EventState::Busy) {
|
||||||
events_mask |= (1 << event_id);
|
events_mask |= (1ULL << event_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void RegisterEvent(const u32 event_id) {
|
void RegisterEvent(const u32 event_id) {
|
||||||
|
@ -74,8 +83,8 @@ struct EventInterface {
|
||||||
}
|
}
|
||||||
void LiberateEvent(const u32 event_id) {
|
void LiberateEvent(const u32 event_id) {
|
||||||
status[event_id] = registered[event_id] ? EventState::Registered : EventState::Free;
|
status[event_id] = registered[event_id] ? EventState::Registered : EventState::Free;
|
||||||
events_mask &= ~(1 << event_id);
|
events_mask &= ~(1ULL << event_id);
|
||||||
assigned_syncpt[event_id] = 0xFFFFFFFF;
|
assigned_syncpt[event_id] = unassigned_syncpt;
|
||||||
assigned_value[event_id] = 0;
|
assigned_value[event_id] = 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -80,6 +80,7 @@ void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform,
|
||||||
|
|
||||||
std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() {
|
std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() {
|
||||||
auto itr = queue.end();
|
auto itr = queue.end();
|
||||||
|
// Iterate to find a queued buffer matching the requested slot.
|
||||||
while (itr == queue.end() && !queue_sequence.empty()) {
|
while (itr == queue.end() && !queue_sequence.empty()) {
|
||||||
u32 slot = queue_sequence.front();
|
u32 slot = queue_sequence.front();
|
||||||
itr = std::find_if(queue.begin(), queue.end(), [&slot](const Buffer& buffer) {
|
itr = std::find_if(queue.begin(), queue.end(), [&slot](const Buffer& buffer) {
|
||||||
|
|
|
@ -536,7 +536,7 @@ private:
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
// Buffer is available
|
// Buffer is available
|
||||||
IGBPDequeueBufferResponseParcel response{(*result).first, *(*result).second};
|
IGBPDequeueBufferResponseParcel response{result->first, *result->second};
|
||||||
ctx.WriteBuffer(response.Serialize());
|
ctx.WriteBuffer(response.Serialize());
|
||||||
} else {
|
} else {
|
||||||
// Wait the current thread until a buffer becomes available
|
// Wait the current thread until a buffer becomes available
|
||||||
|
@ -549,8 +549,7 @@ private:
|
||||||
auto result = buffer_queue.DequeueBuffer(width, height);
|
auto result = buffer_queue.DequeueBuffer(width, height);
|
||||||
ASSERT_MSG(result != std::nullopt, "Could not dequeue buffer.");
|
ASSERT_MSG(result != std::nullopt, "Could not dequeue buffer.");
|
||||||
|
|
||||||
IGBPDequeueBufferResponseParcel response{(*result).first,
|
IGBPDequeueBufferResponseParcel response{result->first, *result->second};
|
||||||
*(*result).second};
|
|
||||||
ctx.WriteBuffer(response.Serialize());
|
ctx.WriteBuffer(response.Serialize());
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
|
Loading…
Reference in a new issue