summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp51
-rw-r--r--src/core/hle/kernel/hle_ipc.h2
-rw-r--r--src/core/hle/kernel/server_session.cpp97
-rw-r--r--src/core/hle/kernel/server_session.h14
-rw-r--r--src/core/hle/kernel/thread.cpp1
-rw-r--r--src/core/hle/kernel/thread.h1
-rw-r--r--src/core/hle/service/audio/audren_u.cpp3
-rw-r--r--src/core/hle/service/hid/hid.cpp43
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp14
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.h11
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp7
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h7
-rw-r--r--src/core/hle/service/vi/vi.cpp57
13 files changed, 229 insertions, 79 deletions
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 6d16f71a7..25ba26f18 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -254,4 +254,55 @@ size_t HLERequestContext::GetWriteBufferSize() const {
return is_buffer_b ? BufferDescriptorB()[0].Size() : BufferDescriptorC()[0].Size();
}
+std::string HLERequestContext::Description() const {
+ if (!command_header) {
+ return "No command header available";
+ }
+ std::ostringstream s;
+ s << "IPC::CommandHeader: Type:" << static_cast<u32>(command_header->type.Value());
+ s << ", X(Pointer):" << command_header->num_buf_x_descriptors;
+ if (command_header->num_buf_x_descriptors) {
+ s << '[';
+ for (u64 i = 0; i < command_header->num_buf_x_descriptors; ++i) {
+ s << "0x" << std::hex << BufferDescriptorX()[i].Size();
+ if (i < command_header->num_buf_x_descriptors - 1)
+ s << ", ";
+ }
+ s << ']';
+ }
+ s << ", A(Send):" << command_header->num_buf_a_descriptors;
+ if (command_header->num_buf_a_descriptors) {
+ s << '[';
+ for (u64 i = 0; i < command_header->num_buf_a_descriptors; ++i) {
+ s << "0x" << std::hex << BufferDescriptorA()[i].Size();
+ if (i < command_header->num_buf_a_descriptors - 1)
+ s << ", ";
+ }
+ s << ']';
+ }
+ s << ", B(Receive):" << command_header->num_buf_b_descriptors;
+ if (command_header->num_buf_b_descriptors) {
+ s << '[';
+ for (u64 i = 0; i < command_header->num_buf_b_descriptors; ++i) {
+ s << "0x" << std::hex << BufferDescriptorB()[i].Size();
+ if (i < command_header->num_buf_b_descriptors - 1)
+ s << ", ";
+ }
+ s << ']';
+ }
+ s << ", C(ReceiveList):" << BufferDescriptorC().size();
+ if (!BufferDescriptorC().empty()) {
+ s << '[';
+ for (u64 i = 0; i < BufferDescriptorC().size(); ++i) {
+ s << "0x" << std::hex << BufferDescriptorC()[i].Size();
+ if (i < BufferDescriptorC().size() - 1)
+ s << ", ";
+ }
+ s << ']';
+ }
+ s << ", data_size:" << command_header->data_size.Value();
+
+ return s.str();
+}
+
} // namespace Kernel
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 81e3489c8..b5631b773 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -202,6 +202,8 @@ public:
return domain_objects.size();
}
+ std::string Description() const;
+
private:
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
SharedPtr<Kernel::ServerSession> server_session;
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 54481f7f1..5608418c3 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -57,6 +57,33 @@ void ServerSession::Acquire(Thread* thread) {
pending_requesting_threads.pop_back();
}
+ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) {
+ auto& domain_message_header = context.GetDomainMessageHeader();
+ if (domain_message_header) {
+ // If there is a DomainMessageHeader, then this is CommandType "Request"
+ const u32 object_id{context.GetDomainMessageHeader()->object_id};
+ switch (domain_message_header->command) {
+ case IPC::DomainMessageHeader::CommandType::SendMessage:
+ return domain_request_handlers[object_id - 1]->HandleSyncRequest(context);
+
+ case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: {
+ LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x%08X", object_id);
+
+ domain_request_handlers[object_id - 1] = nullptr;
+
+ IPC::ResponseBuilder rb{context, 2};
+ rb.Push(RESULT_SUCCESS);
+ return RESULT_SUCCESS;
+ }
+ }
+
+ LOG_CRITICAL(IPC, "Unknown domain command=%d", domain_message_header->command.Value());
+ ASSERT(false);
+ }
+
+ return RESULT_SUCCESS;
+}
+
ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
// The ServerSession received a sync request, this means that there's new data available
// from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or
@@ -67,46 +94,39 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process,
Kernel::g_handle_table);
- // If the session has been converted to a domain, handle the doomain request
+ ResultCode result = RESULT_SUCCESS;
+ // If the session has been converted to a domain, handle the domain request
if (IsDomain()) {
- auto& domain_message_header = context.GetDomainMessageHeader();
- if (domain_message_header) {
- // If there is a DomainMessageHeader, then this is CommandType "Request"
- const u32 object_id{context.GetDomainMessageHeader()->object_id};
- switch (domain_message_header->command) {
- case IPC::DomainMessageHeader::CommandType::SendMessage:
- return domain_request_handlers[object_id - 1]->HandleSyncRequest(context);
-
- case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: {
- LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x%08X", object_id);
-
- domain_request_handlers[object_id - 1] = nullptr;
-
- IPC::ResponseBuilder rb{context, 2};
- rb.Push(RESULT_SUCCESS);
- return RESULT_SUCCESS;
- }
- }
-
- LOG_CRITICAL(IPC, "Unknown domain command=%d", domain_message_header->command.Value());
- ASSERT(false);
- }
+ result = HandleDomainSyncRequest(context);
// If there is no domain header, the regular session handler is used
+ } else if (hle_handler != nullptr) {
+ // If this ServerSession has an associated HLE handler, forward the request to it.
+ result = hle_handler->HandleSyncRequest(context);
}
- // If this ServerSession has an associated HLE handler, forward the request to it.
- ResultCode result{RESULT_SUCCESS};
- if (hle_handler != nullptr) {
- // Attempt to translate the incoming request's command buffer.
- ResultCode translate_result = TranslateHLERequest(this);
- if (translate_result.IsError())
- return translate_result;
-
- result = hle_handler->HandleSyncRequest(context);
- } else {
- // Add the thread to the list of threads that have issued a sync request with this
- // server.
- pending_requesting_threads.push_back(std::move(thread));
+ if (thread->status == THREADSTATUS_RUNNING) {
+ // Put the thread to sleep until the server replies, it will be awoken in
+ // svcReplyAndReceive for LLE servers.
+ thread->status = THREADSTATUS_WAIT_IPC;
+
+ if (hle_handler != nullptr) {
+ // For HLE services, we put the request threads to sleep for a short duration to
+ // simulate IPC overhead, but only if the HLE handler didn't put the thread to sleep for
+ // other reasons like an async callback. The IPC overhead is needed to prevent
+ // starvation when a thread only does sync requests to HLE services while a
+ // lower-priority thread is waiting to run.
+
+ // This delay was approximated in a homebrew application by measuring the average time
+ // it takes for svcSendSyncRequest to return when performing the SetLcdForceBlack IPC
+ // request to the GSP:GPU service in a n3DS with firmware 11.6. The measured values have
+ // a high variance and vary between models.
+ static constexpr u64 IPCDelayNanoseconds = 39000;
+ thread->WakeAfterDelay(IPCDelayNanoseconds);
+ } else {
+ // Add the thread to the list of threads that have issued a sync request with this
+ // server.
+ pending_requesting_threads.push_back(std::move(thread));
+ }
}
// If this ServerSession does not have an HLE implementation, just wake up the threads waiting
@@ -140,9 +160,4 @@ ServerSession::SessionPair ServerSession::CreateSessionPair(const std::string& n
return std::make_tuple(std::move(server_session), std::move(client_session));
}
-
-ResultCode TranslateHLERequest(ServerSession* server_session) {
- // TODO(Subv): Implement this function once multiple concurrent processes are supported.
- return RESULT_SUCCESS;
-}
} // namespace Kernel
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index 144692106..2da807042 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -21,6 +21,7 @@ class ServerSession;
class Session;
class SessionRequestHandler;
class Thread;
+class HLERequestContext;
/**
* Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS
@@ -116,17 +117,12 @@ private:
*/
static ResultVal<SharedPtr<ServerSession>> Create(std::string name = "Unknown");
+ /// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an
+ /// object handle.
+ ResultCode HandleDomainSyncRequest(Kernel::HLERequestContext& context);
+
/// When set to True, converts the session to a domain at the end of the command
bool convert_to_domain{};
};
-/**
- * Performs command buffer translation for an HLE IPC request.
- * The command buffer from the ServerSession thread's TLS is copied into a
- * buffer and all descriptors in the buffer are processed.
- * TODO(Subv): Implement this function, currently we do not support multiple processes running at
- * once, but once that is implemented we'll need to properly translate all descriptors
- * in the command buffer.
- */
-ResultCode TranslateHLERequest(ServerSession* server_session);
} // namespace Kernel
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 1a33cc6cb..130b669a0 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -284,6 +284,7 @@ void Thread::ResumeFromWait() {
case THREADSTATUS_WAIT_SYNCH_ANY:
case THREADSTATUS_WAIT_ARB:
case THREADSTATUS_WAIT_SLEEP:
+ case THREADSTATUS_WAIT_IPC:
break;
case THREADSTATUS_READY:
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 0a1ada27d..bbffaf4cf 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -40,6 +40,7 @@ enum ThreadStatus {
THREADSTATUS_READY, ///< Ready to run
THREADSTATUS_WAIT_ARB, ///< Waiting on an address arbiter
THREADSTATUS_WAIT_SLEEP, ///< Waiting due to a SleepThread SVC
+ THREADSTATUS_WAIT_IPC, ///< Waiting for the reply from an IPC request
THREADSTATUS_WAIT_SYNCH_ANY, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false
THREADSTATUS_WAIT_SYNCH_ALL, ///< Waiting due to WaitSynchronizationN with wait_all = true
THREADSTATUS_DORMANT, ///< Created but not yet made ready
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 20306c6cf..4efc789ac 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -53,7 +53,8 @@ private:
}
void RequestUpdateAudioRenderer(Kernel::HLERequestContext& ctx) {
- AudioRendererResponseData response_data = {0};
+ LOG_DEBUG(Service_Audio, "%s", ctx.Description().c_str());
+ AudioRendererResponseData response_data{};
response_data.section_0_size =
response_data.state_entries.size() * sizeof(AudioRendererStateEntry);
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 3f1c18505..dacd1862d 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -176,7 +176,10 @@ public:
{0, &Hid::CreateAppletResource, "CreateAppletResource"},
{1, &Hid::ActivateDebugPad, "ActivateDebugPad"},
{11, &Hid::ActivateTouchScreen, "ActivateTouchScreen"},
+ {21, &Hid::ActivateMouse, "ActivateMouse"},
+ {31, &Hid::ActivateKeyboard, "ActivateKeyboard"},
{66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"},
+ {79, &Hid::SetGyroscopeZeroDriftMode, "SetGyroscopeZeroDriftMode"},
{100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"},
{102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"},
{103, &Hid::ActivateNpad, "ActivateNpad"},
@@ -184,9 +187,13 @@ public:
"AcquireNpadStyleSetUpdateEventHandle"},
{120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"},
{121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"},
+ {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault,
+ "SetNpadJoyAssignmentModeSingleByDefault"},
{124, nullptr, "SetNpadJoyAssignmentModeDual"},
{128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"},
{200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"},
+ {201, &Hid::SendVibrationValue, "SendVibrationValue"},
+ {202, &Hid::GetActualVibrationValue, "GetActualVibrationValue"},
{203, &Hid::CreateActiveVibrationDeviceList, "CreateActiveVibrationDeviceList"},
{206, &Hid::SendVibrationValues, "SendVibrationValues"},
};
@@ -224,12 +231,30 @@ private:
LOG_WARNING(Service_HID, "(STUBBED) called");
}
+ void ActivateMouse(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+ }
+
+ void ActivateKeyboard(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+ }
+
void StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service_HID, "(STUBBED) called");
}
+ void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+ }
+
void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -268,6 +293,24 @@ private:
LOG_WARNING(Service_HID, "(STUBBED) called");
}
+ void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+ }
+
+ void SendVibrationValue(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+ }
+
+ void GetActualVibrationValue(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+ }
+
void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index ee99ab280..45711d686 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -17,6 +17,8 @@ u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<
switch (static_cast<IoctlCommand>(command.raw)) {
case IoctlCommand::IocGetConfigCommand:
return NvOsGetConfigU32(input, output);
+ case IoctlCommand::IocCtrlEventWaitCommand:
+ return IocCtrlEventWait(input, output);
}
UNIMPLEMENTED();
return 0;
@@ -45,6 +47,18 @@ u32 nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>&
return 0;
}
+u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output) {
+ IocCtrlEventWaitParams params{};
+ std::memcpy(&params, input.data(), sizeof(params));
+ LOG_WARNING(Service_NVDRV, "(STUBBED) called, syncpt_id=%u threshold=%u timeout=%d",
+ params.syncpt_id, params.threshold, params.timeout);
+
+ // TODO(Subv): Implement actual syncpt waiting.
+ params.value = 0;
+ std::memcpy(output.data(), &params, sizeof(params));
+ return 0;
+}
+
} // namespace Devices
} // namespace Nvidia
} // namespace Service
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
index fd02a5e45..0ca01aa6d 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
@@ -31,6 +31,7 @@ private:
IocModuleRegRDWRCommand = 0xC008010E,
IocSyncptWaitexCommand = 0xC0100019,
IocSyncptReadMaxCommand = 0xC008001A,
+ IocCtrlEventWaitCommand = 0xC010001D,
IocGetConfigCommand = 0xC183001B,
};
@@ -41,7 +42,17 @@ private:
};
static_assert(sizeof(IocGetConfigParams) == 387, "IocGetConfigParams is incorrect size");
+ struct IocCtrlEventWaitParams {
+ u32_le syncpt_id;
+ u32_le threshold;
+ s32_le timeout;
+ u32_le value;
+ };
+ static_assert(sizeof(IocCtrlEventWaitParams) == 16, "IocCtrlEventWaitParams is incorrect size");
+
u32 NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output);
+
+ u32 IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output);
};
} // namespace Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
index cd8c0c605..b3842eb4c 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -103,11 +103,8 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
[&](const auto& entry) { return entry.second->id == params.id; });
ASSERT(itr != handles.end());
- // Make a new handle for the object
- u32 handle = next_handle++;
- handles[handle] = itr->second;
-
- params.handle = handle;
+ // Return the existing handle instead of creating a new one.
+ params.handle = itr->first;
std::memcpy(output.data(), &params, sizeof(params));
return 0;
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h
index e44644624..6a55ff96d 100644
--- a/src/core/hle/service/nvdrv/nvdrv.h
+++ b/src/core/hle/service/nvdrv/nvdrv.h
@@ -17,6 +17,13 @@ namespace Devices {
class nvdevice;
}
+struct IoctlFence {
+ u32 id;
+ u32 value;
+};
+
+static_assert(sizeof(IoctlFence) == 8, "IoctlFence has wrong size");
+
class Module final {
public:
Module();
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index ff5005f71..0aa621dfe 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -8,6 +8,7 @@
#include "common/scope_exit.h"
#include "core/core_timing.h"
#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/nvflinger/buffer_queue.h"
#include "core/hle/service/vi/vi.h"
#include "core/hle/service/vi/vi_m.h"
@@ -38,6 +39,7 @@ public:
template <typename T>
T Read() {
+ ASSERT(read_index + sizeof(T) <= buffer.size());
T val;
std::memcpy(&val, buffer.data() + read_index, sizeof(T));
read_index += sizeof(T);
@@ -47,6 +49,7 @@ public:
template <typename T>
T ReadUnaligned() {
+ ASSERT(read_index + sizeof(T) <= buffer.size());
T val;
std::memcpy(&val, buffer.data() + read_index, sizeof(T));
read_index += sizeof(T);
@@ -54,6 +57,7 @@ public:
}
std::vector<u8> ReadBlock(size_t length) {
+ ASSERT(read_index + length <= buffer.size());
const u8* const begin = buffer.data() + read_index;
const u8* const end = begin + length;
std::vector<u8> data(begin, end);
@@ -86,7 +90,18 @@ public:
write_index = Common::AlignUp(write_index, 4);
}
+ template <typename T>
+ void WriteObject(const T& val) {
+ u32_le size = static_cast<u32>(sizeof(val));
+ Write(size);
+ // TODO(Subv): Support file descriptors.
+ Write<u32_le>(0); // Fd count.
+ Write(val);
+ }
+
void Deserialize() {
+ ASSERT(buffer.size() > sizeof(Header));
+
Header header{};
std::memcpy(&header, buffer.data(), sizeof(Header));
@@ -262,10 +277,11 @@ public:
Data data;
};
-// TODO(bunnei): Remove this. When set to 1, games will think a fence is valid and boot further.
-// This will break libnx and potentially other apps that more stringently check this. This is here
-// purely as a convenience, and should go away once we implement fences.
-static constexpr u32 FENCE_HACK = 0;
+struct BufferProducerFence {
+ u32 is_valid;
+ std::array<Nvidia::IoctlFence, 4> fences;
+};
+static_assert(sizeof(BufferProducerFence) == 36, "BufferProducerFence has wrong size");
class IGBPDequeueBufferResponseParcel : public Parcel {
public:
@@ -274,20 +290,16 @@ public:
protected:
void SerializeData() override {
- // TODO(bunnei): Find out what this all means. Writing anything non-zero here breaks libnx.
- Write<u32>(0);
- Write<u32>(FENCE_HACK);
- Write<u32>(0);
- Write<u32>(0);
- Write<u32>(0);
- Write<u32>(0);
- Write<u32>(0);
- Write<u32>(0);
- Write<u32>(0);
- Write<u32>(0);
- Write<u32>(0);
- Write<u32>(0);
- Write<u32>(0);
+ // TODO(Subv): Find out how this Fence is used.
+ BufferProducerFence fence = {};
+ fence.is_valid = 1;
+ for (auto& fence_ : fence.fences)
+ fence_.id = -1;
+
+ Write(slot);
+ Write<u32_le>(1);
+ WriteObject(fence);
+ Write<u32_le>(0);
}
u32_le slot;
@@ -316,11 +328,10 @@ public:
protected:
void SerializeData() override {
- // TODO(bunnei): Find out what this all means. Writing anything non-zero here breaks libnx.
- Write<u32_le>(0);
- Write<u32_le>(FENCE_HACK);
- Write<u32_le>(0);
- Write(buffer);
+ // TODO(Subv): Figure out what this value means, writing non-zero here will make libnx try
+ // to read an IGBPBuffer object from the parcel.
+ Write<u32_le>(1);
+ WriteObject(buffer);
Write<u32_le>(0);
}