Compare commits
22 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3160f83607 | ||
|
|
890e98a33e | ||
|
|
deadcb39c2 | ||
|
|
6fce1414c3 | ||
|
|
068744db1b | ||
|
|
b26cdf1fe5 | ||
|
|
8e7da73214 | ||
|
|
0532de6559 | ||
|
|
c83a1b2320 | ||
|
|
725304094e | ||
|
|
63de56ee0f | ||
|
|
309276a317 | ||
|
|
1add3b20c4 | ||
|
|
3b35202280 | ||
|
|
45e5a67676 | ||
|
|
22caeee64f | ||
|
|
576f0cf027 | ||
|
|
ca99063600 | ||
|
|
205daab50d | ||
|
|
d3bbed5e78 | ||
|
|
dc0a137e5b | ||
|
|
db11c9a0b9 |
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -20,8 +20,8 @@ public:
|
||||
{0x2, nullptr, "GetAudioRendererMixBufferCount"},
|
||||
{0x3, nullptr, "GetAudioRendererState"},
|
||||
{0x4, &IAudioRenderer::RequestUpdateAudioRenderer, "RequestUpdateAudioRenderer"},
|
||||
{0x5, nullptr, "StartAudioRenderer"},
|
||||
{0x6, nullptr, "StopAudioRenderer"},
|
||||
{0x5, &IAudioRenderer::StartAudioRenderer, "StartAudioRenderer"},
|
||||
{0x6, &IAudioRenderer::StopAudioRenderer, "StopAudioRenderer"},
|
||||
{0x7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"},
|
||||
{0x8, nullptr, "SetAudioRendererRenderingTimeLimit"},
|
||||
{0x9, nullptr, "GetAudioRendererRenderingTimeLimit"},
|
||||
@@ -35,6 +35,42 @@ public:
|
||||
|
||||
private:
|
||||
void RequestUpdateAudioRenderer(Kernel::HLERequestContext& ctx) {
|
||||
AudioRendererResponseData response_data = {0};
|
||||
|
||||
response_data.section_0_size =
|
||||
response_data.state_entries.size() * sizeof(AudioRendererStateEntry);
|
||||
response_data.section_1_size = response_data.section_1.size();
|
||||
response_data.section_2_size = response_data.section_2.size();
|
||||
response_data.section_3_size = response_data.section_3.size();
|
||||
response_data.section_4_size = response_data.section_4.size();
|
||||
response_data.section_5_size = response_data.section_5.size();
|
||||
response_data.total_size = sizeof(AudioRendererResponseData);
|
||||
|
||||
for (unsigned i = 0; i < response_data.state_entries.size(); i++) {
|
||||
// 4 = Busy and 5 = Ready?
|
||||
response_data.state_entries[i].state = 5;
|
||||
}
|
||||
|
||||
auto& buffer = ctx.BufferDescriptorB()[0];
|
||||
|
||||
Memory::WriteBlock(buffer.Address(), &response_data, response_data.total_size);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void StartAudioRenderer(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void StopAudioRenderer(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -52,6 +88,44 @@ private:
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
}
|
||||
|
||||
struct AudioRendererStateEntry {
|
||||
u32_le state;
|
||||
u32_le unknown_4;
|
||||
u32_le unknown_8;
|
||||
u32_le unknown_c;
|
||||
};
|
||||
static_assert(sizeof(AudioRendererStateEntry) == 0x10,
|
||||
"AudioRendererStateEntry has wrong size");
|
||||
|
||||
struct AudioRendererResponseData {
|
||||
u32_le unknown_0;
|
||||
u32_le section_5_size;
|
||||
u32_le section_0_size;
|
||||
u32_le section_1_size;
|
||||
u32_le unknown_10;
|
||||
u32_le section_2_size;
|
||||
u32_le unknown_18;
|
||||
u32_le section_3_size;
|
||||
u32_le section_4_size;
|
||||
u32_le unknown_24;
|
||||
u32_le unknown_28;
|
||||
u32_le unknown_2c;
|
||||
u32_le unknown_30;
|
||||
u32_le unknown_34;
|
||||
u32_le unknown_38;
|
||||
u32_le total_size;
|
||||
|
||||
std::array<AudioRendererStateEntry, 0x18e> state_entries;
|
||||
|
||||
std::array<u8, 0x600> section_1;
|
||||
std::array<u8, 0xe0> section_2;
|
||||
std::array<u8, 0x20> section_3;
|
||||
std::array<u8, 0x10> section_4;
|
||||
std::array<u8, 0xb0> section_5;
|
||||
};
|
||||
static_assert(sizeof(AudioRendererResponseData) == 0x20e0,
|
||||
"AudioRendererResponseData has wrong size");
|
||||
|
||||
Kernel::SharedPtr<Kernel::Event> system_event;
|
||||
};
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@ 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"},
|
||||
@@ -96,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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
@@ -101,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;
|
||||
@@ -142,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");
|
||||
|
||||
@@ -211,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>();
|
||||
}
|
||||
|
||||
@@ -301,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);
|
||||
}
|
||||
|
||||
@@ -327,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;
|
||||
};
|
||||
@@ -401,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);
|
||||
}
|
||||
@@ -425,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};
|
||||
|
||||
@@ -461,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};
|
||||
|
||||
@@ -489,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);
|
||||
}
|
||||
@@ -657,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');
|
||||
@@ -687,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>();
|
||||
|
||||
@@ -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