commit
25d607f5f6
67 changed files with 770 additions and 1001 deletions
|
@ -70,8 +70,10 @@ public:
|
|||
Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioOutBufferReleased");
|
||||
|
||||
stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate,
|
||||
audio_params.channel_count, std::move(unique_name),
|
||||
[this] { buffer_event.writable->Signal(); });
|
||||
audio_params.channel_count, std::move(unique_name), [this] {
|
||||
const auto guard = LockService();
|
||||
buffer_event.writable->Signal();
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -49,16 +49,16 @@ public:
|
|||
|
||||
system_event =
|
||||
Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioRenderer:SystemEvent");
|
||||
renderer = std::make_unique<AudioCore::AudioRenderer>(system.CoreTiming(), system.Memory(),
|
||||
audren_params, system_event.writable,
|
||||
instance_number);
|
||||
renderer = std::make_unique<AudioCore::AudioRenderer>(
|
||||
system.CoreTiming(), system.Memory(), audren_params,
|
||||
[this]() {
|
||||
const auto guard = LockService();
|
||||
system_event.writable->Signal();
|
||||
},
|
||||
instance_number);
|
||||
}
|
||||
|
||||
private:
|
||||
void UpdateAudioCallback() {
|
||||
system_event.writable->Signal();
|
||||
}
|
||||
|
||||
void GetSampleRate(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
|
|
|
@ -78,11 +78,13 @@ IAppletResource::IAppletResource(Core::System& system_)
|
|||
pad_update_event = Core::Timing::CreateEvent(
|
||||
"HID::UpdatePadCallback",
|
||||
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
|
||||
const auto guard = LockService();
|
||||
UpdateControllers(user_data, ns_late);
|
||||
});
|
||||
motion_update_event = Core::Timing::CreateEvent(
|
||||
"HID::MotionPadCallback",
|
||||
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
|
||||
const auto guard = LockService();
|
||||
UpdateMotion(user_data, ns_late);
|
||||
});
|
||||
|
||||
|
|
|
@ -31,8 +31,8 @@ public:
|
|||
* @param output A buffer where the output data will be written to.
|
||||
* @returns The result code of the ioctl.
|
||||
*/
|
||||
virtual NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) = 0;
|
||||
virtual NvResult Ioctl1(Ioctl command, const std::vector<u8>& input,
|
||||
std::vector<u8>& output) = 0;
|
||||
|
||||
/**
|
||||
* Handles an ioctl2 request.
|
||||
|
@ -43,8 +43,7 @@ public:
|
|||
* @returns The result code of the ioctl.
|
||||
*/
|
||||
virtual NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) = 0;
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output) = 0;
|
||||
|
||||
/**
|
||||
* Handles an ioctl3 request.
|
||||
|
@ -55,7 +54,7 @@ public:
|
|||
* @returns The result code of the ioctl.
|
||||
*/
|
||||
virtual NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) = 0;
|
||||
std::vector<u8>& inline_output) = 0;
|
||||
|
||||
protected:
|
||||
Core::System& system;
|
||||
|
|
|
@ -18,21 +18,20 @@ nvdisp_disp0::nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_de
|
|||
: nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
|
||||
nvdisp_disp0 ::~nvdisp_disp0() = default;
|
||||
|
||||
NvResult nvdisp_disp0::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
NvResult nvdisp_disp0::Ioctl1(Ioctl command, const std::vector<u8>& input,
|
||||
std::vector<u8>& output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvdisp_disp0::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvdisp_disp0::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) {
|
||||
std::vector<u8>& inline_output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
|
|
@ -20,13 +20,11 @@ public:
|
|||
explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
|
||||
~nvdisp_disp0() override;
|
||||
|
||||
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
|
||||
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output) override;
|
||||
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) override;
|
||||
std::vector<u8>& inline_output) override;
|
||||
|
||||
/// Performs a screen flip, drawing the buffer pointed to by the handle.
|
||||
void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride,
|
||||
|
|
|
@ -21,8 +21,8 @@ nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_
|
|||
: nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
|
||||
nvhost_as_gpu::~nvhost_as_gpu() = default;
|
||||
|
||||
NvResult nvhost_as_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
NvResult nvhost_as_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input,
|
||||
std::vector<u8>& output) {
|
||||
switch (command.group) {
|
||||
case 'A':
|
||||
switch (command.cmd) {
|
||||
|
@ -55,14 +55,13 @@ NvResult nvhost_as_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, std:
|
|||
}
|
||||
|
||||
NvResult nvhost_as_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) {
|
||||
std::vector<u8>& inline_output) {
|
||||
switch (command.group) {
|
||||
case 'A':
|
||||
switch (command.cmd) {
|
||||
|
|
|
@ -30,13 +30,11 @@ public:
|
|||
explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
|
||||
~nvhost_as_gpu() override;
|
||||
|
||||
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
|
||||
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output) override;
|
||||
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) override;
|
||||
std::vector<u8>& inline_output) override;
|
||||
|
||||
private:
|
||||
class BufferMap final {
|
||||
|
|
|
@ -20,8 +20,7 @@ nvhost_ctrl::nvhost_ctrl(Core::System& system, EventInterface& events_interface,
|
|||
: nvdevice(system), events_interface{events_interface}, syncpoint_manager{syncpoint_manager} {}
|
||||
nvhost_ctrl::~nvhost_ctrl() = default;
|
||||
|
||||
NvResult nvhost_ctrl::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
NvResult nvhost_ctrl::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
switch (command.group) {
|
||||
case 0x0:
|
||||
switch (command.cmd) {
|
||||
|
@ -30,9 +29,9 @@ NvResult nvhost_ctrl::Ioctl1(Ioctl command, const std::vector<u8>& input, std::v
|
|||
case 0x1c:
|
||||
return IocCtrlClearEventWait(input, output);
|
||||
case 0x1d:
|
||||
return IocCtrlEventWait(input, output, false, ctrl);
|
||||
return IocCtrlEventWait(input, output, false);
|
||||
case 0x1e:
|
||||
return IocCtrlEventWait(input, output, true, ctrl);
|
||||
return IocCtrlEventWait(input, output, true);
|
||||
case 0x1f:
|
||||
return IocCtrlEventRegister(input, output);
|
||||
case 0x20:
|
||||
|
@ -48,14 +47,13 @@ NvResult nvhost_ctrl::Ioctl1(Ioctl command, const std::vector<u8>& input, std::v
|
|||
}
|
||||
|
||||
NvResult nvhost_ctrl::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) {
|
||||
std::vector<u8>& inline_outpu) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
@ -69,7 +67,7 @@ NvResult nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector
|
|||
}
|
||||
|
||||
NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output,
|
||||
bool is_async, IoctlCtrl& ctrl) {
|
||||
bool is_async) {
|
||||
IocCtrlEventWaitParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_async={}",
|
||||
|
@ -141,12 +139,6 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector
|
|||
params.value |= event_id;
|
||||
event.event.writable->Clear();
|
||||
gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value);
|
||||
if (!is_async && ctrl.fresh_call) {
|
||||
ctrl.must_delay = true;
|
||||
ctrl.timeout = params.timeout;
|
||||
ctrl.event_id = event_id;
|
||||
return NvResult::Timeout;
|
||||
}
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
return NvResult::Timeout;
|
||||
}
|
||||
|
|
|
@ -18,13 +18,11 @@ public:
|
|||
SyncpointManager& syncpoint_manager);
|
||||
~nvhost_ctrl() override;
|
||||
|
||||
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
|
||||
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output) override;
|
||||
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) override;
|
||||
std::vector<u8>& inline_output) override;
|
||||
|
||||
private:
|
||||
struct IocSyncptReadParams {
|
||||
|
@ -123,8 +121,7 @@ private:
|
|||
static_assert(sizeof(IocCtrlEventKill) == 8, "IocCtrlEventKill is incorrect size");
|
||||
|
||||
NvResult NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async,
|
||||
IoctlCtrl& ctrl);
|
||||
NvResult IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async);
|
||||
NvResult IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
|
|
|
@ -16,7 +16,7 @@ nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {}
|
|||
nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default;
|
||||
|
||||
NvResult nvhost_ctrl_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input,
|
||||
std::vector<u8>& output, IoctlCtrl& ctrl) {
|
||||
std::vector<u8>& output) {
|
||||
switch (command.group) {
|
||||
case 'G':
|
||||
switch (command.cmd) {
|
||||
|
@ -48,15 +48,13 @@ NvResult nvhost_ctrl_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input,
|
|||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input,
|
||||
std::vector<u8>& output, std::vector<u8>& inline_output,
|
||||
IoctlCtrl& ctrl) {
|
||||
std::vector<u8>& output, std::vector<u8>& inline_output) {
|
||||
switch (command.group) {
|
||||
case 'G':
|
||||
switch (command.cmd) {
|
||||
|
|
|
@ -16,13 +16,11 @@ public:
|
|||
explicit nvhost_ctrl_gpu(Core::System& system);
|
||||
~nvhost_ctrl_gpu() override;
|
||||
|
||||
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
|
||||
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output) override;
|
||||
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) override;
|
||||
std::vector<u8>& inline_output) override;
|
||||
|
||||
private:
|
||||
struct IoctlGpuCharacteristics {
|
||||
|
|
|
@ -23,8 +23,7 @@ nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
|
|||
|
||||
nvhost_gpu::~nvhost_gpu() = default;
|
||||
|
||||
NvResult nvhost_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
NvResult nvhost_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
switch (command.group) {
|
||||
case 0x0:
|
||||
switch (command.cmd) {
|
||||
|
@ -76,8 +75,7 @@ NvResult nvhost_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, std::ve
|
|||
};
|
||||
|
||||
NvResult nvhost_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output) {
|
||||
switch (command.group) {
|
||||
case 'H':
|
||||
switch (command.cmd) {
|
||||
|
@ -91,7 +89,7 @@ NvResult nvhost_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
|||
}
|
||||
|
||||
NvResult nvhost_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) {
|
||||
std::vector<u8>& inline_output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
|
|
@ -26,13 +26,11 @@ public:
|
|||
SyncpointManager& syncpoint_manager);
|
||||
~nvhost_gpu() override;
|
||||
|
||||
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
|
||||
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output) override;
|
||||
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) override;
|
||||
std::vector<u8>& inline_output) override;
|
||||
|
||||
private:
|
||||
enum class CtxObjects : u32_le {
|
||||
|
|
|
@ -15,8 +15,8 @@ nvhost_nvdec::nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_de
|
|||
: nvhost_nvdec_common(system, std::move(nvmap_dev)) {}
|
||||
nvhost_nvdec::~nvhost_nvdec() = default;
|
||||
|
||||
NvResult nvhost_nvdec::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
NvResult nvhost_nvdec::Ioctl1(Ioctl command, const std::vector<u8>& input,
|
||||
std::vector<u8>& output) {
|
||||
switch (command.group) {
|
||||
case 0x0:
|
||||
switch (command.cmd) {
|
||||
|
@ -58,14 +58,13 @@ NvResult nvhost_nvdec::Ioctl1(Ioctl command, const std::vector<u8>& input, std::
|
|||
}
|
||||
|
||||
NvResult nvhost_nvdec::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) {
|
||||
std::vector<u8>& inline_output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
|
|
@ -14,13 +14,11 @@ public:
|
|||
explicit nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
|
||||
~nvhost_nvdec() override;
|
||||
|
||||
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
|
||||
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output) override;
|
||||
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) override;
|
||||
std::vector<u8>& inline_output) override;
|
||||
};
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
||||
|
|
|
@ -13,8 +13,8 @@ namespace Service::Nvidia::Devices {
|
|||
nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {}
|
||||
nvhost_nvjpg::~nvhost_nvjpg() = default;
|
||||
|
||||
NvResult nvhost_nvjpg::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
NvResult nvhost_nvjpg::Ioctl1(Ioctl command, const std::vector<u8>& input,
|
||||
std::vector<u8>& output) {
|
||||
switch (command.group) {
|
||||
case 'H':
|
||||
switch (command.cmd) {
|
||||
|
@ -33,14 +33,13 @@ NvResult nvhost_nvjpg::Ioctl1(Ioctl command, const std::vector<u8>& input, std::
|
|||
}
|
||||
|
||||
NvResult nvhost_nvjpg::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvjpg::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) {
|
||||
std::vector<u8>& inline_output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
|
|
@ -16,13 +16,11 @@ public:
|
|||
explicit nvhost_nvjpg(Core::System& system);
|
||||
~nvhost_nvjpg() override;
|
||||
|
||||
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
|
||||
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output) override;
|
||||
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) override;
|
||||
std::vector<u8>& inline_output) override;
|
||||
|
||||
private:
|
||||
struct IoctlSetNvmapFD {
|
||||
|
|
|
@ -15,8 +15,7 @@ nvhost_vic::nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
|
|||
|
||||
nvhost_vic::~nvhost_vic() = default;
|
||||
|
||||
NvResult nvhost_vic::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
NvResult nvhost_vic::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
switch (command.group) {
|
||||
case 0x0:
|
||||
switch (command.cmd) {
|
||||
|
@ -51,14 +50,13 @@ NvResult nvhost_vic::Ioctl1(Ioctl command, const std::vector<u8>& input, std::ve
|
|||
}
|
||||
|
||||
NvResult nvhost_vic::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvhost_vic::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) {
|
||||
std::vector<u8>& inline_output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
|
|
@ -14,12 +14,10 @@ public:
|
|||
explicit nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
|
||||
~nvhost_vic();
|
||||
|
||||
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
|
||||
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output) override;
|
||||
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) override;
|
||||
std::vector<u8>& inline_output) override;
|
||||
};
|
||||
} // namespace Service::Nvidia::Devices
|
||||
|
|
|
@ -19,8 +19,7 @@ nvmap::nvmap(Core::System& system) : nvdevice(system) {
|
|||
|
||||
nvmap::~nvmap() = default;
|
||||
|
||||
NvResult nvmap::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
NvResult nvmap::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
switch (command.group) {
|
||||
case 0x1:
|
||||
switch (command.cmd) {
|
||||
|
@ -49,14 +48,13 @@ NvResult nvmap::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<
|
|||
}
|
||||
|
||||
NvResult nvmap::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvmap::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) {
|
||||
std::vector<u8>& inline_output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
|
|
@ -19,13 +19,11 @@ public:
|
|||
explicit nvmap(Core::System& system);
|
||||
~nvmap() override;
|
||||
|
||||
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
|
||||
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output) override;
|
||||
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) override;
|
||||
std::vector<u8>& inline_output) override;
|
||||
|
||||
/// Returns the allocated address of an nvmap object given its handle.
|
||||
VAddr GetObjectAddress(u32 handle) const;
|
||||
|
|
|
@ -61,32 +61,9 @@ void NVDRV::Ioctl1(Kernel::HLERequestContext& ctx) {
|
|||
std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0));
|
||||
const auto input_buffer = ctx.ReadBuffer(0);
|
||||
|
||||
IoctlCtrl ctrl{};
|
||||
|
||||
const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, output_buffer, ctrl);
|
||||
if (ctrl.must_delay) {
|
||||
ctrl.fresh_call = false;
|
||||
ctx.SleepClientThread(
|
||||
"NVServices::DelayedResponse", ctrl.timeout,
|
||||
[=, this](std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx_,
|
||||
Kernel::ThreadWakeupReason reason) {
|
||||
IoctlCtrl ctrl2{ctrl};
|
||||
std::vector<u8> tmp_output = output_buffer;
|
||||
const auto nv_result2 = nvdrv->Ioctl1(fd, command, input_buffer, tmp_output, ctrl2);
|
||||
|
||||
if (command.is_out != 0) {
|
||||
ctx.WriteBuffer(tmp_output);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx_, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushEnum(nv_result2);
|
||||
},
|
||||
nvdrv->GetEventWriteable(ctrl.event_id));
|
||||
} else {
|
||||
if (command.is_out != 0) {
|
||||
ctx.WriteBuffer(output_buffer);
|
||||
}
|
||||
const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, output_buffer);
|
||||
if (command.is_out != 0) {
|
||||
ctx.WriteBuffer(output_buffer);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
|
@ -110,36 +87,8 @@ void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) {
|
|||
const auto input_inlined_buffer = ctx.ReadBuffer(1);
|
||||
std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0));
|
||||
|
||||
IoctlCtrl ctrl{};
|
||||
|
||||
const auto nv_result =
|
||||
nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, output_buffer, ctrl);
|
||||
if (ctrl.must_delay) {
|
||||
ctrl.fresh_call = false;
|
||||
ctx.SleepClientThread(
|
||||
"NVServices::DelayedResponse", ctrl.timeout,
|
||||
[=, this](std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx_,
|
||||
Kernel::ThreadWakeupReason reason) {
|
||||
IoctlCtrl ctrl2{ctrl};
|
||||
std::vector<u8> tmp_output = output_buffer;
|
||||
const auto nv_result2 = nvdrv->Ioctl2(fd, command, input_buffer,
|
||||
input_inlined_buffer, tmp_output, ctrl2);
|
||||
|
||||
if (command.is_out != 0) {
|
||||
ctx.WriteBuffer(tmp_output);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx_, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushEnum(nv_result2);
|
||||
},
|
||||
nvdrv->GetEventWriteable(ctrl.event_id));
|
||||
} else {
|
||||
if (command.is_out != 0) {
|
||||
ctx.WriteBuffer(output_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, output_buffer);
|
||||
if (command.is_out != 0) {
|
||||
ctx.WriteBuffer(output_buffer);
|
||||
}
|
||||
|
@ -165,36 +114,11 @@ void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) {
|
|||
std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0));
|
||||
std::vector<u8> output_buffer_inline(ctx.GetWriteBufferSize(1));
|
||||
|
||||
IoctlCtrl ctrl{};
|
||||
const auto nv_result =
|
||||
nvdrv->Ioctl3(fd, command, input_buffer, output_buffer, output_buffer_inline, ctrl);
|
||||
if (ctrl.must_delay) {
|
||||
ctrl.fresh_call = false;
|
||||
ctx.SleepClientThread(
|
||||
"NVServices::DelayedResponse", ctrl.timeout,
|
||||
[=, this](std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx_,
|
||||
Kernel::ThreadWakeupReason reason) {
|
||||
IoctlCtrl ctrl2{ctrl};
|
||||
std::vector<u8> tmp_output = output_buffer;
|
||||
std::vector<u8> tmp_output2 = output_buffer;
|
||||
const auto nv_result2 =
|
||||
nvdrv->Ioctl3(fd, command, input_buffer, tmp_output, tmp_output2, ctrl2);
|
||||
|
||||
if (command.is_out != 0) {
|
||||
ctx.WriteBuffer(tmp_output, 0);
|
||||
ctx.WriteBuffer(tmp_output2, 1);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx_, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushEnum(nv_result2);
|
||||
},
|
||||
nvdrv->GetEventWriteable(ctrl.event_id));
|
||||
} else {
|
||||
if (command.is_out != 0) {
|
||||
ctx.WriteBuffer(output_buffer, 0);
|
||||
ctx.WriteBuffer(output_buffer_inline, 1);
|
||||
}
|
||||
nvdrv->Ioctl3(fd, command, input_buffer, output_buffer, output_buffer_inline);
|
||||
if (command.is_out != 0) {
|
||||
ctx.WriteBuffer(output_buffer, 0);
|
||||
ctx.WriteBuffer(output_buffer_inline, 1);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
|
|
|
@ -97,15 +97,4 @@ union Ioctl {
|
|||
BitField<31, 1, u32> is_out;
|
||||
};
|
||||
|
||||
struct IoctlCtrl {
|
||||
// First call done to the servioce for services that call itself again after a call.
|
||||
bool fresh_call{true};
|
||||
// Tells the Ioctl Wrapper that it must delay the IPC response and send the thread to sleep
|
||||
bool must_delay{};
|
||||
// Timeout for the delay
|
||||
s64 timeout{};
|
||||
// NV Event Id
|
||||
s32 event_id{-1};
|
||||
};
|
||||
|
||||
} // namespace Service::Nvidia
|
||||
|
|
|
@ -91,7 +91,7 @@ DeviceFD Module::Open(const std::string& device_name) {
|
|||
}
|
||||
|
||||
NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
|
||||
std::vector<u8>& output, IoctlCtrl& ctrl) {
|
||||
std::vector<u8>& output) {
|
||||
if (fd < 0) {
|
||||
LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
|
||||
return NvResult::InvalidState;
|
||||
|
@ -104,12 +104,11 @@ NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input
|
|||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
return itr->second->Ioctl1(command, input, output, ctrl);
|
||||
return itr->second->Ioctl1(command, input, output);
|
||||
}
|
||||
|
||||
NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output) {
|
||||
if (fd < 0) {
|
||||
LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
|
||||
return NvResult::InvalidState;
|
||||
|
@ -122,11 +121,11 @@ NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input
|
|||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
return itr->second->Ioctl2(command, input, inline_input, output, ctrl);
|
||||
return itr->second->Ioctl2(command, input, inline_input, output);
|
||||
}
|
||||
|
||||
NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
|
||||
std::vector<u8>& output, std::vector<u8>& inline_output, IoctlCtrl& ctrl) {
|
||||
std::vector<u8>& output, std::vector<u8>& inline_output) {
|
||||
if (fd < 0) {
|
||||
LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
|
||||
return NvResult::InvalidState;
|
||||
|
@ -139,7 +138,7 @@ NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input
|
|||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
return itr->second->Ioctl3(command, input, output, inline_output, ctrl);
|
||||
return itr->second->Ioctl3(command, input, output, inline_output);
|
||||
}
|
||||
|
||||
NvResult Module::Close(DeviceFD fd) {
|
||||
|
|
|
@ -119,13 +119,13 @@ public:
|
|||
|
||||
/// Sends an ioctl command to the specified file descriptor.
|
||||
NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
|
||||
std::vector<u8>& output, IoctlCtrl& ctrl);
|
||||
std::vector<u8>& output);
|
||||
|
||||
NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output, IoctlCtrl& ctrl);
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output);
|
||||
|
||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
|
||||
std::vector<u8>& output, std::vector<u8>& inline_output, IoctlCtrl& ctrl);
|
||||
std::vector<u8>& output, std::vector<u8>& inline_output);
|
||||
|
||||
/// Closes a device file descriptor and returns operation success.
|
||||
NvResult Close(DeviceFD fd);
|
||||
|
|
|
@ -25,7 +25,12 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer)
|
|||
ASSERT(slot < buffer_slots);
|
||||
LOG_WARNING(Service, "Adding graphics buffer {}", slot);
|
||||
|
||||
free_buffers.push_back(slot);
|
||||
{
|
||||
std::unique_lock lock{queue_mutex};
|
||||
free_buffers.push_back(slot);
|
||||
}
|
||||
condition.notify_one();
|
||||
|
||||
buffers[slot] = {
|
||||
.slot = slot,
|
||||
.status = Buffer::Status::Free,
|
||||
|
@ -41,10 +46,20 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer)
|
|||
|
||||
std::optional<std::pair<u32, Service::Nvidia::MultiFence*>> BufferQueue::DequeueBuffer(u32 width,
|
||||
u32 height) {
|
||||
// Wait for first request before trying to dequeue
|
||||
{
|
||||
std::unique_lock lock{queue_mutex};
|
||||
condition.wait(lock, [this] { return !free_buffers.empty() || !is_connect; });
|
||||
}
|
||||
|
||||
if (free_buffers.empty()) {
|
||||
if (!is_connect) {
|
||||
// Buffer was disconnected while the thread was blocked, this is most likely due to
|
||||
// emulation being stopped
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::unique_lock lock{queue_mutex};
|
||||
|
||||
auto f_itr = free_buffers.begin();
|
||||
auto slot = buffers.size();
|
||||
|
||||
|
@ -97,7 +112,11 @@ void BufferQueue::CancelBuffer(u32 slot, const Service::Nvidia::MultiFence& mult
|
|||
buffers[slot].multi_fence = multi_fence;
|
||||
buffers[slot].swap_interval = 0;
|
||||
|
||||
free_buffers.push_back(slot);
|
||||
{
|
||||
std::unique_lock lock{queue_mutex};
|
||||
free_buffers.push_back(slot);
|
||||
}
|
||||
condition.notify_one();
|
||||
|
||||
buffer_wait_event.writable->Signal();
|
||||
}
|
||||
|
@ -127,15 +146,28 @@ void BufferQueue::ReleaseBuffer(u32 slot) {
|
|||
ASSERT(buffers[slot].slot == slot);
|
||||
|
||||
buffers[slot].status = Buffer::Status::Free;
|
||||
free_buffers.push_back(slot);
|
||||
{
|
||||
std::unique_lock lock{queue_mutex};
|
||||
free_buffers.push_back(slot);
|
||||
}
|
||||
condition.notify_one();
|
||||
|
||||
buffer_wait_event.writable->Signal();
|
||||
}
|
||||
|
||||
void BufferQueue::Connect() {
|
||||
queue_sequence.clear();
|
||||
id = 1;
|
||||
layer_id = 1;
|
||||
is_connect = true;
|
||||
}
|
||||
|
||||
void BufferQueue::Disconnect() {
|
||||
buffers.fill({});
|
||||
queue_sequence.clear();
|
||||
buffer_wait_event.writable->Signal();
|
||||
is_connect = false;
|
||||
condition.notify_one();
|
||||
}
|
||||
|
||||
u32 BufferQueue::Query(QueryType type) {
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <condition_variable>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
|
@ -99,6 +101,7 @@ public:
|
|||
void CancelBuffer(u32 slot, const Service::Nvidia::MultiFence& multi_fence);
|
||||
std::optional<std::reference_wrapper<const Buffer>> AcquireBuffer();
|
||||
void ReleaseBuffer(u32 slot);
|
||||
void Connect();
|
||||
void Disconnect();
|
||||
u32 Query(QueryType type);
|
||||
|
||||
|
@ -106,18 +109,28 @@ public:
|
|||
return id;
|
||||
}
|
||||
|
||||
bool IsConnected() const {
|
||||
return is_connect;
|
||||
}
|
||||
|
||||
std::shared_ptr<Kernel::WritableEvent> GetWritableBufferWaitEvent() const;
|
||||
|
||||
std::shared_ptr<Kernel::ReadableEvent> GetBufferWaitEvent() const;
|
||||
|
||||
private:
|
||||
u32 id;
|
||||
u64 layer_id;
|
||||
BufferQueue(const BufferQueue&) = delete;
|
||||
|
||||
u32 id{};
|
||||
u64 layer_id{};
|
||||
std::atomic_bool is_connect{};
|
||||
|
||||
std::list<u32> free_buffers;
|
||||
std::array<Buffer, buffer_slots> buffers;
|
||||
std::list<u32> queue_sequence;
|
||||
Kernel::EventPair buffer_wait_event;
|
||||
|
||||
std::mutex queue_mutex;
|
||||
std::condition_variable condition;
|
||||
};
|
||||
|
||||
} // namespace Service::NVFlinger
|
||||
|
|
|
@ -88,6 +88,10 @@ NVFlinger::NVFlinger(Core::System& system) : system(system) {
|
|||
}
|
||||
|
||||
NVFlinger::~NVFlinger() {
|
||||
for (auto& buffer_queue : buffer_queues) {
|
||||
buffer_queue->Disconnect();
|
||||
}
|
||||
|
||||
if (system.IsMulticore()) {
|
||||
is_running = false;
|
||||
wait_event->Set();
|
||||
|
@ -104,6 +108,8 @@ void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
|
|||
}
|
||||
|
||||
std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) {
|
||||
const auto guard = Lock();
|
||||
|
||||
LOG_DEBUG(Service, "Opening \"{}\" display", name);
|
||||
|
||||
// TODO(Subv): Currently we only support the Default display.
|
||||
|
@ -121,6 +127,7 @@ std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) {
|
|||
}
|
||||
|
||||
std::optional<u64> NVFlinger::CreateLayer(u64 display_id) {
|
||||
const auto guard = Lock();
|
||||
auto* const display = FindDisplay(display_id);
|
||||
|
||||
if (display == nullptr) {
|
||||
|
@ -129,18 +136,22 @@ std::optional<u64> NVFlinger::CreateLayer(u64 display_id) {
|
|||
|
||||
const u64 layer_id = next_layer_id++;
|
||||
const u32 buffer_queue_id = next_buffer_queue_id++;
|
||||
buffer_queues.emplace_back(system.Kernel(), buffer_queue_id, layer_id);
|
||||
display->CreateLayer(layer_id, buffer_queues.back());
|
||||
buffer_queues.emplace_back(
|
||||
std::make_unique<BufferQueue>(system.Kernel(), buffer_queue_id, layer_id));
|
||||
display->CreateLayer(layer_id, *buffer_queues.back());
|
||||
return layer_id;
|
||||
}
|
||||
|
||||
void NVFlinger::CloseLayer(u64 layer_id) {
|
||||
const auto guard = Lock();
|
||||
|
||||
for (auto& display : displays) {
|
||||
display.CloseLayer(layer_id);
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) const {
|
||||
const auto guard = Lock();
|
||||
const auto* const layer = FindLayer(display_id, layer_id);
|
||||
|
||||
if (layer == nullptr) {
|
||||
|
@ -151,6 +162,7 @@ std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) co
|
|||
}
|
||||
|
||||
std::shared_ptr<Kernel::ReadableEvent> NVFlinger::FindVsyncEvent(u64 display_id) const {
|
||||
const auto guard = Lock();
|
||||
auto* const display = FindDisplay(display_id);
|
||||
|
||||
if (display == nullptr) {
|
||||
|
@ -160,20 +172,16 @@ std::shared_ptr<Kernel::ReadableEvent> NVFlinger::FindVsyncEvent(u64 display_id)
|
|||
return display->GetVSyncEvent();
|
||||
}
|
||||
|
||||
BufferQueue& NVFlinger::FindBufferQueue(u32 id) {
|
||||
BufferQueue* NVFlinger::FindBufferQueue(u32 id) {
|
||||
const auto guard = Lock();
|
||||
const auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(),
|
||||
[id](const auto& queue) { return queue.GetId() == id; });
|
||||
[id](const auto& queue) { return queue->GetId() == id; });
|
||||
|
||||
ASSERT(itr != buffer_queues.end());
|
||||
return *itr;
|
||||
}
|
||||
if (itr == buffer_queues.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const BufferQueue& NVFlinger::FindBufferQueue(u32 id) const {
|
||||
const auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(),
|
||||
[id](const auto& queue) { return queue.GetId() == id; });
|
||||
|
||||
ASSERT(itr != buffer_queues.end());
|
||||
return *itr;
|
||||
return itr->get();
|
||||
}
|
||||
|
||||
VI::Display* NVFlinger::FindDisplay(u64 display_id) {
|
||||
|
|
|
@ -75,10 +75,7 @@ public:
|
|||
[[nodiscard]] std::shared_ptr<Kernel::ReadableEvent> FindVsyncEvent(u64 display_id) const;
|
||||
|
||||
/// Obtains a buffer queue identified by the ID.
|
||||
[[nodiscard]] BufferQueue& FindBufferQueue(u32 id);
|
||||
|
||||
/// Obtains a buffer queue identified by the ID.
|
||||
[[nodiscard]] const BufferQueue& FindBufferQueue(u32 id) const;
|
||||
[[nodiscard]] BufferQueue* FindBufferQueue(u32 id);
|
||||
|
||||
/// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when
|
||||
/// finished.
|
||||
|
@ -86,11 +83,11 @@ public:
|
|||
|
||||
[[nodiscard]] s64 GetNextTicks() const;
|
||||
|
||||
private:
|
||||
[[nodiscard]] std::unique_lock<std::mutex> Lock() const {
|
||||
return std::unique_lock{*guard};
|
||||
}
|
||||
|
||||
private:
|
||||
/// Finds the display identified by the specified ID.
|
||||
[[nodiscard]] VI::Display* FindDisplay(u64 display_id);
|
||||
|
||||
|
@ -110,7 +107,7 @@ private:
|
|||
std::shared_ptr<Nvidia::Module> nvdrv;
|
||||
|
||||
std::vector<VI::Display> displays;
|
||||
std::vector<BufferQueue> buffer_queues;
|
||||
std::vector<std::unique_ptr<BufferQueue>> buffer_queues;
|
||||
|
||||
/// Id to use for the next layer that is created, this counter is shared among all displays.
|
||||
u64 next_layer_id = 1;
|
||||
|
|
|
@ -95,9 +95,14 @@ ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* se
|
|||
: system{system_}, service_name{service_name_}, max_sessions{max_sessions_},
|
||||
handler_invoker{handler_invoker_} {}
|
||||
|
||||
ServiceFrameworkBase::~ServiceFrameworkBase() = default;
|
||||
ServiceFrameworkBase::~ServiceFrameworkBase() {
|
||||
// Wait for other threads to release access before destroying
|
||||
const auto guard = LockService();
|
||||
}
|
||||
|
||||
void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) {
|
||||
const auto guard = LockService();
|
||||
|
||||
ASSERT(!port_installed);
|
||||
|
||||
auto port = service_manager.RegisterService(service_name, max_sessions).Unwrap();
|
||||
|
@ -106,6 +111,8 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager)
|
|||
}
|
||||
|
||||
void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) {
|
||||
const auto guard = LockService();
|
||||
|
||||
ASSERT(!port_installed);
|
||||
|
||||
auto [server_port, client_port] =
|
||||
|
@ -115,17 +122,6 @@ void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) {
|
|||
port_installed = true;
|
||||
}
|
||||
|
||||
std::shared_ptr<Kernel::ClientPort> ServiceFrameworkBase::CreatePort(Kernel::KernelCore& kernel) {
|
||||
ASSERT(!port_installed);
|
||||
|
||||
auto [server_port, client_port] =
|
||||
Kernel::ServerPort::CreatePortPair(kernel, max_sessions, service_name);
|
||||
auto port = MakeResult(std::move(server_port)).Unwrap();
|
||||
port->SetHleHandler(shared_from_this());
|
||||
port_installed = true;
|
||||
return client_port;
|
||||
}
|
||||
|
||||
void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) {
|
||||
handlers.reserve(handlers.size() + n);
|
||||
for (std::size_t i = 0; i < n; ++i) {
|
||||
|
@ -164,6 +160,8 @@ void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) {
|
|||
}
|
||||
|
||||
ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& context) {
|
||||
const auto guard = LockService();
|
||||
|
||||
switch (context.GetCommandType()) {
|
||||
case IPC::CommandType::Close: {
|
||||
IPC::ResponseBuilder rb{context, 2};
|
||||
|
@ -184,7 +182,11 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co
|
|||
UNIMPLEMENTED_MSG("command_type={}", context.GetCommandType());
|
||||
}
|
||||
|
||||
context.WriteToOutgoingCommandBuffer(context.GetThread());
|
||||
// If emulation was shutdown, we are closing service threads, do not write the response back to
|
||||
// memory that may be shutting down as well.
|
||||
if (system.IsPoweredOn()) {
|
||||
context.WriteToOutgoingCommandBuffer(context.GetThread());
|
||||
}
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -5,9 +5,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "common/spin_lock.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
|
||||
|
@ -68,11 +70,9 @@ public:
|
|||
void InstallAsService(SM::ServiceManager& service_manager);
|
||||
/// Creates a port pair and registers it on the kernel's global port registry.
|
||||
void InstallAsNamedPort(Kernel::KernelCore& kernel);
|
||||
/// Creates and returns an unregistered port for the service.
|
||||
std::shared_ptr<Kernel::ClientPort> CreatePort(Kernel::KernelCore& kernel);
|
||||
|
||||
/// Invokes a service request routine.
|
||||
void InvokeRequest(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/// Handles a synchronization request for the service.
|
||||
ResultCode HandleSyncRequest(Kernel::HLERequestContext& context) override;
|
||||
|
||||
protected:
|
||||
|
@ -80,6 +80,11 @@ protected:
|
|||
template <typename Self>
|
||||
using HandlerFnP = void (Self::*)(Kernel::HLERequestContext&);
|
||||
|
||||
/// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
|
||||
[[nodiscard]] std::scoped_lock<Common::SpinLock> LockService() {
|
||||
return std::scoped_lock{lock_service};
|
||||
}
|
||||
|
||||
/// System context that the service operates under.
|
||||
Core::System& system;
|
||||
|
||||
|
@ -115,6 +120,9 @@ private:
|
|||
/// Function used to safely up-cast pointers to the derived class before invoking a handler.
|
||||
InvokerFn* handler_invoker;
|
||||
boost::container::flat_map<u32, FunctionInfoBase> handlers;
|
||||
|
||||
/// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
|
||||
Common::SpinLock lock_service;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,161 +0,0 @@
|
|||
// Copyright 2020 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/microprofile.h"
|
||||
#include "common/thread.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
|
||||
namespace Service::Sockets {
|
||||
|
||||
/**
|
||||
* Worker abstraction to execute blocking calls on host without blocking the guest thread
|
||||
*
|
||||
* @tparam Service Service where the work is executed
|
||||
* @tparam Types Types of work to execute
|
||||
*/
|
||||
template <class Service, class... Types>
|
||||
class BlockingWorker {
|
||||
using This = BlockingWorker<Service, Types...>;
|
||||
using WorkVariant = std::variant<std::monostate, Types...>;
|
||||
|
||||
public:
|
||||
/// Create a new worker
|
||||
static std::unique_ptr<This> Create(Core::System& system, Service* service,
|
||||
std::string_view name) {
|
||||
return std::unique_ptr<This>(new This(system, service, name));
|
||||
}
|
||||
|
||||
~BlockingWorker() {
|
||||
while (!is_available.load(std::memory_order_relaxed)) {
|
||||
// Busy wait until work is finished
|
||||
std::this_thread::yield();
|
||||
}
|
||||
// Monostate means to exit the thread
|
||||
work = std::monostate{};
|
||||
work_event.Set();
|
||||
thread.join();
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to capture the worker to send work after a success
|
||||
* @returns True when the worker has been successfully captured
|
||||
*/
|
||||
bool TryCapture() {
|
||||
bool expected = true;
|
||||
return is_available.compare_exchange_weak(expected, false, std::memory_order_relaxed,
|
||||
std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send work to this worker abstraction
|
||||
* @see TryCapture must be called before attempting to call this function
|
||||
*/
|
||||
template <class Work>
|
||||
void SendWork(Work new_work) {
|
||||
ASSERT_MSG(!is_available, "Trying to send work on a worker that's not captured");
|
||||
work = std::move(new_work);
|
||||
work_event.Set();
|
||||
}
|
||||
|
||||
/// Generate a callback for @see SleepClientThread
|
||||
template <class Work>
|
||||
auto Callback() {
|
||||
return [this](std::shared_ptr<Kernel::Thread>, Kernel::HLERequestContext& ctx,
|
||||
Kernel::ThreadWakeupReason reason) {
|
||||
ASSERT(reason == Kernel::ThreadWakeupReason::Signal);
|
||||
std::get<Work>(work).Response(ctx);
|
||||
is_available.store(true);
|
||||
};
|
||||
}
|
||||
|
||||
/// Get kernel event that will be signalled by the worker when the host operation finishes
|
||||
std::shared_ptr<Kernel::WritableEvent> KernelEvent() const {
|
||||
return kernel_event;
|
||||
}
|
||||
|
||||
private:
|
||||
explicit BlockingWorker(Core::System& system, Service* service, std::string_view name) {
|
||||
auto pair = Kernel::WritableEvent::CreateEventPair(system.Kernel(), std::string(name));
|
||||
kernel_event = std::move(pair.writable);
|
||||
thread = std::thread([this, &system, service, name] { Run(system, service, name); });
|
||||
}
|
||||
|
||||
void Run(Core::System& system, Service* service, std::string_view name) {
|
||||
system.RegisterHostThread();
|
||||
|
||||
const std::string thread_name = fmt::format("yuzu:{}", name);
|
||||
MicroProfileOnThreadCreate(thread_name.c_str());
|
||||
Common::SetCurrentThreadName(thread_name.c_str());
|
||||
|
||||
bool keep_running = true;
|
||||
while (keep_running) {
|
||||
work_event.Wait();
|
||||
|
||||
const auto visit_fn = [service, &keep_running]<typename T>(T&& w) {
|
||||
if constexpr (std::is_same_v<std::decay_t<T>, std::monostate>) {
|
||||
keep_running = false;
|
||||
} else {
|
||||
w.Execute(service);
|
||||
}
|
||||
};
|
||||
std::visit(visit_fn, work);
|
||||
|
||||
kernel_event->Signal();
|
||||
}
|
||||
}
|
||||
|
||||
std::thread thread;
|
||||
WorkVariant work;
|
||||
Common::Event work_event;
|
||||
std::shared_ptr<Kernel::WritableEvent> kernel_event;
|
||||
std::atomic_bool is_available{true};
|
||||
};
|
||||
|
||||
template <class Service, class... Types>
|
||||
class BlockingWorkerPool {
|
||||
using Worker = BlockingWorker<Service, Types...>;
|
||||
|
||||
public:
|
||||
explicit BlockingWorkerPool(Core::System& system_, Service* service_)
|
||||
: system{system_}, service{service_} {}
|
||||
|
||||
/// Returns a captured worker thread, creating new ones if necessary
|
||||
Worker* CaptureWorker() {
|
||||
for (auto& worker : workers) {
|
||||
if (worker->TryCapture()) {
|
||||
return worker.get();
|
||||
}
|
||||
}
|
||||
auto new_worker = Worker::Create(system, service, fmt::format("BSD:{}", workers.size()));
|
||||
[[maybe_unused]] const bool success = new_worker->TryCapture();
|
||||
ASSERT(success);
|
||||
|
||||
return workers.emplace_back(std::move(new_worker)).get();
|
||||
}
|
||||
|
||||
private:
|
||||
Core::System& system;
|
||||
Service* const service;
|
||||
|
||||
std::vector<std::unique_ptr<Worker>> workers;
|
||||
};
|
||||
|
||||
} // namespace Service::Sockets
|
|
@ -178,13 +178,12 @@ void BSD::Poll(Kernel::HLERequestContext& ctx) {
|
|||
|
||||
LOG_DEBUG(Service, "called. nfds={} timeout={}", nfds, timeout);
|
||||
|
||||
ExecuteWork(ctx, "BSD:Poll", timeout != 0,
|
||||
PollWork{
|
||||
.nfds = nfds,
|
||||
.timeout = timeout,
|
||||
.read_buffer = ctx.ReadBuffer(),
|
||||
.write_buffer = std::vector<u8>(ctx.GetWriteBufferSize()),
|
||||
});
|
||||
ExecuteWork(ctx, PollWork{
|
||||
.nfds = nfds,
|
||||
.timeout = timeout,
|
||||
.read_buffer = ctx.ReadBuffer(),
|
||||
.write_buffer = std::vector<u8>(ctx.GetWriteBufferSize()),
|
||||
});
|
||||
}
|
||||
|
||||
void BSD::Accept(Kernel::HLERequestContext& ctx) {
|
||||
|
@ -193,11 +192,10 @@ void BSD::Accept(Kernel::HLERequestContext& ctx) {
|
|||
|
||||
LOG_DEBUG(Service, "called. fd={}", fd);
|
||||
|
||||
ExecuteWork(ctx, "BSD:Accept", IsBlockingSocket(fd),
|
||||
AcceptWork{
|
||||
.fd = fd,
|
||||
.write_buffer = std::vector<u8>(ctx.GetWriteBufferSize()),
|
||||
});
|
||||
ExecuteWork(ctx, AcceptWork{
|
||||
.fd = fd,
|
||||
.write_buffer = std::vector<u8>(ctx.GetWriteBufferSize()),
|
||||
});
|
||||
}
|
||||
|
||||
void BSD::Bind(Kernel::HLERequestContext& ctx) {
|
||||
|
@ -215,11 +213,10 @@ void BSD::Connect(Kernel::HLERequestContext& ctx) {
|
|||
|
||||
LOG_DEBUG(Service, "called. fd={} addrlen={}", fd, ctx.GetReadBufferSize());
|
||||
|
||||
ExecuteWork(ctx, "BSD:Connect", IsBlockingSocket(fd),
|
||||
ConnectWork{
|
||||
.fd = fd,
|
||||
.addr = ctx.ReadBuffer(),
|
||||
});
|
||||
ExecuteWork(ctx, ConnectWork{
|
||||
.fd = fd,
|
||||
.addr = ctx.ReadBuffer(),
|
||||
});
|
||||
}
|
||||
|
||||
void BSD::GetPeerName(Kernel::HLERequestContext& ctx) {
|
||||
|
@ -327,12 +324,11 @@ void BSD::Recv(Kernel::HLERequestContext& ctx) {
|
|||
|
||||
LOG_DEBUG(Service, "called. fd={} flags=0x{:x} len={}", fd, flags, ctx.GetWriteBufferSize());
|
||||
|
||||
ExecuteWork(ctx, "BSD:Recv", IsBlockingSocket(fd),
|
||||
RecvWork{
|
||||
.fd = fd,
|
||||
.flags = flags,
|
||||
.message = std::vector<u8>(ctx.GetWriteBufferSize()),
|
||||
});
|
||||
ExecuteWork(ctx, RecvWork{
|
||||
.fd = fd,
|
||||
.flags = flags,
|
||||
.message = std::vector<u8>(ctx.GetWriteBufferSize()),
|
||||
});
|
||||
}
|
||||
|
||||
void BSD::RecvFrom(Kernel::HLERequestContext& ctx) {
|
||||
|
@ -344,13 +340,12 @@ void BSD::RecvFrom(Kernel::HLERequestContext& ctx) {
|
|||
LOG_DEBUG(Service, "called. fd={} flags=0x{:x} len={} addrlen={}", fd, flags,
|
||||
ctx.GetWriteBufferSize(0), ctx.GetWriteBufferSize(1));
|
||||
|
||||
ExecuteWork(ctx, "BSD:RecvFrom", IsBlockingSocket(fd),
|
||||
RecvFromWork{
|
||||
.fd = fd,
|
||||
.flags = flags,
|
||||
.message = std::vector<u8>(ctx.GetWriteBufferSize(0)),
|
||||
.addr = std::vector<u8>(ctx.GetWriteBufferSize(1)),
|
||||
});
|
||||
ExecuteWork(ctx, RecvFromWork{
|
||||
.fd = fd,
|
||||
.flags = flags,
|
||||
.message = std::vector<u8>(ctx.GetWriteBufferSize(0)),
|
||||
.addr = std::vector<u8>(ctx.GetWriteBufferSize(1)),
|
||||
});
|
||||
}
|
||||
|
||||
void BSD::Send(Kernel::HLERequestContext& ctx) {
|
||||
|
@ -361,12 +356,11 @@ void BSD::Send(Kernel::HLERequestContext& ctx) {
|
|||
|
||||
LOG_DEBUG(Service, "called. fd={} flags=0x{:x} len={}", fd, flags, ctx.GetReadBufferSize());
|
||||
|
||||
ExecuteWork(ctx, "BSD:Send", IsBlockingSocket(fd),
|
||||
SendWork{
|
||||
.fd = fd,
|
||||
.flags = flags,
|
||||
.message = ctx.ReadBuffer(),
|
||||
});
|
||||
ExecuteWork(ctx, SendWork{
|
||||
.fd = fd,
|
||||
.flags = flags,
|
||||
.message = ctx.ReadBuffer(),
|
||||
});
|
||||
}
|
||||
|
||||
void BSD::SendTo(Kernel::HLERequestContext& ctx) {
|
||||
|
@ -377,13 +371,12 @@ void BSD::SendTo(Kernel::HLERequestContext& ctx) {
|
|||
LOG_DEBUG(Service, "called. fd={} flags=0x{} len={} addrlen={}", fd, flags,
|
||||
ctx.GetReadBufferSize(0), ctx.GetReadBufferSize(1));
|
||||
|
||||
ExecuteWork(ctx, "BSD:SendTo", IsBlockingSocket(fd),
|
||||
SendToWork{
|
||||
.fd = fd,
|
||||
.flags = flags,
|
||||
.message = ctx.ReadBuffer(0),
|
||||
.addr = ctx.ReadBuffer(1),
|
||||
});
|
||||
ExecuteWork(ctx, SendToWork{
|
||||
.fd = fd,
|
||||
.flags = flags,
|
||||
.message = ctx.ReadBuffer(0),
|
||||
.addr = ctx.ReadBuffer(1),
|
||||
});
|
||||
}
|
||||
|
||||
void BSD::Write(Kernel::HLERequestContext& ctx) {
|
||||
|
@ -392,12 +385,11 @@ void BSD::Write(Kernel::HLERequestContext& ctx) {
|
|||
|
||||
LOG_DEBUG(Service, "called. fd={} len={}", fd, ctx.GetReadBufferSize());
|
||||
|
||||
ExecuteWork(ctx, "BSD:Write", IsBlockingSocket(fd),
|
||||
SendWork{
|
||||
.fd = fd,
|
||||
.flags = 0,
|
||||
.message = ctx.ReadBuffer(),
|
||||
});
|
||||
ExecuteWork(ctx, SendWork{
|
||||
.fd = fd,
|
||||
.flags = 0,
|
||||
.message = ctx.ReadBuffer(),
|
||||
});
|
||||
}
|
||||
|
||||
void BSD::Close(Kernel::HLERequestContext& ctx) {
|
||||
|
@ -410,24 +402,9 @@ void BSD::Close(Kernel::HLERequestContext& ctx) {
|
|||
}
|
||||
|
||||
template <typename Work>
|
||||
void BSD::ExecuteWork(Kernel::HLERequestContext& ctx, std::string_view sleep_reason,
|
||||
bool is_blocking, Work work) {
|
||||
if (!is_blocking) {
|
||||
work.Execute(this);
|
||||
work.Response(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
// Signal a dummy response to make IPC validation happy
|
||||
// This will be overwritten by the SleepClientThread callback
|
||||
void BSD::ExecuteWork(Kernel::HLERequestContext& ctx, Work work) {
|
||||
work.Execute(this);
|
||||
work.Response(ctx);
|
||||
|
||||
auto worker = worker_pool.CaptureWorker();
|
||||
|
||||
ctx.SleepClientThread(std::string(sleep_reason), std::numeric_limits<u64>::max(),
|
||||
worker->Callback<Work>(), worker->KernelEvent());
|
||||
|
||||
worker->SendWork(std::move(work));
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protocol) {
|
||||
|
@ -807,18 +784,6 @@ bool BSD::IsFileDescriptorValid(s32 fd) const noexcept {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool BSD::IsBlockingSocket(s32 fd) const noexcept {
|
||||
// Inform invalid sockets as non-blocking
|
||||
// This way we avoid using a worker thread as it will fail without blocking host
|
||||
if (fd > static_cast<s32>(MAX_FD) || fd < 0) {
|
||||
return false;
|
||||
}
|
||||
if (!file_descriptors[fd]) {
|
||||
return false;
|
||||
}
|
||||
return (file_descriptors[fd]->flags & FLAG_O_NONBLOCK) != 0;
|
||||
}
|
||||
|
||||
void BSD::BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) const noexcept {
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
|
||||
|
@ -827,8 +792,7 @@ void BSD::BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) co
|
|||
rb.PushEnum(bsd_errno);
|
||||
}
|
||||
|
||||
BSD::BSD(Core::System& system_, const char* name)
|
||||
: ServiceFramework{system_, name}, worker_pool{system_, this} {
|
||||
BSD::BSD(Core::System& system_, const char* name) : ServiceFramework{system_, name} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &BSD::RegisterClient, "RegisterClient"},
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/sockets/blocking_worker.h"
|
||||
#include "core/hle/service/sockets/sockets.h"
|
||||
|
||||
namespace Core {
|
||||
|
@ -138,8 +137,7 @@ private:
|
|||
void Close(Kernel::HLERequestContext& ctx);
|
||||
|
||||
template <typename Work>
|
||||
void ExecuteWork(Kernel::HLERequestContext& ctx, std::string_view sleep_reason,
|
||||
bool is_blocking, Work work);
|
||||
void ExecuteWork(Kernel::HLERequestContext& ctx, Work work);
|
||||
|
||||
std::pair<s32, Errno> SocketImpl(Domain domain, Type type, Protocol protocol);
|
||||
std::pair<s32, Errno> PollImpl(std::vector<u8>& write_buffer, std::vector<u8> read_buffer,
|
||||
|
@ -163,15 +161,10 @@ private:
|
|||
|
||||
s32 FindFreeFileDescriptorHandle() noexcept;
|
||||
bool IsFileDescriptorValid(s32 fd) const noexcept;
|
||||
bool IsBlockingSocket(s32 fd) const noexcept;
|
||||
|
||||
void BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) const noexcept;
|
||||
|
||||
std::array<std::optional<FileDescriptor>, MAX_FD> file_descriptors;
|
||||
|
||||
BlockingWorkerPool<BSD, PollWork, AcceptWork, ConnectWork, RecvWork, RecvFromWork, SendWork,
|
||||
SendToWork>
|
||||
worker_pool;
|
||||
};
|
||||
|
||||
class BSDCFG final : public ServiceFramework<BSDCFG> {
|
||||
|
|
|
@ -536,8 +536,7 @@ private:
|
|||
LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id,
|
||||
transaction, flags);
|
||||
|
||||
const auto guard = nv_flinger.Lock();
|
||||
auto& buffer_queue = nv_flinger.FindBufferQueue(id);
|
||||
auto& buffer_queue = *nv_flinger.FindBufferQueue(id);
|
||||
|
||||
switch (transaction) {
|
||||
case TransactionId::Connect: {
|
||||
|
@ -547,6 +546,9 @@ private:
|
|||
Settings::values.resolution_factor.GetValue()),
|
||||
static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedHeight) *
|
||||
Settings::values.resolution_factor.GetValue())};
|
||||
|
||||
buffer_queue.Connect();
|
||||
|
||||
ctx.WriteBuffer(response.Serialize());
|
||||
break;
|
||||
}
|
||||
|
@ -563,40 +565,25 @@ private:
|
|||
IGBPDequeueBufferRequestParcel request{ctx.ReadBuffer()};
|
||||
const u32 width{request.data.width};
|
||||
const u32 height{request.data.height};
|
||||
auto result = buffer_queue.DequeueBuffer(width, height);
|
||||
|
||||
if (result) {
|
||||
// Buffer is available
|
||||
IGBPDequeueBufferResponseParcel response{result->first, *result->second};
|
||||
ctx.WriteBuffer(response.Serialize());
|
||||
} else {
|
||||
// Wait the current thread until a buffer becomes available
|
||||
ctx.SleepClientThread(
|
||||
"IHOSBinderDriver::DequeueBuffer", UINT64_MAX,
|
||||
[=, this](std::shared_ptr<Kernel::Thread> thread,
|
||||
Kernel::HLERequestContext& ctx, Kernel::ThreadWakeupReason reason) {
|
||||
// Repeat TransactParcel DequeueBuffer when a buffer is available
|
||||
const auto guard = nv_flinger.Lock();
|
||||
auto& buffer_queue = nv_flinger.FindBufferQueue(id);
|
||||
auto result = buffer_queue.DequeueBuffer(width, height);
|
||||
ASSERT_MSG(result != std::nullopt, "Could not dequeue buffer.");
|
||||
do {
|
||||
if (auto result = buffer_queue.DequeueBuffer(width, height); result) {
|
||||
// Buffer is available
|
||||
IGBPDequeueBufferResponseParcel response{result->first, *result->second};
|
||||
ctx.WriteBuffer(response.Serialize());
|
||||
break;
|
||||
}
|
||||
} while (buffer_queue.IsConnected());
|
||||
|
||||
IGBPDequeueBufferResponseParcel response{result->first, *result->second};
|
||||
ctx.WriteBuffer(response.Serialize());
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
},
|
||||
buffer_queue.GetWritableBufferWaitEvent());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TransactionId::RequestBuffer: {
|
||||
IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()};
|
||||
|
||||
auto& buffer = buffer_queue.RequestBuffer(request.slot);
|
||||
|
||||
IGBPRequestBufferResponseParcel response{buffer};
|
||||
ctx.WriteBuffer(response.Serialize());
|
||||
|
||||
break;
|
||||
}
|
||||
case TransactionId::QueueBuffer: {
|
||||
|
@ -682,7 +669,7 @@ private:
|
|||
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown);
|
||||
|
||||
const auto& buffer_queue = nv_flinger.FindBufferQueue(id);
|
||||
const auto& buffer_queue = *nv_flinger.FindBufferQueue(id);
|
||||
|
||||
// TODO(Subv): Find out what this actually is.
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue