summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp20
-rw-r--r--src/core/hle/service/audio/audren_u.cpp119
-rw-r--r--src/core/hle/service/audio/audren_u.h1
-rw-r--r--src/core/hle/service/lm/lm.cpp69
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp6
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.h4
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp3
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h16
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp2
-rw-r--r--src/core/hle/service/vi/vi.cpp93
-rw-r--r--src/core/memory.h9
-rw-r--r--src/video_core/renderer_base.h1
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp14
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h3
14 files changed, 283 insertions, 77 deletions
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index 302bae569..283d20831 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -85,11 +85,19 @@ public:
ARM_Dynarmic& parent;
size_t ticks_remaining = 0;
size_t num_interpreted_instructions = 0;
- u64 tpidrr0_el0 = 0;
+ u64 tpidrro_el0 = 0;
};
std::unique_ptr<Dynarmic::A64::Jit> MakeJit(const std::unique_ptr<ARM_Dynarmic_Callbacks>& cb) {
- Dynarmic::A64::UserConfig config{cb.get()};
+ const auto page_table = Kernel::g_current_process->vm_manager.page_table.pointers.data();
+
+ Dynarmic::A64::UserConfig config;
+ config.callbacks = cb.get();
+ config.tpidrro_el0 = &cb->tpidrro_el0;
+ config.dczid_el0 = 4;
+ config.page_table = reinterpret_cast<void**>(page_table);
+ config.page_table_address_space_bits = Memory::ADDRESS_SPACE_BITS;
+ config.silently_mirror_page_table = false;
return std::make_unique<Dynarmic::A64::Jit>(config);
}
@@ -149,11 +157,11 @@ void ARM_Dynarmic::SetCPSR(u32 cpsr) {
}
u64 ARM_Dynarmic::GetTlsAddress() const {
- return cb->tpidrr0_el0;
+ return cb->tpidrro_el0;
}
void ARM_Dynarmic::SetTlsAddress(u64 address) {
- cb->tpidrr0_el0 = address;
+ cb->tpidrro_el0 = address;
}
void ARM_Dynarmic::ExecuteInstructions(int num_instructions) {
@@ -170,7 +178,7 @@ void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& ctx) {
ctx.cpsr = jit->GetPstate();
ctx.fpu_registers = jit->GetVectors();
ctx.fpscr = jit->GetFpcr();
- ctx.tls_address = cb->tpidrr0_el0;
+ ctx.tls_address = cb->tpidrro_el0;
}
void ARM_Dynarmic::LoadContext(const ARM_Interface::ThreadContext& ctx) {
@@ -180,7 +188,7 @@ void ARM_Dynarmic::LoadContext(const ARM_Interface::ThreadContext& ctx) {
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;
+ cb->tpidrro_el0 = ctx.tls_address;
}
void ARM_Dynarmic::PrepareReschedule() {
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 4c3a685e9..c8d8ba748 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include "common/logging/log.h"
+#include "core/core_timing.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/hle_ipc.h"
@@ -11,6 +12,9 @@
namespace Service {
namespace Audio {
+/// TODO(bunnei): Find a proper value for the audio_ticks
+constexpr u64 audio_ticks{static_cast<u64>(BASE_CLOCK_RATE / 200)};
+
class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
public:
IAudioRenderer() : ServiceFramework("IAudioRenderer") {
@@ -20,8 +24,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"},
@@ -30,11 +34,61 @@ public:
system_event =
Kernel::Event::Create(Kernel::ResetType::OneShot, "IAudioRenderer:SystemEvent");
+
+ // Register event callback to update the Audio Buffer
+ audio_event = CoreTiming::RegisterEvent(
+ "IAudioRenderer::UpdateAudioCallback", [this](u64 userdata, int cycles_late) {
+ UpdateAudioCallback();
+ CoreTiming::ScheduleEvent(audio_ticks - cycles_late, audio_event);
+ });
+
+ // Start the audio event
+ CoreTiming::ScheduleEvent(audio_ticks, audio_event);
}
~IAudioRenderer() = default;
private:
+ void UpdateAudioCallback() {
+ system_event->Signal();
+ }
+
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,15 +106,56 @@ 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");
+
+ /// This is used to trigger the audio event callback.
+ CoreTiming::EventType* audio_event;
+
Kernel::SharedPtr<Kernel::Event> system_event;
};
AudRenU::AudRenU() : ServiceFramework("audren:u") {
static const FunctionInfo functions[] = {
- {0x00000000, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"},
- {0x00000001, &AudRenU::GetAudioRendererWorkBufferSize, "GetAudioRendererWorkBufferSize"},
- {0x00000002, nullptr, "GetAudioRenderersProcessMasterVolume"},
- {0x00000003, nullptr, "SetAudioRenderersProcessMasterVolume"},
+ {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"},
+ {1, &AudRenU::GetAudioRendererWorkBufferSize, "GetAudioRendererWorkBufferSize"},
+ {2, &AudRenU::GetAudioRenderersProcessMasterVolume, "GetAudioRenderersProcessMasterVolume"},
+ {3, nullptr, "SetAudioRenderersProcessMasterVolume"},
};
RegisterHandlers(functions);
}
@@ -78,9 +173,17 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
- rb.Push<u64>(0x1000);
+ rb.Push<u64>(0x400);
+
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
+}
+
+void AudRenU::GetAudioRenderersProcessMasterVolume(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+
+ rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_Audio, "called");
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
}
} // namespace Audio
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h
index e97543742..939d353a9 100644
--- a/src/core/hle/service/audio/audren_u.h
+++ b/src/core/hle/service/audio/audren_u.h
@@ -21,6 +21,7 @@ public:
private:
void OpenAudioRenderer(Kernel::HLERequestContext& ctx);
void GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx);
+ void GetAudioRenderersProcessMasterVolume(Kernel::HLERequestContext& ctx);
};
} // namespace Audio
diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp
index c480f6b97..b8e53d2c7 100644
--- a/src/core/hle/service/lm/lm.cpp
+++ b/src/core/hle/service/lm/lm.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <sstream>
#include <string>
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
@@ -28,19 +29,28 @@ private:
IsHead = 1,
IsTail = 2,
};
+ enum Severity : u32_le {
+ Trace,
+ Info,
+ Warning,
+ Error,
+ Critical,
+ };
u64_le pid;
u64_le threadContext;
union {
BitField<0, 16, Flags> flags;
- BitField<16, 8, u32_le> severity;
+ BitField<16, 8, Severity> severity;
BitField<24, 8, u32_le> verbosity;
};
u32_le payload_size;
- /// Returns true if this is part of a single log message
- bool IsSingleMessage() const {
- return (flags & Flags::IsHead) && (flags & Flags::IsTail);
+ bool IsHeadLog() const {
+ return flags & Flags::IsHead;
+ }
+ bool IsTailLog() const {
+ return flags & Flags::IsTail;
}
};
static_assert(sizeof(MessageHeader) == 0x18, "MessageHeader is incorrect size");
@@ -57,7 +67,7 @@ private:
};
/**
- * LM::Initialize service function
+ * LM::Log service function
* Inputs:
* 0: 0x00000000
* Outputs:
@@ -75,9 +85,9 @@ private:
Memory::ReadBlock(addr, &header, sizeof(MessageHeader));
addr += sizeof(MessageHeader);
- if (!header.IsSingleMessage()) {
- LOG_WARNING(Service_LM, "Multi message logs are unimplemeneted");
- return;
+ if (header.IsHeadLog()) {
+ log_stream.str("");
+ log_stream.clear();
}
// Parse out log metadata
@@ -85,7 +95,7 @@ private:
std::string message, filename, function;
while (addr < end_addr) {
const Field field{static_cast<Field>(Memory::Read8(addr++))};
- size_t length{Memory::Read8(addr++)};
+ const size_t length{Memory::Read8(addr++)};
if (static_cast<Field>(Memory::Read8(addr)) == Field::Skip) {
++addr;
@@ -110,28 +120,47 @@ private:
}
// Empty log - nothing to do here
- if (message.empty()) {
+ if (log_stream.str().empty() && message.empty()) {
return;
}
// Format a nicely printable string out of the log metadata
- std::string output;
- if (filename.size()) {
- output += filename + ':';
+ if (!filename.empty()) {
+ log_stream << filename << ':';
}
- if (function.size()) {
- output += function + ':';
+ if (!function.empty()) {
+ log_stream << function << ':';
}
if (line) {
- output += std::to_string(line) + ':';
+ log_stream << std::to_string(line) << ':';
}
- if (output.length() > 0 && output.back() == ':') {
- output += ' ';
+ if (log_stream.str().length() > 0 && log_stream.str().back() == ':') {
+ log_stream << ' ';
}
- output += message;
+ log_stream << message;
- LOG_INFO(Debug_Emulated, "%s", output.c_str());
+ if (header.IsTailLog()) {
+ switch (header.severity) {
+ case MessageHeader::Severity::Trace:
+ LOG_TRACE(Debug_Emulated, "%s", log_stream.str().c_str());
+ break;
+ case MessageHeader::Severity::Info:
+ LOG_INFO(Debug_Emulated, "%s", log_stream.str().c_str());
+ break;
+ case MessageHeader::Severity::Warning:
+ LOG_WARNING(Debug_Emulated, "%s", log_stream.str().c_str());
+ break;
+ case MessageHeader::Severity::Error:
+ LOG_ERROR(Debug_Emulated, "%s", log_stream.str().c_str());
+ break;
+ case MessageHeader::Severity::Critical:
+ LOG_CRITICAL(Debug_Emulated, "%s", log_stream.str().c_str());
+ break;
+ }
+ }
}
+
+ std::ostringstream log_stream;
};
void InstallInterfaces(SM::ServiceManager& service_manager) {
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index 4d0ab844c..7674d332d 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -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);
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
index f3cfc9925..66f56f23d 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
@@ -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;
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp
index f90c7ca51..ff7b6b039 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue.cpp
@@ -58,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() {
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
index 5c6719407..ef9732769 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.h
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -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);
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index fe622b986..2089462b7 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -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);
}
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 69ac2fe07..8b4ed30d2 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -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");
@@ -260,6 +262,11 @@ public:
Data data;
};
+// TODO(bunnei): Remove this. When set to 1, games will think a fence is valid and boot further.
+// This will break libnx and potentially other apps that more stringently check this. This is here
+// purely as a convenience, and should go away once we implement fences.
+static constexpr u32 FENCE_HACK = 0;
+
class IGBPDequeueBufferResponseParcel : public Parcel {
public:
explicit IGBPDequeueBufferResponseParcel(u32 slot) : Parcel(), slot(slot) {}
@@ -267,11 +274,20 @@ public:
protected:
void SerializeData() override {
- Write(slot);
- // TODO(Subv): Find out how this Fence is used.
- std::array<u32_le, 11> fence = {};
- Write(fence);
- Write<u32_le>(0);
+ // TODO(bunnei): Find out what this all means. Writing anything non-zero here breaks libnx.
+ Write<u32>(0);
+ Write<u32>(FENCE_HACK);
+ Write<u32>(0);
+ Write<u32>(0);
+ Write<u32>(0);
+ Write<u32>(0);
+ Write<u32>(0);
+ Write<u32>(0);
+ Write<u32>(0);
+ Write<u32>(0);
+ Write<u32>(0);
+ Write<u32>(0);
+ Write<u32>(0);
}
u32_le slot;
@@ -302,7 +318,7 @@ protected:
void SerializeData() override {
// TODO(bunnei): Find out what this all means. Writing anything non-zero here breaks libnx.
Write<u32_le>(0);
- Write<u32_le>(0);
+ Write<u32_le>(FENCE_HACK);
Write<u32_le>(0);
Write(buffer);
Write<u32_le>(0);
@@ -323,13 +339,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;
};
@@ -424,18 +456,20 @@ private:
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);
- std::vector<u8> response_buffer;
+
if (transaction == TransactionId::Connect) {
IGBPConnectRequestParcel request{input_data};
IGBPConnectResponseParcel response{1280, 720};
- response_buffer = response.Serialize();
+ std::vector<u8> response_buffer = response.Serialize();
+ Memory::WriteBlock(output_addr, response_buffer.data(), response_buffer.size());
} else if (transaction == TransactionId::SetPreallocatedBuffer) {
IGBPSetPreallocatedBufferRequestParcel request{input_data};
buffer_queue->SetPreallocatedBuffer(request.data.slot, request.buffer);
IGBPSetPreallocatedBufferResponseParcel response{};
- response_buffer = response.Serialize();
+ std::vector<u8> response_buffer = response.Serialize();
+ Memory::WriteBlock(output_addr, response_buffer.data(), response_buffer.size());
} else if (transaction == TransactionId::DequeueBuffer) {
IGBPDequeueBufferRequestParcel request{input_data};
@@ -443,21 +477,24 @@ private:
request.data.height);
IGBPDequeueBufferResponseParcel response{slot};
- response_buffer = response.Serialize();
+ std::vector<u8> response_buffer = response.Serialize();
+ Memory::WriteBlock(output_addr, response_buffer.data(), response_buffer.size());
} else if (transaction == TransactionId::RequestBuffer) {
IGBPRequestBufferRequestParcel request{input_data};
auto& buffer = buffer_queue->RequestBuffer(request.slot);
IGBPRequestBufferResponseParcel response{buffer};
- response_buffer = response.Serialize();
+ std::vector<u8> response_buffer = response.Serialize();
+ Memory::WriteBlock(output_addr, response_buffer.data(), response_buffer.size());
} 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};
- response_buffer = response.Serialize();
+ std::vector<u8> response_buffer = response.Serialize();
+ Memory::WriteBlock(output_addr, response_buffer.data(), response_buffer.size());
} else if (transaction == TransactionId::Query) {
IGBPQueryRequestParcel request{input_data};
@@ -465,13 +502,13 @@ private:
buffer_queue->Query(static_cast<NVFlinger::BufferQueue::QueryType>(request.type));
IGBPQueryResponseParcel response{value};
- response_buffer = response.Serialize();
-
+ std::vector<u8> response_buffer = response.Serialize();
+ Memory::WriteBlock(output_addr, response_buffer.data(), response_buffer.size());
+ } else if (transaction == TransactionId::CancelBuffer) {
+ LOG_WARNING(Service_VI, "(STUBBED) called, transaction=CancelBuffer");
} else {
ASSERT_MSG(false, "Unimplemented");
}
-
- Memory::WriteBlock(output_addr, response_buffer.data(), output_size);
}
void TransactParcel(Kernel::HLERequestContext& ctx) {
@@ -537,7 +574,7 @@ private:
}
std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;
-};
+}; // namespace VI
class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> {
public:
@@ -672,7 +709,7 @@ void IApplicationDisplayService::CloseDisplay(Kernel::HLERequestContext& ctx) {
}
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');
@@ -697,7 +734,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>();
diff --git a/src/core/memory.h b/src/core/memory.h
index b2158ca46..f3ace7a98 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -25,10 +25,11 @@ namespace Memory {
* Page size used by the ARM architecture. This is the smallest granularity with which memory can
* be mapped.
*/
-const int PAGE_BITS = 12;
-const u64 PAGE_SIZE = 1 << PAGE_BITS;
-const u64 PAGE_MASK = PAGE_SIZE - 1;
-const size_t PAGE_TABLE_NUM_ENTRIES = 1ULL << (36 - PAGE_BITS);
+constexpr size_t PAGE_BITS = 12;
+constexpr u64 PAGE_SIZE = 1 << PAGE_BITS;
+constexpr u64 PAGE_MASK = PAGE_SIZE - 1;
+constexpr size_t ADDRESS_SPACE_BITS = 36;
+constexpr size_t PAGE_TABLE_NUM_ENTRIES = 1ULL << (ADDRESS_SPACE_BITS - PAGE_BITS);
enum class PageType : u8 {
/// Page is unmapped and should cause an access error.
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h
index 28893b181..2aba50eda 100644
--- a/src/video_core/renderer_base.h
+++ b/src/video_core/renderer_base.h
@@ -43,6 +43,7 @@ public:
u32 height;
u32 stride;
PixelFormat pixel_format;
+ bool flip_vertical;
};
virtual ~RendererBase() {}
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 8c23128ae..7f921fa32 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -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;
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index db6c355a5..05bb3c5cf 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -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;
};