diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic.cpp | 20 | ||||
-rw-r--r-- | src/core/hle/service/audio/audren_u.cpp | 119 | ||||
-rw-r--r-- | src/core/hle/service/audio/audren_u.h | 1 | ||||
-rw-r--r-- | src/core/hle/service/lm/lm.cpp | 69 | ||||
-rw-r--r-- | src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp | 6 | ||||
-rw-r--r-- | src/core/hle/service/nvdrv/devices/nvdisp_disp0.h | 4 | ||||
-rw-r--r-- | src/core/hle/service/nvflinger/buffer_queue.cpp | 3 | ||||
-rw-r--r-- | src/core/hle/service/nvflinger/buffer_queue.h | 16 | ||||
-rw-r--r-- | src/core/hle/service/nvflinger/nvflinger.cpp | 2 | ||||
-rw-r--r-- | src/core/hle/service/vi/vi.cpp | 93 | ||||
-rw-r--r-- | src/core/memory.h | 9 | ||||
-rw-r--r-- | src/video_core/renderer_base.h | 1 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 14 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.h | 3 |
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 302bae5690..283d208314 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 4c3a685e95..c8d8ba748a 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 e975437423..939d353a90 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 c480f6b97c..b8e53d2c74 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 4d0ab844ce..7674d332de 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 f3cfc9925e..66f56f23df 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 f90c7ca518..ff7b6b039f 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 5c6719407f..ef97327699 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 fe622b9864..2089462b7f 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 69ac2fe07f..8b4ed30d2d 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 b2158ca462..f3ace7a98d 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 28893b181a..2aba50edae 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 8c23128aec..7f921fa320 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 db6c355a51..05bb3c5cf1 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; }; |