Compare commits
27 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
deadcb39c2 | ||
|
|
6fce1414c3 | ||
|
|
068744db1b | ||
|
|
b26cdf1fe5 | ||
|
|
8e7da73214 | ||
|
|
0532de6559 | ||
|
|
c83a1b2320 | ||
|
|
725304094e | ||
|
|
63de56ee0f | ||
|
|
309276a317 | ||
|
|
1add3b20c4 | ||
|
|
3b35202280 | ||
|
|
45e5a67676 | ||
|
|
22caeee64f | ||
|
|
576f0cf027 | ||
|
|
ca99063600 | ||
|
|
205daab50d | ||
|
|
d3bbed5e78 | ||
|
|
dc0a137e5b | ||
|
|
db11c9a0b9 | ||
|
|
a39a65cbe0 | ||
|
|
c711253798 | ||
|
|
196f8dff08 | ||
|
|
703880c9ab | ||
|
|
869d65e923 | ||
|
|
335096e19a | ||
|
|
2b75b52489 |
@@ -2,7 +2,7 @@
|
||||
|
||||
set -o pipefail
|
||||
|
||||
export MACOSX_DEPLOYMENT_TARGET=10.9
|
||||
export MACOSX_DEPLOYMENT_TARGET=10.12
|
||||
export Qt5_DIR=$(brew --prefix)/opt/qt5
|
||||
export UNICORNDIR=$(pwd)/externals/unicorn
|
||||
|
||||
|
||||
2
externals/dynarmic
vendored
2
externals/dynarmic
vendored
Submodule externals/dynarmic updated: a6d17e6bb0...406c071008
2
externals/xbyak
vendored
2
externals/xbyak
vendored
Submodule externals/xbyak updated: d512551e91...2794cde79e
@@ -92,6 +92,8 @@ add_library(core STATIC
|
||||
hle/service/aoc/aoc_u.h
|
||||
hle/service/apm/apm.cpp
|
||||
hle/service/apm/apm.h
|
||||
hle/service/apm/interface.cpp
|
||||
hle/service/apm/interface.h
|
||||
hle/service/audio/audio.cpp
|
||||
hle/service/audio/audio.h
|
||||
hle/service/audio/audin_u.cpp
|
||||
@@ -137,6 +139,8 @@ add_library(core STATIC
|
||||
hle/service/nvdrv/devices/nvmap.h
|
||||
hle/service/nvdrv/interface.cpp
|
||||
hle/service/nvdrv/interface.h
|
||||
hle/service/nvdrv/memory_manager.cpp
|
||||
hle/service/nvdrv/memory_manager.h
|
||||
hle/service/nvdrv/nvdrv.cpp
|
||||
hle/service/nvdrv/nvdrv.h
|
||||
hle/service/nvdrv/nvmemp.cpp
|
||||
|
||||
@@ -8,9 +8,12 @@
|
||||
#include <dynarmic/A64/config.h>
|
||||
#include "core/arm/dynarmic/arm_dynarmic.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/kernel/memory.h"
|
||||
#include "core/hle/kernel/svc.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
using Vector = Dynarmic::A64::Vector;
|
||||
|
||||
class ARM_Dynarmic_Callbacks : public Dynarmic::A64::UserCallbacks {
|
||||
public:
|
||||
explicit ARM_Dynarmic_Callbacks(ARM_Dynarmic& parent) : parent(parent) {}
|
||||
@@ -28,6 +31,9 @@ public:
|
||||
u64 MemoryRead64(u64 vaddr) override {
|
||||
return Memory::Read64(vaddr);
|
||||
}
|
||||
Vector MemoryRead128(u64 vaddr) override {
|
||||
return {Memory::Read64(vaddr), Memory::Read64(vaddr + 8)};
|
||||
}
|
||||
|
||||
void MemoryWrite8(u64 vaddr, u8 value) override {
|
||||
Memory::Write8(vaddr, value);
|
||||
@@ -41,6 +47,10 @@ public:
|
||||
void MemoryWrite64(u64 vaddr, u64 value) override {
|
||||
Memory::Write64(vaddr, value);
|
||||
}
|
||||
void MemoryWrite128(u64 vaddr, Vector value) override {
|
||||
Memory::Write64(vaddr, value[0]);
|
||||
Memory::Write64(vaddr + 8, value[1]);
|
||||
}
|
||||
|
||||
void InterpreterFallback(u64 pc, size_t num_instructions) override {
|
||||
ARM_Interface::ThreadContext ctx;
|
||||
@@ -52,12 +62,12 @@ public:
|
||||
num_interpreted_instructions += num_instructions;
|
||||
}
|
||||
|
||||
void ExceptionRaised(u64 pc, Dynarmic::A64::Exception /*exception*/) override {
|
||||
ASSERT_MSG(false, "ExceptionRaised(%" PRIx64 ")", pc);
|
||||
void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override {
|
||||
ASSERT_MSG(false, "ExceptionRaised(exception = %zu, pc = %" PRIx64 ")",
|
||||
static_cast<size_t>(exception), pc);
|
||||
}
|
||||
|
||||
void CallSVC(u32 swi) override {
|
||||
printf("svc %x\n", swi);
|
||||
Kernel::CallSVC(swi);
|
||||
}
|
||||
|
||||
@@ -78,9 +88,13 @@ public:
|
||||
u64 tpidrr0_el0 = 0;
|
||||
};
|
||||
|
||||
std::unique_ptr<Dynarmic::A64::Jit> MakeJit(const std::unique_ptr<ARM_Dynarmic_Callbacks>& cb) {
|
||||
Dynarmic::A64::UserConfig config{cb.get()};
|
||||
return std::make_unique<Dynarmic::A64::Jit>(config);
|
||||
}
|
||||
|
||||
ARM_Dynarmic::ARM_Dynarmic()
|
||||
: cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)),
|
||||
jit(Dynarmic::A64::UserConfig{cb.get()}) {
|
||||
: cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), jit(MakeJit(cb)) {
|
||||
ARM_Interface::ThreadContext ctx;
|
||||
inner_unicorn.SaveContext(ctx);
|
||||
LoadContext(ctx);
|
||||
@@ -94,27 +108,27 @@ void ARM_Dynarmic::MapBackingMemory(u64 address, size_t size, u8* memory,
|
||||
}
|
||||
|
||||
void ARM_Dynarmic::SetPC(u64 pc) {
|
||||
jit.SetPC(pc);
|
||||
jit->SetPC(pc);
|
||||
}
|
||||
|
||||
u64 ARM_Dynarmic::GetPC() const {
|
||||
return jit.GetPC();
|
||||
return jit->GetPC();
|
||||
}
|
||||
|
||||
u64 ARM_Dynarmic::GetReg(int index) const {
|
||||
return jit.GetRegister(index);
|
||||
return jit->GetRegister(index);
|
||||
}
|
||||
|
||||
void ARM_Dynarmic::SetReg(int index, u64 value) {
|
||||
jit.SetRegister(index, value);
|
||||
jit->SetRegister(index, value);
|
||||
}
|
||||
|
||||
u128 ARM_Dynarmic::GetExtReg(int index) const {
|
||||
return jit.GetVector(index);
|
||||
return jit->GetVector(index);
|
||||
}
|
||||
|
||||
void ARM_Dynarmic::SetExtReg(int index, u128 value) {
|
||||
jit.SetVector(index, value);
|
||||
jit->SetVector(index, value);
|
||||
}
|
||||
|
||||
u32 ARM_Dynarmic::GetVFPReg(int /*index*/) const {
|
||||
@@ -127,11 +141,11 @@ void ARM_Dynarmic::SetVFPReg(int /*index*/, u32 /*value*/) {
|
||||
}
|
||||
|
||||
u32 ARM_Dynarmic::GetCPSR() const {
|
||||
return jit.GetPstate();
|
||||
return jit->GetPstate();
|
||||
}
|
||||
|
||||
void ARM_Dynarmic::SetCPSR(u32 cpsr) {
|
||||
jit.SetPstate(cpsr);
|
||||
jit->SetPstate(cpsr);
|
||||
}
|
||||
|
||||
u64 ARM_Dynarmic::GetTlsAddress() const {
|
||||
@@ -144,41 +158,41 @@ void ARM_Dynarmic::SetTlsAddress(u64 address) {
|
||||
|
||||
void ARM_Dynarmic::ExecuteInstructions(int num_instructions) {
|
||||
cb->ticks_remaining = num_instructions;
|
||||
jit.Run();
|
||||
jit->Run();
|
||||
CoreTiming::AddTicks(num_instructions - cb->num_interpreted_instructions);
|
||||
cb->num_interpreted_instructions = 0;
|
||||
}
|
||||
|
||||
void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& ctx) {
|
||||
ctx.cpu_registers = jit.GetRegisters();
|
||||
ctx.sp = jit.GetSP();
|
||||
ctx.pc = jit.GetPC();
|
||||
ctx.cpsr = jit.GetPstate();
|
||||
ctx.fpu_registers = jit.GetVectors();
|
||||
ctx.fpscr = jit.GetFpcr();
|
||||
ctx.cpu_registers = jit->GetRegisters();
|
||||
ctx.sp = jit->GetSP();
|
||||
ctx.pc = jit->GetPC();
|
||||
ctx.cpsr = jit->GetPstate();
|
||||
ctx.fpu_registers = jit->GetVectors();
|
||||
ctx.fpscr = jit->GetFpcr();
|
||||
ctx.tls_address = cb->tpidrr0_el0;
|
||||
}
|
||||
|
||||
void ARM_Dynarmic::LoadContext(const ARM_Interface::ThreadContext& ctx) {
|
||||
jit.SetRegisters(ctx.cpu_registers);
|
||||
jit.SetSP(ctx.sp);
|
||||
jit.SetPC(ctx.pc);
|
||||
jit.SetPstate(static_cast<u32>(ctx.cpsr));
|
||||
jit.SetVectors(ctx.fpu_registers);
|
||||
jit.SetFpcr(static_cast<u32>(ctx.fpscr));
|
||||
jit->SetRegisters(ctx.cpu_registers);
|
||||
jit->SetSP(ctx.sp);
|
||||
jit->SetPC(ctx.pc);
|
||||
jit->SetPstate(static_cast<u32>(ctx.cpsr));
|
||||
jit->SetVectors(ctx.fpu_registers);
|
||||
jit->SetFpcr(static_cast<u32>(ctx.fpscr));
|
||||
cb->tpidrr0_el0 = ctx.tls_address;
|
||||
}
|
||||
|
||||
void ARM_Dynarmic::PrepareReschedule() {
|
||||
if (jit.IsExecuting()) {
|
||||
jit.HaltExecution();
|
||||
if (jit->IsExecuting()) {
|
||||
jit->HaltExecution();
|
||||
}
|
||||
}
|
||||
|
||||
void ARM_Dynarmic::ClearInstructionCache() {
|
||||
jit.ClearCache();
|
||||
jit->ClearCache();
|
||||
}
|
||||
|
||||
void ARM_Dynarmic::PageTableChanged() {
|
||||
UNIMPLEMENTED();
|
||||
jit = MakeJit(cb);
|
||||
}
|
||||
|
||||
@@ -45,6 +45,6 @@ public:
|
||||
private:
|
||||
friend class ARM_Dynarmic_Callbacks;
|
||||
std::unique_ptr<ARM_Dynarmic_Callbacks> cb;
|
||||
Dynarmic::A64::Jit jit;
|
||||
std::unique_ptr<Dynarmic::A64::Jit> jit;
|
||||
ARM_Unicorn inner_unicorn;
|
||||
};
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
namespace Service {
|
||||
namespace Account {
|
||||
|
||||
using Uid = std::array<u64, 2>;
|
||||
static constexpr Uid DEFAULT_USER_ID{0x10ull, 0x20ull};
|
||||
|
||||
class IProfile final : public ServiceFramework<IProfile> {
|
||||
public:
|
||||
IProfile() : ServiceFramework("IProfile") {
|
||||
@@ -61,6 +64,15 @@ void ACC_U0::GetUserExistence(Kernel::HLERequestContext& ctx) {
|
||||
rb.Push(true); // TODO: Check when this is supposed to return true and when not
|
||||
}
|
||||
|
||||
void ACC_U0::ListAllUsers(Kernel::HLERequestContext& ctx) {
|
||||
constexpr std::array<u128, 10> user_ids{DEFAULT_USER_ID};
|
||||
const auto& output_buffer = ctx.BufferDescriptorC()[0];
|
||||
Memory::WriteBlock(output_buffer.Address(), user_ids.data(), user_ids.size());
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_ACC, "called");
|
||||
}
|
||||
|
||||
void ACC_U0::GetProfile(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -85,13 +97,13 @@ void ACC_U0::GetLastOpenedUser(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u64>(0x0);
|
||||
rb.Push<u64>(0x0);
|
||||
rb.PushRaw(DEFAULT_USER_ID);
|
||||
}
|
||||
|
||||
ACC_U0::ACC_U0() : ServiceFramework("acc:u0") {
|
||||
static const FunctionInfo functions[] = {
|
||||
{1, &ACC_U0::GetUserExistence, "GetUserExistence"},
|
||||
{2, &ACC_U0::ListAllUsers, "ListAllUsers"},
|
||||
{4, &ACC_U0::GetLastOpenedUser, "GetLastOpenedUser"},
|
||||
{5, &ACC_U0::GetProfile, "GetProfile"},
|
||||
{100, &ACC_U0::InitializeApplicationInfo, "InitializeApplicationInfo"},
|
||||
|
||||
@@ -28,6 +28,7 @@ public:
|
||||
|
||||
private:
|
||||
void GetUserExistence(Kernel::HLERequestContext& ctx);
|
||||
void ListAllUsers(Kernel::HLERequestContext& ctx);
|
||||
void GetLastOpenedUser(Kernel::HLERequestContext& ctx);
|
||||
void GetProfile(Kernel::HLERequestContext& ctx);
|
||||
void InitializeApplicationInfo(Kernel::HLERequestContext& ctx);
|
||||
|
||||
@@ -45,6 +45,7 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
|
||||
static const FunctionInfo functions[] = {
|
||||
{1, &ISelfController::LockExit, "LockExit"},
|
||||
{2, &ISelfController::UnlockExit, "UnlockExit"},
|
||||
{9, &ISelfController::GetLibraryAppletLaunchableEvent, "GetLibraryAppletLaunchableEvent"},
|
||||
{11, &ISelfController::SetOperationModeChangedNotification,
|
||||
"SetOperationModeChangedNotification"},
|
||||
{12, &ISelfController::SetPerformanceModeChangedNotification,
|
||||
@@ -55,6 +56,9 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
|
||||
{40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
|
||||
launchable_event =
|
||||
Kernel::Event::Create(Kernel::ResetType::OneShot, "ISelfController:LaunchableEvent");
|
||||
}
|
||||
|
||||
void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) {
|
||||
@@ -132,6 +136,16 @@ void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) {
|
||||
launchable_event->Signal();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(launchable_event);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) {
|
||||
// TODO(Subv): Find out how AM determines the display to use, for now just create the layer
|
||||
// in the Default display.
|
||||
@@ -200,7 +214,69 @@ void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryAppletCreator") {}
|
||||
class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {
|
||||
public:
|
||||
explicit ILibraryAppletAccessor() : ServiceFramework("ILibraryAppletAccessor") {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"},
|
||||
{1, nullptr, "IsCompleted"},
|
||||
{10, nullptr, "Start"},
|
||||
{20, nullptr, "RequestExit"},
|
||||
{25, nullptr, "Terminate"},
|
||||
{30, nullptr, "GetResult"},
|
||||
{50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"},
|
||||
{100, nullptr, "PushInData"},
|
||||
{101, nullptr, "PopOutData"},
|
||||
{102, nullptr, "PushExtraStorage"},
|
||||
{103, nullptr, "PushInteractiveInData"},
|
||||
{104, nullptr, "PopInteractiveOutData"},
|
||||
{105, nullptr, "GetPopOutDataEvent"},
|
||||
{106, nullptr, "GetPopInteractiveOutDataEvent"},
|
||||
{120, nullptr, "NeedsToExitProcess"},
|
||||
{120, nullptr, "GetLibraryAppletInfo"},
|
||||
{150, nullptr, "RequestForAppletToGetForeground"},
|
||||
{160, nullptr, "GetIndirectLayerConsumerHandle"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
|
||||
state_changed_event = Kernel::Event::Create(Kernel::ResetType::OneShot,
|
||||
"ILibraryAppletAccessor:StateChangedEvent");
|
||||
}
|
||||
|
||||
private:
|
||||
void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) {
|
||||
state_changed_event->Signal();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(state_changed_event);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
Kernel::SharedPtr<Kernel::Event> state_changed_event;
|
||||
};
|
||||
|
||||
ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryAppletCreator") {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"},
|
||||
{1, nullptr, "TerminateAllLibraryApplets"},
|
||||
{2, nullptr, "AreAnyLibraryAppletsLeft"},
|
||||
{10, nullptr, "CreateStorage"},
|
||||
{11, nullptr, "CreateTransferMemoryStorage"},
|
||||
{12, nullptr, "CreateHandleStorage"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<AM::ILibraryAppletAccessor>();
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
|
||||
public:
|
||||
|
||||
@@ -60,9 +60,11 @@ private:
|
||||
void SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx);
|
||||
void LockExit(Kernel::HLERequestContext& ctx);
|
||||
void UnlockExit(Kernel::HLERequestContext& ctx);
|
||||
void GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx);
|
||||
void CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
|
||||
Kernel::SharedPtr<Kernel::Event> launchable_event;
|
||||
};
|
||||
|
||||
class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
|
||||
@@ -92,6 +94,9 @@ private:
|
||||
class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
|
||||
public:
|
||||
ILibraryAppletCreator();
|
||||
|
||||
private:
|
||||
void CreateLibraryApplet(Kernel::HLERequestContext& ctx);
|
||||
};
|
||||
|
||||
class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
|
||||
|
||||
@@ -5,63 +5,15 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/service/apm/apm.h"
|
||||
#include "core/hle/service/apm/interface.h"
|
||||
|
||||
namespace Service {
|
||||
namespace APM {
|
||||
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager) {
|
||||
std::make_shared<APM>()->InstallAsService(service_manager);
|
||||
}
|
||||
|
||||
class ISession final : public ServiceFramework<ISession> {
|
||||
public:
|
||||
ISession() : ServiceFramework("ISession") {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ISession::SetPerformanceConfiguration, "SetPerformanceConfiguration"},
|
||||
{1, &ISession::GetPerformanceConfiguration, "GetPerformanceConfiguration"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
private:
|
||||
void SetPerformanceConfiguration(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
auto mode = static_cast<PerformanceMode>(rp.Pop<u32>());
|
||||
u32 config = rp.Pop<u32>();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_APM, "(STUBBED) called mode=%u config=%u", static_cast<u32>(mode),
|
||||
config);
|
||||
}
|
||||
|
||||
void GetPerformanceConfiguration(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
auto mode = static_cast<PerformanceMode>(rp.Pop<u32>());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(0); // Performance configuration
|
||||
|
||||
LOG_WARNING(Service_APM, "(STUBBED) called mode=%u", static_cast<u32>(mode));
|
||||
}
|
||||
};
|
||||
|
||||
APM::APM() : ServiceFramework("apm") {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0x00000000, &APM::OpenSession, "OpenSession"},
|
||||
{0x00000001, nullptr, "GetPerformanceMode"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
void APM::OpenSession(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ISession>();
|
||||
auto module_ = std::make_shared<Module>();
|
||||
std::make_shared<APM>(module_, "apm")->InstallAsService(service_manager);
|
||||
std::make_shared<APM>(module_, "apm:p")->InstallAsService(service_manager);
|
||||
}
|
||||
|
||||
} // namespace APM
|
||||
|
||||
@@ -14,13 +14,10 @@ enum class PerformanceMode : u8 {
|
||||
Docked = 1,
|
||||
};
|
||||
|
||||
class APM final : public ServiceFramework<APM> {
|
||||
class Module final {
|
||||
public:
|
||||
APM();
|
||||
~APM() = default;
|
||||
|
||||
private:
|
||||
void OpenSession(Kernel::HLERequestContext& ctx);
|
||||
Module() = default;
|
||||
~Module() = default;
|
||||
};
|
||||
|
||||
/// Registers all AM services with the specified service manager.
|
||||
|
||||
66
src/core/hle/service/apm/interface.cpp
Normal file
66
src/core/hle/service/apm/interface.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/service/apm/apm.h"
|
||||
#include "core/hle/service/apm/interface.h"
|
||||
|
||||
namespace Service {
|
||||
namespace APM {
|
||||
|
||||
class ISession final : public ServiceFramework<ISession> {
|
||||
public:
|
||||
ISession() : ServiceFramework("ISession") {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ISession::SetPerformanceConfiguration, "SetPerformanceConfiguration"},
|
||||
{1, &ISession::GetPerformanceConfiguration, "GetPerformanceConfiguration"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
private:
|
||||
void SetPerformanceConfiguration(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
auto mode = static_cast<PerformanceMode>(rp.Pop<u32>());
|
||||
u32 config = rp.Pop<u32>();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_APM, "(STUBBED) called mode=%u config=%u", static_cast<u32>(mode),
|
||||
config);
|
||||
}
|
||||
|
||||
void GetPerformanceConfiguration(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
auto mode = static_cast<PerformanceMode>(rp.Pop<u32>());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(0); // Performance configuration
|
||||
|
||||
LOG_WARNING(Service_APM, "(STUBBED) called mode=%u", static_cast<u32>(mode));
|
||||
}
|
||||
};
|
||||
|
||||
APM::APM(std::shared_ptr<Module> apm, const char* name)
|
||||
: ServiceFramework(name), apm(std::move(apm)) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &APM::OpenSession, "OpenSession"},
|
||||
{1, nullptr, "GetPerformanceMode"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
void APM::OpenSession(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ISession>();
|
||||
}
|
||||
|
||||
} // namespace APM
|
||||
} // namespace Service
|
||||
27
src/core/hle/service/apm/interface.h
Normal file
27
src/core/hle/service/apm/interface.h
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service {
|
||||
namespace APM {
|
||||
|
||||
class APM final : public ServiceFramework<APM> {
|
||||
public:
|
||||
APM(std::shared_ptr<Module> apm, const char* name);
|
||||
~APM() = default;
|
||||
|
||||
private:
|
||||
void OpenSession(Kernel::HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<Module> apm;
|
||||
};
|
||||
|
||||
/// Registers all AM services with the specified service manager.
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager);
|
||||
|
||||
} // namespace APM
|
||||
} // namespace Service
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/service/audio/audren_u.h"
|
||||
|
||||
@@ -18,27 +19,69 @@ public:
|
||||
{0x1, nullptr, "GetAudioRendererSampleCount"},
|
||||
{0x2, nullptr, "GetAudioRendererMixBufferCount"},
|
||||
{0x3, nullptr, "GetAudioRendererState"},
|
||||
{0x4, nullptr, "RequestUpdateAudioRenderer"},
|
||||
{0x4, &IAudioRenderer::RequestUpdateAudioRenderer, "RequestUpdateAudioRenderer"},
|
||||
{0x5, nullptr, "StartAudioRenderer"},
|
||||
{0x6, nullptr, "StopAudioRenderer"},
|
||||
{0x7, nullptr, "QuerySystemEvent"},
|
||||
{0x7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"},
|
||||
{0x8, nullptr, "SetAudioRendererRenderingTimeLimit"},
|
||||
{0x9, nullptr, "GetAudioRendererRenderingTimeLimit"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
|
||||
system_event =
|
||||
Kernel::Event::Create(Kernel::ResetType::OneShot, "IAudioRenderer:SystemEvent");
|
||||
}
|
||||
~IAudioRenderer() = default;
|
||||
|
||||
private:
|
||||
void RequestUpdateAudioRenderer(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void QuerySystemEvent(Kernel::HLERequestContext& ctx) {
|
||||
// system_event->Signal();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(system_event);
|
||||
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
}
|
||||
|
||||
Kernel::SharedPtr<Kernel::Event> system_event;
|
||||
};
|
||||
|
||||
AudRenU::AudRenU() : ServiceFramework("audren:u") {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0x00000000, nullptr, "OpenAudioRenderer"},
|
||||
{0x00000001, nullptr, "GetAudioRendererWorkBufferSize"},
|
||||
{0x00000000, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"},
|
||||
{0x00000001, &AudRenU::GetAudioRendererWorkBufferSize, "GetAudioRendererWorkBufferSize"},
|
||||
{0x00000002, nullptr, "GetAudioRenderersProcessMasterVolume"},
|
||||
{0x00000003, nullptr, "SetAudioRenderersProcessMasterVolume"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<Audio::IAudioRenderer>();
|
||||
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
}
|
||||
|
||||
void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u64>(0x1000);
|
||||
|
||||
LOG_WARNING(Service_Audio, "called");
|
||||
}
|
||||
|
||||
} // namespace Audio
|
||||
} // namespace Service
|
||||
|
||||
@@ -17,6 +17,10 @@ class AudRenU final : public ServiceFramework<AudRenU> {
|
||||
public:
|
||||
explicit AudRenU();
|
||||
~AudRenU() = default;
|
||||
|
||||
private:
|
||||
void OpenAudioRenderer(Kernel::HLERequestContext& ctx);
|
||||
void GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx);
|
||||
};
|
||||
|
||||
} // namespace Audio
|
||||
|
||||
@@ -70,7 +70,9 @@ private:
|
||||
FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
|
||||
static const FunctionInfo functions[] = {
|
||||
{1, &FSP_SRV::Initalize, "Initalize"},
|
||||
{18, &FSP_SRV::MountSdCard, "MountSdCard"},
|
||||
{200, &FSP_SRV::OpenDataStorageByCurrentProcess, "OpenDataStorageByCurrentProcess"},
|
||||
{202, nullptr, "OpenDataStorageByDataId"},
|
||||
{203, &FSP_SRV::OpenRomStorage, "OpenRomStorage"},
|
||||
{1005, &FSP_SRV::GetGlobalAccessLogMode, "GetGlobalAccessLogMode"},
|
||||
};
|
||||
@@ -95,6 +97,13 @@ void FSP_SRV::Initalize(Kernel::HLERequestContext& ctx) {
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_FS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_FS, "(STUBBED) called");
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ private:
|
||||
void TryLoadRomFS();
|
||||
|
||||
void Initalize(Kernel::HLERequestContext& ctx);
|
||||
void MountSdCard(Kernel::HLERequestContext& ctx);
|
||||
void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
|
||||
void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
|
||||
void OpenRomStorage(Kernel::HLERequestContext& ctx);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/client_port.h"
|
||||
#include "core/hle/kernel/client_session.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/kernel/shared_memory.h"
|
||||
#include "core/hle/service/hid/hid.h"
|
||||
#include "core/hle/service/service.h"
|
||||
@@ -179,17 +180,24 @@ public:
|
||||
{100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"},
|
||||
{102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"},
|
||||
{103, &Hid::ActivateNpad, "ActivateNpad"},
|
||||
{106, &Hid::AcquireNpadStyleSetUpdateEventHandle,
|
||||
"AcquireNpadStyleSetUpdateEventHandle"},
|
||||
{120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"},
|
||||
{121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"},
|
||||
{124, nullptr, "SetNpadJoyAssignmentModeDual"},
|
||||
{128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"},
|
||||
{203, &Hid::CreateActiveVibrationDeviceList, "CreateActiveVibrationDeviceList"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
|
||||
event = Kernel::Event::Create(Kernel::ResetType::OneShot, "hid:EventHandle");
|
||||
}
|
||||
~Hid() = default;
|
||||
|
||||
private:
|
||||
std::shared_ptr<IAppletResource> applet_resource;
|
||||
u32 joy_hold_type{0};
|
||||
Kernel::SharedPtr<Kernel::Event> event;
|
||||
|
||||
void CreateAppletResource(Kernel::HLERequestContext& ctx) {
|
||||
if (applet_resource == nullptr) {
|
||||
@@ -238,12 +246,26 @@ private:
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(event);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(joy_hold_type);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
@@ -20,15 +20,17 @@ u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, std::vector
|
||||
}
|
||||
|
||||
void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height,
|
||||
u32 stride) {
|
||||
u32 stride, NVFlinger::BufferQueue::BufferTransformFlags transform) {
|
||||
VAddr addr = nvmap_dev->GetObjectAddress(buffer_handle);
|
||||
LOG_WARNING(Service,
|
||||
"Drawing from address %llx offset %08X Width %u Height %u Stride %u Format %u",
|
||||
addr, offset, width, height, stride, format);
|
||||
|
||||
using PixelFormat = RendererBase::FramebufferInfo::PixelFormat;
|
||||
using Flags = NVFlinger::BufferQueue::BufferTransformFlags;
|
||||
const bool flip_vertical = static_cast<u32>(transform) & static_cast<u32>(Flags::FlipV);
|
||||
const RendererBase::FramebufferInfo framebuffer_info{
|
||||
addr, offset, width, height, stride, static_cast<PixelFormat>(format)};
|
||||
addr, offset, width, height, stride, static_cast<PixelFormat>(format), flip_vertical};
|
||||
|
||||
Core::System::GetInstance().perf_stats.EndGameFrame();
|
||||
VideoCore::g_renderer->SwapBuffers(framebuffer_info);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvdevice.h"
|
||||
#include "core/hle/service/nvflinger/buffer_queue.h"
|
||||
|
||||
namespace Service {
|
||||
namespace Nvidia {
|
||||
@@ -23,7 +24,8 @@ public:
|
||||
u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& 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);
|
||||
void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride,
|
||||
NVFlinger::BufferQueue::BufferTransformFlags transform);
|
||||
|
||||
private:
|
||||
std::shared_ptr<nvmap> nvmap_dev;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvmap.h"
|
||||
|
||||
namespace Service {
|
||||
namespace Nvidia {
|
||||
@@ -40,9 +41,16 @@ u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& ou
|
||||
u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlAllocSpace params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, pages=%x, page_size=%x, flags=%x", params.pages,
|
||||
params.page_size, params.flags);
|
||||
params.offset = 0xdeadbeef; // TODO(ogniK): Actually allocate space and give a real offset
|
||||
LOG_DEBUG(Service_NVDRV, "called, pages=%x, page_size=%x, flags=%x", params.pages,
|
||||
params.page_size, params.flags);
|
||||
|
||||
const u64 size{static_cast<u64>(params.pages) * static_cast<u64>(params.page_size)};
|
||||
if (params.flags & 1) {
|
||||
params.offset = memory_manager->AllocateSpace(params.offset, size, 1);
|
||||
} else {
|
||||
params.offset = memory_manager->AllocateSpace(size, params.align);
|
||||
}
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return 0;
|
||||
}
|
||||
@@ -51,12 +59,24 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou
|
||||
IoctlMapBufferEx params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
LOG_WARNING(Service_NVDRV,
|
||||
"(STUBBED) called, flags=%x, nvmap_handle=%x, buffer_offset=%lx, mapping_size=%lx, "
|
||||
"offset=%lx",
|
||||
params.flags, params.nvmap_handle, params.buffer_offset, params.mapping_size,
|
||||
params.offset);
|
||||
params.offset = 0x0; // TODO(ogniK): Actually map and give a real offset
|
||||
LOG_DEBUG(Service_NVDRV,
|
||||
"called, flags=%x, nvmap_handle=%x, buffer_offset=%lx, mapping_size=%lx, offset=%lx",
|
||||
params.flags, params.nvmap_handle, params.buffer_offset, params.mapping_size,
|
||||
params.offset);
|
||||
|
||||
if (!params.nvmap_handle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto object = nvmap_dev->GetObject(params.nvmap_handle);
|
||||
ASSERT(object);
|
||||
|
||||
if (params.flags & 1) {
|
||||
params.offset = memory_manager->MapBufferEx(object->addr, params.offset, object->size);
|
||||
} else {
|
||||
params.offset = memory_manager->MapBufferEx(object->addr, object->size);
|
||||
}
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4,18 +4,25 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvdevice.h"
|
||||
#include "core/hle/service/nvdrv/memory_manager.h"
|
||||
|
||||
namespace Service {
|
||||
namespace Nvidia {
|
||||
namespace Devices {
|
||||
|
||||
class nvmap;
|
||||
|
||||
class nvhost_as_gpu final : public nvdevice {
|
||||
public:
|
||||
nvhost_as_gpu() = default;
|
||||
nvhost_as_gpu(std::shared_ptr<nvmap> nvmap_dev) : nvdevice(), nvmap_dev(std::move(nvmap_dev)) {
|
||||
memory_manager = std::make_shared<MemoryManager>();
|
||||
}
|
||||
~nvhost_as_gpu() override = default;
|
||||
|
||||
u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
|
||||
@@ -92,6 +99,9 @@ private:
|
||||
u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
|
||||
std::shared_ptr<nvmap> nvmap_dev;
|
||||
std::shared_ptr<MemoryManager> memory_manager;
|
||||
};
|
||||
|
||||
} // namespace Devices
|
||||
|
||||
@@ -104,8 +104,20 @@ u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u
|
||||
}
|
||||
|
||||
u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
std::memset(output.data(), 0, output.size());
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
IoctlNvgpuGpuZcullGetInfoArgs params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
params.width_align_pixels = 0x20;
|
||||
params.height_align_pixels = 0x20;
|
||||
params.pixel_squares_by_aliquots = 0x400;
|
||||
params.aliquot_total = 0x800;
|
||||
params.region_byte_multiplier = 0x20;
|
||||
params.region_header_size = 0x20;
|
||||
params.subregion_header_size = 0xc0;
|
||||
params.subregion_width_align_pixels = 0x20;
|
||||
params.subregion_height_align_pixels = 0x40;
|
||||
params.subregion_count = 0x10;
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,10 +13,8 @@ namespace Nvidia {
|
||||
namespace Devices {
|
||||
|
||||
VAddr nvmap::GetObjectAddress(u32 handle) const {
|
||||
auto itr = handles.find(handle);
|
||||
ASSERT(itr != handles.end());
|
||||
|
||||
auto object = itr->second;
|
||||
auto object = GetObject(handle);
|
||||
ASSERT(object);
|
||||
ASSERT(object->status == Object::Status::Allocated);
|
||||
return object->addr;
|
||||
}
|
||||
@@ -52,7 +50,7 @@ u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
u32 handle = next_handle++;
|
||||
handles[handle] = std::move(object);
|
||||
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) size 0x%08X", params.size);
|
||||
LOG_DEBUG(Service_NVDRV, "size=0x%08X", params.size);
|
||||
|
||||
params.handle = handle;
|
||||
|
||||
@@ -64,17 +62,16 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IocAllocParams params;
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
|
||||
auto itr = handles.find(params.handle);
|
||||
ASSERT(itr != handles.end());
|
||||
auto object = GetObject(params.handle);
|
||||
ASSERT(object);
|
||||
|
||||
auto object = itr->second;
|
||||
object->flags = params.flags;
|
||||
object->align = params.align;
|
||||
object->kind = params.kind;
|
||||
object->addr = params.addr;
|
||||
object->status = Object::Status::Allocated;
|
||||
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) Allocated address 0x%llx", params.addr);
|
||||
LOG_DEBUG(Service_NVDRV, "called, addr=0x%llx", params.addr);
|
||||
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
return 0;
|
||||
@@ -86,10 +83,10 @@ u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
|
||||
LOG_WARNING(Service_NVDRV, "called");
|
||||
|
||||
auto itr = handles.find(params.handle);
|
||||
ASSERT(itr != handles.end());
|
||||
auto object = GetObject(params.handle);
|
||||
ASSERT(object);
|
||||
|
||||
params.id = itr->second->id;
|
||||
params.id = object->id;
|
||||
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
return 0;
|
||||
@@ -123,10 +120,8 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called type=%u", params.type);
|
||||
|
||||
auto itr = handles.find(params.handle);
|
||||
ASSERT(itr != handles.end());
|
||||
|
||||
auto object = itr->second;
|
||||
auto object = GetObject(params.handle);
|
||||
ASSERT(object);
|
||||
ASSERT(object->status == Object::Status::Allocated);
|
||||
|
||||
switch (static_cast<ParamTypes>(params.type)) {
|
||||
|
||||
@@ -26,8 +26,7 @@ public:
|
||||
|
||||
u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
|
||||
|
||||
private:
|
||||
// Represents an nvmap object.
|
||||
/// Represents an nvmap object.
|
||||
struct Object {
|
||||
enum class Status { Created, Allocated };
|
||||
u32 id;
|
||||
@@ -39,10 +38,19 @@ private:
|
||||
Status status;
|
||||
};
|
||||
|
||||
std::shared_ptr<Object> GetObject(u32 handle) const {
|
||||
auto itr = handles.find(handle);
|
||||
if (itr != handles.end()) {
|
||||
return itr->second;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
private:
|
||||
/// Id to use for the next handle that is created.
|
||||
u32 next_handle = 1;
|
||||
|
||||
// Id to use for the next object that is created.
|
||||
/// Id to use for the next object that is created.
|
||||
u32 next_id = 1;
|
||||
|
||||
/// Mapping of currently allocated handles to the objects they represent.
|
||||
|
||||
@@ -78,11 +78,10 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
|
||||
u32 event_id = rp.Pop<u32>();
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd=%x, event_id=%x", fd, event_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
IPC::ResponseBuilder rb{ctx, 3, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
auto event = Kernel::Event::Create(Kernel::ResetType::Pulse, "NVEvent");
|
||||
event->Signal();
|
||||
rb.PushCopyObjects(event);
|
||||
rb.PushCopyObjects(query_event);
|
||||
rb.Push<u32>(0);
|
||||
}
|
||||
|
||||
void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) {
|
||||
@@ -113,6 +112,8 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
|
||||
{13, &NVDRV::FinishInitialize, "FinishInitialize"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
|
||||
query_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "NVDRV::query_event");
|
||||
}
|
||||
|
||||
} // namespace Nvidia
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/service/nvdrv/nvdrv.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
@@ -29,6 +30,8 @@ private:
|
||||
std::shared_ptr<Module> nvdrv;
|
||||
|
||||
u64 pid{};
|
||||
|
||||
Kernel::SharedPtr<Kernel::Event> query_event;
|
||||
};
|
||||
|
||||
} // namespace Nvidia
|
||||
|
||||
112
src/core/hle/service/nvdrv/memory_manager.cpp
Normal file
112
src/core/hle/service/nvdrv/memory_manager.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "core/hle/service/nvdrv/memory_manager.h"
|
||||
|
||||
namespace Service {
|
||||
namespace Nvidia {
|
||||
|
||||
PAddr MemoryManager::AllocateSpace(u64 size, u64 align) {
|
||||
boost::optional<PAddr> paddr = FindFreeBlock(size, align);
|
||||
ASSERT(paddr);
|
||||
|
||||
for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
|
||||
PageSlot(*paddr + offset) = static_cast<u64>(PageStatus::Allocated);
|
||||
}
|
||||
|
||||
return *paddr;
|
||||
}
|
||||
|
||||
PAddr MemoryManager::AllocateSpace(PAddr paddr, u64 size, u64 align) {
|
||||
for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
|
||||
if (IsPageMapped(paddr + offset)) {
|
||||
return AllocateSpace(size, align);
|
||||
}
|
||||
}
|
||||
|
||||
for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
|
||||
PageSlot(paddr + offset) = static_cast<u64>(PageStatus::Allocated);
|
||||
}
|
||||
|
||||
return paddr;
|
||||
}
|
||||
|
||||
PAddr MemoryManager::MapBufferEx(VAddr vaddr, u64 size) {
|
||||
vaddr &= ~Memory::PAGE_MASK;
|
||||
|
||||
boost::optional<PAddr> paddr = FindFreeBlock(size);
|
||||
ASSERT(paddr);
|
||||
|
||||
for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
|
||||
PageSlot(*paddr + offset) = vaddr + offset;
|
||||
}
|
||||
|
||||
return *paddr;
|
||||
}
|
||||
|
||||
PAddr MemoryManager::MapBufferEx(VAddr vaddr, PAddr paddr, u64 size) {
|
||||
vaddr &= ~Memory::PAGE_MASK;
|
||||
paddr &= ~Memory::PAGE_MASK;
|
||||
|
||||
for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
|
||||
if (PageSlot(paddr + offset) != static_cast<u64>(PageStatus::Allocated)) {
|
||||
return MapBufferEx(vaddr, size);
|
||||
}
|
||||
}
|
||||
|
||||
for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
|
||||
PageSlot(paddr + offset) = vaddr + offset;
|
||||
}
|
||||
|
||||
return paddr;
|
||||
}
|
||||
|
||||
boost::optional<PAddr> MemoryManager::FindFreeBlock(u64 size, u64 align) {
|
||||
PAddr paddr{};
|
||||
u64 free_space{};
|
||||
align = (align + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
|
||||
|
||||
while (paddr + free_space < MAX_ADDRESS) {
|
||||
if (!IsPageMapped(paddr + free_space)) {
|
||||
free_space += Memory::PAGE_SIZE;
|
||||
if (free_space >= size) {
|
||||
return paddr;
|
||||
}
|
||||
} else {
|
||||
paddr += free_space + Memory::PAGE_SIZE;
|
||||
free_space = 0;
|
||||
const u64 remainder{paddr % align};
|
||||
if (!remainder) {
|
||||
paddr = (paddr - remainder) + align;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
VAddr MemoryManager::PhysicalToVirtualAddress(PAddr paddr) {
|
||||
VAddr base_addr = PageSlot(paddr);
|
||||
ASSERT(base_addr != static_cast<u64>(PageStatus::Unmapped));
|
||||
return base_addr + (paddr & Memory::PAGE_MASK);
|
||||
}
|
||||
|
||||
bool MemoryManager::IsPageMapped(PAddr paddr) {
|
||||
return PageSlot(paddr) != static_cast<u64>(PageStatus::Unmapped);
|
||||
}
|
||||
|
||||
VAddr& MemoryManager::PageSlot(PAddr paddr) {
|
||||
auto& block = page_table[(paddr >> (Memory::PAGE_BITS + PAGE_TABLE_BITS)) & PAGE_TABLE_MASK];
|
||||
if (!block) {
|
||||
block = std::make_unique<PageBlock>();
|
||||
for (unsigned index = 0; index < PAGE_BLOCK_SIZE; index++) {
|
||||
(*block)[index] = static_cast<u64>(PageStatus::Unmapped);
|
||||
}
|
||||
}
|
||||
return (*block)[(paddr >> Memory::PAGE_BITS) & PAGE_BLOCK_MASK];
|
||||
}
|
||||
|
||||
} // namespace Nvidia
|
||||
} // namespace Service
|
||||
48
src/core/hle/service/nvdrv/memory_manager.h
Normal file
48
src/core/hle/service/nvdrv/memory_manager.h
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include "common/common_types.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Service {
|
||||
namespace Nvidia {
|
||||
|
||||
class MemoryManager final {
|
||||
public:
|
||||
MemoryManager() = default;
|
||||
|
||||
PAddr AllocateSpace(u64 size, u64 align);
|
||||
PAddr AllocateSpace(PAddr paddr, u64 size, u64 align);
|
||||
PAddr MapBufferEx(VAddr vaddr, u64 size);
|
||||
PAddr MapBufferEx(VAddr vaddr, PAddr paddr, u64 size);
|
||||
VAddr PhysicalToVirtualAddress(PAddr paddr);
|
||||
|
||||
private:
|
||||
boost::optional<PAddr> FindFreeBlock(u64 size, u64 align = 1);
|
||||
bool IsPageMapped(PAddr paddr);
|
||||
VAddr& PageSlot(PAddr paddr);
|
||||
|
||||
enum class PageStatus : u64 {
|
||||
Unmapped = 0xFFFFFFFFFFFFFFFFULL,
|
||||
Allocated = 0xFFFFFFFFFFFFFFFEULL,
|
||||
};
|
||||
|
||||
static constexpr u64 MAX_ADDRESS{0x10000000000ULL};
|
||||
static constexpr u64 PAGE_TABLE_BITS{14};
|
||||
static constexpr u64 PAGE_TABLE_SIZE{1 << PAGE_TABLE_BITS};
|
||||
static constexpr u64 PAGE_TABLE_MASK{PAGE_TABLE_SIZE - 1};
|
||||
static constexpr u64 PAGE_BLOCK_BITS{14};
|
||||
static constexpr u64 PAGE_BLOCK_SIZE{1 << PAGE_BLOCK_BITS};
|
||||
static constexpr u64 PAGE_BLOCK_MASK{PAGE_BLOCK_SIZE - 1};
|
||||
|
||||
using PageBlock = std::array<VAddr, PAGE_BLOCK_SIZE>;
|
||||
std::array<std::unique_ptr<PageBlock>, PAGE_TABLE_SIZE> page_table{};
|
||||
};
|
||||
|
||||
} // namespace Nvidia
|
||||
} // namespace Service
|
||||
@@ -31,7 +31,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
|
||||
|
||||
Module::Module() {
|
||||
auto nvmap_dev = std::make_shared<Devices::nvmap>();
|
||||
devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>();
|
||||
devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>(nvmap_dev);
|
||||
devices["/dev/nvhost-ctrl-gpu"] = std::make_shared<Devices::nvhost_ctrl_gpu>();
|
||||
devices["/dev/nvmap"] = nvmap_dev;
|
||||
devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(nvmap_dev);
|
||||
|
||||
@@ -40,7 +40,11 @@ u32 BufferQueue::DequeueBuffer(u32 pixel_format, u32 width, u32 height) {
|
||||
return igbp_buffer.format == pixel_format && igbp_buffer.width == width &&
|
||||
igbp_buffer.height == height;
|
||||
});
|
||||
ASSERT(itr != queue.end());
|
||||
if (itr == queue.end()) {
|
||||
LOG_CRITICAL(Service_NVDRV, "no free buffers for pixel_format=%d, width=%d, height=%d",
|
||||
pixel_format, width, height);
|
||||
itr = queue.begin();
|
||||
}
|
||||
|
||||
itr->status = Buffer::Status::Dequeued;
|
||||
return itr->slot;
|
||||
@@ -54,12 +58,13 @@ const IGBPBuffer& BufferQueue::RequestBuffer(u32 slot) const {
|
||||
return itr->igbp_buffer;
|
||||
}
|
||||
|
||||
void BufferQueue::QueueBuffer(u32 slot) {
|
||||
void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform) {
|
||||
auto itr = std::find_if(queue.begin(), queue.end(),
|
||||
[&](const Buffer& buffer) { return buffer.slot == slot; });
|
||||
ASSERT(itr != queue.end());
|
||||
ASSERT(itr->status == Buffer::Status::Dequeued);
|
||||
itr->status = Buffer::Status::Queued;
|
||||
itr->transform = transform;
|
||||
}
|
||||
|
||||
boost::optional<const BufferQueue::Buffer&> BufferQueue::AcquireBuffer() {
|
||||
|
||||
@@ -46,18 +46,32 @@ public:
|
||||
BufferQueue(u32 id, u64 layer_id);
|
||||
~BufferQueue() = default;
|
||||
|
||||
enum class BufferTransformFlags : u32 {
|
||||
/// Flip source image horizontally (around the vertical axis)
|
||||
FlipH = 0x01,
|
||||
/// Flip source image vertically (around the horizontal axis)
|
||||
FlipV = 0x02,
|
||||
/// Rotate source image 90 degrees clockwise
|
||||
Rotate90 = 0x04,
|
||||
/// Rotate source image 180 degrees
|
||||
Roate180 = 0x03,
|
||||
/// Rotate source image 270 degrees clockwise
|
||||
Roate270 = 0x07,
|
||||
};
|
||||
|
||||
struct Buffer {
|
||||
enum class Status { Free = 0, Queued = 1, Dequeued = 2, Acquired = 3 };
|
||||
|
||||
u32 slot;
|
||||
Status status = Status::Free;
|
||||
IGBPBuffer igbp_buffer;
|
||||
BufferTransformFlags transform;
|
||||
};
|
||||
|
||||
void SetPreallocatedBuffer(u32 slot, IGBPBuffer& buffer);
|
||||
u32 DequeueBuffer(u32 pixel_format, u32 width, u32 height);
|
||||
const IGBPBuffer& RequestBuffer(u32 slot) const;
|
||||
void QueueBuffer(u32 slot);
|
||||
void QueueBuffer(u32 slot, BufferTransformFlags transform);
|
||||
boost::optional<const Buffer&> AcquireBuffer();
|
||||
void ReleaseBuffer(u32 slot);
|
||||
u32 Query(QueryType type);
|
||||
|
||||
@@ -145,7 +145,7 @@ void NVFlinger::Compose() {
|
||||
ASSERT(nvdisp);
|
||||
|
||||
nvdisp->flip(igbp_buffer.gpu_buffer_id, igbp_buffer.offset, igbp_buffer.format,
|
||||
igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride);
|
||||
igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride, buffer->transform);
|
||||
|
||||
buffer_queue->ReleaseBuffer(buffer->slot);
|
||||
}
|
||||
|
||||
@@ -68,8 +68,15 @@ public:
|
||||
ITimeZoneService() : ServiceFramework("ITimeZoneService") {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ITimeZoneService::GetDeviceLocationName, "GetDeviceLocationName"},
|
||||
{1, nullptr, "SetDeviceLocationName"},
|
||||
{2, &ITimeZoneService::GetTotalLocationNameCount, "GetTotalLocationNameCount"},
|
||||
{3, nullptr, "LoadLocationNameList"},
|
||||
{4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"},
|
||||
{5, nullptr, "GetTimeZoneRuleVersion"},
|
||||
{100, nullptr, "ToCalendarTime"},
|
||||
{101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
|
||||
{200, nullptr, "ToPosixTime"},
|
||||
{201, nullptr, "ToPosixTimeWithMyRule"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
@@ -90,6 +97,12 @@ private:
|
||||
rb.Push<u32>(0);
|
||||
}
|
||||
|
||||
void LoadTimeZoneRule(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_Time, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 posix_time = rp.Pop<u64>();
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <array>
|
||||
#include "common/alignment.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "core/core_timing.h"
|
||||
@@ -19,6 +19,15 @@
|
||||
namespace Service {
|
||||
namespace VI {
|
||||
|
||||
struct DisplayInfo {
|
||||
char display_name[0x40]{"Default"};
|
||||
u64 unknown_1{1};
|
||||
u64 unknown_2{1};
|
||||
u64 width{1920};
|
||||
u64 height{1080};
|
||||
};
|
||||
static_assert(sizeof(DisplayInfo) == 0x60, "DisplayInfo has wrong size");
|
||||
|
||||
class Parcel {
|
||||
public:
|
||||
// This default size was chosen arbitrarily.
|
||||
@@ -92,8 +101,10 @@ public:
|
||||
SerializeData();
|
||||
|
||||
Header header{};
|
||||
header.data_offset = sizeof(Header);
|
||||
header.data_size = static_cast<u32_le>(write_index - sizeof(Header));
|
||||
header.data_offset = sizeof(Header);
|
||||
header.objects_size = 4;
|
||||
header.objects_offset = sizeof(Header) + header.data_size;
|
||||
std::memcpy(buffer.data(), &header, sizeof(Header));
|
||||
|
||||
return buffer;
|
||||
@@ -133,11 +144,11 @@ protected:
|
||||
private:
|
||||
struct Data {
|
||||
u32_le magic = 2;
|
||||
u32_le process_id;
|
||||
u32_le process_id = 1;
|
||||
u32_le id;
|
||||
INSERT_PADDING_BYTES(0xC);
|
||||
INSERT_PADDING_WORDS(3);
|
||||
std::array<u8, 8> dispdrv = {'d', 'i', 's', 'p', 'd', 'r', 'v', '\0'};
|
||||
INSERT_PADDING_BYTES(8);
|
||||
INSERT_PADDING_WORDS(2);
|
||||
};
|
||||
static_assert(sizeof(Data) == 0x28, "ParcelData has wrong size");
|
||||
|
||||
@@ -202,7 +213,6 @@ public:
|
||||
void DeserializeData() override {
|
||||
std::u16string token = ReadInterfaceToken();
|
||||
data = Read<Data>();
|
||||
ASSERT(data.graphic_buffer_length == sizeof(NVFlinger::IGBPBuffer));
|
||||
buffer = Read<NVFlinger::IGBPBuffer>();
|
||||
}
|
||||
|
||||
@@ -292,14 +302,11 @@ public:
|
||||
|
||||
protected:
|
||||
void SerializeData() override {
|
||||
// TODO(Subv): Find out what this all means
|
||||
Write<u32_le>(1);
|
||||
|
||||
Write<u32_le>(sizeof(NVFlinger::IGBPBuffer));
|
||||
Write<u32_le>(0); // Unknown
|
||||
|
||||
// TODO(bunnei): Find out what this all means. Writing anything non-zero here breaks libnx.
|
||||
Write<u32_le>(0);
|
||||
Write<u32_le>(0);
|
||||
Write<u32_le>(0);
|
||||
Write(buffer);
|
||||
|
||||
Write<u32_le>(0);
|
||||
}
|
||||
|
||||
@@ -318,13 +325,29 @@ public:
|
||||
data = Read<Data>();
|
||||
}
|
||||
|
||||
struct Fence {
|
||||
u32_le id;
|
||||
u32_le value;
|
||||
};
|
||||
static_assert(sizeof(Fence) == 8, "Fence has wrong size");
|
||||
|
||||
struct Data {
|
||||
u32_le slot;
|
||||
INSERT_PADDING_WORDS(2);
|
||||
INSERT_PADDING_WORDS(3);
|
||||
u32_le timestamp;
|
||||
INSERT_PADDING_WORDS(20);
|
||||
s32_le is_auto_timestamp;
|
||||
s32_le crop_left;
|
||||
s32_le crop_top;
|
||||
s32_le crop_right;
|
||||
s32_le crop_bottom;
|
||||
s32_le scaling_mode;
|
||||
NVFlinger::BufferQueue::BufferTransformFlags transform;
|
||||
u32_le sticky_transform;
|
||||
INSERT_PADDING_WORDS(2);
|
||||
u32_le fence_is_valid;
|
||||
std::array<Fence, 2> fences;
|
||||
};
|
||||
static_assert(sizeof(Data) == 96, "ParcelData has wrong size");
|
||||
static_assert(sizeof(Data) == 80, "ParcelData has wrong size");
|
||||
|
||||
Data data;
|
||||
};
|
||||
@@ -392,7 +415,7 @@ public:
|
||||
{0, &IHOSBinderDriver::TransactParcel, "TransactParcel"},
|
||||
{1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"},
|
||||
{2, &IHOSBinderDriver::GetNativeHandle, "GetNativeHandle"},
|
||||
{3, nullptr, "TransactParcelAuto"},
|
||||
{3, &IHOSBinderDriver::TransactParcelAuto, "TransactParcelAuto"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
@@ -416,35 +439,21 @@ private:
|
||||
SetPreallocatedBuffer = 14
|
||||
};
|
||||
|
||||
void TransactParcel(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
u32 id = rp.Pop<u32>();
|
||||
auto transaction = static_cast<TransactionId>(rp.Pop<u32>());
|
||||
u32 flags = rp.Pop<u32>();
|
||||
|
||||
auto& input_buffer = ctx.BufferDescriptorA()[0];
|
||||
std::vector<u8> input_data(input_buffer.Size());
|
||||
Memory::ReadBlock(input_buffer.Address(), input_data.data(), input_buffer.Size());
|
||||
|
||||
auto& output_buffer = ctx.BufferDescriptorB()[0];
|
||||
|
||||
void TransactParcel(u32 id, TransactionId transaction, const std::vector<u8>& input_data,
|
||||
VAddr output_addr, u64 output_size) {
|
||||
auto buffer_queue = nv_flinger->GetBufferQueue(id);
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called, transaction=%x", transaction);
|
||||
std::vector<u8> response_buffer;
|
||||
if (transaction == TransactionId::Connect) {
|
||||
IGBPConnectRequestParcel request{input_data};
|
||||
IGBPConnectResponseParcel response{1280, 720};
|
||||
auto response_buffer = response.Serialize();
|
||||
Memory::WriteBlock(output_buffer.Address(), response_buffer.data(),
|
||||
output_buffer.Size());
|
||||
response_buffer = response.Serialize();
|
||||
} else if (transaction == TransactionId::SetPreallocatedBuffer) {
|
||||
IGBPSetPreallocatedBufferRequestParcel request{input_data};
|
||||
|
||||
buffer_queue->SetPreallocatedBuffer(request.data.slot, request.buffer);
|
||||
|
||||
IGBPSetPreallocatedBufferResponseParcel response{};
|
||||
auto response_buffer = response.Serialize();
|
||||
Memory::WriteBlock(output_buffer.Address(), response_buffer.data(),
|
||||
output_buffer.Size());
|
||||
response_buffer = response.Serialize();
|
||||
} else if (transaction == TransactionId::DequeueBuffer) {
|
||||
IGBPDequeueBufferRequestParcel request{input_data};
|
||||
|
||||
@@ -452,27 +461,21 @@ private:
|
||||
request.data.height);
|
||||
|
||||
IGBPDequeueBufferResponseParcel response{slot};
|
||||
auto response_buffer = response.Serialize();
|
||||
Memory::WriteBlock(output_buffer.Address(), response_buffer.data(),
|
||||
output_buffer.Size());
|
||||
response_buffer = response.Serialize();
|
||||
} else if (transaction == TransactionId::RequestBuffer) {
|
||||
IGBPRequestBufferRequestParcel request{input_data};
|
||||
|
||||
auto& buffer = buffer_queue->RequestBuffer(request.slot);
|
||||
|
||||
IGBPRequestBufferResponseParcel response{buffer};
|
||||
auto response_buffer = response.Serialize();
|
||||
Memory::WriteBlock(output_buffer.Address(), response_buffer.data(),
|
||||
output_buffer.Size());
|
||||
response_buffer = response.Serialize();
|
||||
} else if (transaction == TransactionId::QueueBuffer) {
|
||||
IGBPQueueBufferRequestParcel request{input_data};
|
||||
|
||||
buffer_queue->QueueBuffer(request.data.slot);
|
||||
buffer_queue->QueueBuffer(request.data.slot, request.data.transform);
|
||||
|
||||
IGBPQueueBufferResponseParcel response{1280, 720};
|
||||
auto response_buffer = response.Serialize();
|
||||
Memory::WriteBlock(output_buffer.Address(), response_buffer.data(),
|
||||
output_buffer.Size());
|
||||
response_buffer = response.Serialize();
|
||||
} else if (transaction == TransactionId::Query) {
|
||||
IGBPQueryRequestParcel request{input_data};
|
||||
|
||||
@@ -480,13 +483,47 @@ private:
|
||||
buffer_queue->Query(static_cast<NVFlinger::BufferQueue::QueryType>(request.type));
|
||||
|
||||
IGBPQueryResponseParcel response{value};
|
||||
auto response_buffer = response.Serialize();
|
||||
Memory::WriteBlock(output_buffer.Address(), response_buffer.data(),
|
||||
output_buffer.Size());
|
||||
response_buffer = response.Serialize();
|
||||
|
||||
} else {
|
||||
ASSERT_MSG(false, "Unimplemented");
|
||||
}
|
||||
|
||||
Memory::WriteBlock(output_addr, response_buffer.data(), output_size);
|
||||
}
|
||||
|
||||
void TransactParcel(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
u32 id = rp.Pop<u32>();
|
||||
auto transaction = static_cast<TransactionId>(rp.Pop<u32>());
|
||||
u32 flags = rp.Pop<u32>();
|
||||
LOG_DEBUG(Service_VI, "called, transaction=%x", transaction);
|
||||
|
||||
auto& input_buffer = ctx.BufferDescriptorA()[0];
|
||||
auto& output_buffer = ctx.BufferDescriptorB()[0];
|
||||
std::vector<u8> input_data(input_buffer.Size());
|
||||
Memory::ReadBlock(input_buffer.Address(), input_data.data(), input_buffer.Size());
|
||||
|
||||
TransactParcel(id, transaction, input_data, output_buffer.Address(), output_buffer.Size());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void TransactParcelAuto(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
u32 id = rp.Pop<u32>();
|
||||
auto transaction = static_cast<TransactionId>(rp.Pop<u32>());
|
||||
u32 flags = rp.Pop<u32>();
|
||||
LOG_DEBUG(Service_VI, "called, transaction=%x", transaction);
|
||||
|
||||
auto& input_buffer = ctx.BufferDescriptorX()[0];
|
||||
auto& output_buffer = ctx.BufferDescriptorC()[0];
|
||||
std::vector<u8> input_data(input_buffer.size);
|
||||
Memory::ReadBlock(input_buffer.Address(), input_data.data(), input_buffer.size);
|
||||
|
||||
TransactParcel(id, transaction, input_data, output_buffer.Address(), output_buffer.Size());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
@@ -648,12 +685,12 @@ void IApplicationDisplayService::CloseDisplay(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 display_id = rp.Pop<u64>();
|
||||
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0);
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void IApplicationDisplayService::OpenLayer(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
LOG_DEBUG(Service_VI, "called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto name_buf = rp.PopRaw<std::array<u8, 0x40>>();
|
||||
auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
|
||||
@@ -678,7 +715,7 @@ void IApplicationDisplayService::OpenLayer(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
void IApplicationDisplayService::CreateStrayLayer(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service, "(STUBBED) called");
|
||||
LOG_DEBUG(Service_VI, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
u32 flags = rp.Pop<u32>();
|
||||
@@ -722,6 +759,17 @@ void IApplicationDisplayService::SetLayerScalingMode(Kernel::HLERequestContext&
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void IApplicationDisplayService::ListDisplays(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
DisplayInfo display_info;
|
||||
auto& buffer = ctx.BufferDescriptorB()[0];
|
||||
Memory::WriteBlock(buffer.Address(), &display_info, sizeof(DisplayInfo));
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u64>(1);
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IApplicationDisplayService::GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
@@ -743,7 +791,7 @@ IApplicationDisplayService::IApplicationDisplayService(
|
||||
{102, &IApplicationDisplayService::GetManagerDisplayService, "GetManagerDisplayService"},
|
||||
{103, &IApplicationDisplayService::GetIndirectDisplayTransactionService,
|
||||
"GetIndirectDisplayTransactionService"},
|
||||
{1000, nullptr, "ListDisplays"},
|
||||
{1000, &IApplicationDisplayService::ListDisplays, "ListDisplays"},
|
||||
{1010, &IApplicationDisplayService::OpenDisplay, "OpenDisplay"},
|
||||
{1020, &IApplicationDisplayService::CloseDisplay, "CloseDisplay"},
|
||||
{2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"},
|
||||
|
||||
@@ -30,6 +30,7 @@ private:
|
||||
void OpenDisplay(Kernel::HLERequestContext& ctx);
|
||||
void CloseDisplay(Kernel::HLERequestContext& ctx);
|
||||
void SetLayerScalingMode(Kernel::HLERequestContext& ctx);
|
||||
void ListDisplays(Kernel::HLERequestContext& ctx);
|
||||
void OpenLayer(Kernel::HLERequestContext& ctx);
|
||||
void CreateStrayLayer(Kernel::HLERequestContext& ctx);
|
||||
void DestroyStrayLayer(Kernel::HLERequestContext& ctx);
|
||||
|
||||
@@ -43,6 +43,7 @@ public:
|
||||
u32 height;
|
||||
u32 stride;
|
||||
PixelFormat pixel_format;
|
||||
bool flip_vertical;
|
||||
};
|
||||
|
||||
virtual ~RendererBase() {}
|
||||
|
||||
@@ -262,6 +262,8 @@ void RendererOpenGL::LoadFBToScreenInfo(const FramebufferInfo& framebuffer_info,
|
||||
// only allows rows to have a memory alignement of 4.
|
||||
ASSERT(framebuffer_info.stride % 4 == 0);
|
||||
|
||||
framebuffer_flip_vertical = framebuffer_info.flip_vertical;
|
||||
|
||||
// Reset the screen info's display texture to its own permanent texture
|
||||
screen_info.display_texture = screen_info.texture.resource.handle;
|
||||
screen_info.display_texcoords = MathUtil::Rectangle<float>(0.f, 0.f, 1.f, 1.f);
|
||||
@@ -401,13 +403,15 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
|
||||
|
||||
void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w,
|
||||
float h) {
|
||||
auto& texcoords = screen_info.display_texcoords;
|
||||
const auto& texcoords = screen_info.display_texcoords;
|
||||
const auto& left = framebuffer_flip_vertical ? texcoords.right : texcoords.left;
|
||||
const auto& right = framebuffer_flip_vertical ? texcoords.left : texcoords.right;
|
||||
|
||||
std::array<ScreenRectVertex, 4> vertices = {{
|
||||
ScreenRectVertex(x, y, texcoords.top, texcoords.right),
|
||||
ScreenRectVertex(x + w, y, texcoords.bottom, texcoords.right),
|
||||
ScreenRectVertex(x, y + h, texcoords.top, texcoords.left),
|
||||
ScreenRectVertex(x + w, y + h, texcoords.bottom, texcoords.left),
|
||||
ScreenRectVertex(x, y, texcoords.top, right),
|
||||
ScreenRectVertex(x + w, y, texcoords.bottom, right),
|
||||
ScreenRectVertex(x, y + h, texcoords.top, left),
|
||||
ScreenRectVertex(x + w, y + h, texcoords.bottom, left),
|
||||
}};
|
||||
|
||||
state.texture_units[0].texture_2d = screen_info.display_texture;
|
||||
|
||||
@@ -86,4 +86,7 @@ private:
|
||||
// Shader attribute input indices
|
||||
GLuint attrib_position;
|
||||
GLuint attrib_tex_coord;
|
||||
|
||||
/// Flips the framebuffer vertically when true
|
||||
bool framebuffer_flip_vertical;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user