From d13e18a8edfb6f26026acb72db426f651ab80ef2 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Nov 2021 18:36:52 -0800 Subject: [PATCH] hle: nvflinger: Move implementation for Parcel to its own header. --- src/core/CMakeLists.txt | 1 + src/core/hle/service/nvflinger/parcel.h | 171 ++++++++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 src/core/hle/service/nvflinger/parcel.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index d9b94b4800..367d44cf38 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -543,6 +543,7 @@ add_library(core STATIC hle/service/nvflinger/consumer_listener.h hle/service/nvflinger/nvflinger.cpp hle/service/nvflinger/nvflinger.h + hle/service/nvflinger/parcel.h hle/service/nvflinger/pixel_format.h hle/service/nvflinger/producer_listener.h hle/service/nvflinger/status.h diff --git a/src/core/hle/service/nvflinger/parcel.h b/src/core/hle/service/nvflinger/parcel.h new file mode 100644 index 0000000000..710964f5d9 --- /dev/null +++ b/src/core/hle/service/nvflinger/parcel.h @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project + +#pragma once + +#include +#include + +#include "common/alignment.h" +#include "common/assert.h" +#include "common/common_types.h" + +namespace android { + +class Parcel final { +public: + static constexpr std::size_t DefaultBufferSize = 0x40; + + Parcel() : buffer(DefaultBufferSize) {} + + template + explicit Parcel(const T& out_data) : buffer(DefaultBufferSize) { + Write(out_data); + } + + explicit Parcel(std::vector in_data) : buffer(std::move(in_data)) { + DeserializeHeader(); + [[maybe_unused]] const std::u16string token = ReadInterfaceToken(); + } + + template + void Read(T& val) { + static_assert(std::is_trivially_copyable_v, "T must be trivially copyable."); + ASSERT(read_index + sizeof(T) <= buffer.size()); + + std::memcpy(&val, buffer.data() + read_index, sizeof(T)); + read_index += sizeof(T); + read_index = Common::AlignUp(read_index, 4); + } + + template + T Read() { + T val; + Read(val); + return val; + } + + template + void ReadFlattened(T& val) { + const auto flattened_size = Read(); + ASSERT(sizeof(T) == flattened_size); + Read(val); + } + + template + T ReadFlattened() { + T val; + ReadFlattened(val); + return val; + } + + template + T ReadUnaligned() { + static_assert(std::is_trivially_copyable_v, "T must be trivially copyable."); + ASSERT(read_index + sizeof(T) <= buffer.size()); + + T val; + std::memcpy(&val, buffer.data() + read_index, sizeof(T)); + read_index += sizeof(T); + return val; + } + + template + const std::shared_ptr ReadObject() { + static_assert(std::is_trivially_copyable_v, "T must be trivially copyable."); + + const auto is_valid{Read()}; + + if (is_valid) { + auto result = std::make_shared(); + ReadFlattened(*result); + return result; + } + + return {}; + } + + std::u16string ReadInterfaceToken() { + [[maybe_unused]] const u32 unknown = Read(); + const u32 length = Read(); + + std::u16string token{}; + + for (u32 ch = 0; ch < length + 1; ++ch) { + token.push_back(ReadUnaligned()); + } + + read_index = Common::AlignUp(read_index, 4); + + return token; + } + + template + void Write(const T& val) { + static_assert(std::is_trivially_copyable_v, "T must be trivially copyable."); + + if (buffer.size() < write_index + sizeof(T)) { + buffer.resize(buffer.size() + sizeof(T) + DefaultBufferSize); + } + + std::memcpy(buffer.data() + write_index, &val, sizeof(T)); + write_index += sizeof(T); + write_index = Common::AlignUp(write_index, 4); + } + + template + void WriteObject(const T* ptr) { + static_assert(std::is_trivially_copyable_v, "T must be trivially copyable."); + + if (!ptr) { + Write(0); + return; + } + + Write(1); + Write(sizeof(T)); + Write(*ptr); + } + + template + void WriteObject(const std::shared_ptr ptr) { + WriteObject(ptr.get()); + } + + void DeserializeHeader() { + ASSERT(buffer.size() > sizeof(Header)); + + Header header{}; + std::memcpy(&header, buffer.data(), sizeof(Header)); + + read_index = header.data_offset; + } + + std::vector Serialize() const { + ASSERT(read_index == 0); + + Header header{}; + header.data_size = static_cast(write_index - sizeof(Header)); + header.data_offset = sizeof(Header); + header.objects_size = 4; + header.objects_offset = static_cast(sizeof(Header) + header.data_size); + std::memcpy(buffer.data(), &header, sizeof(Header)); + + return buffer; + } + +private: + struct Header { + u32 data_size; + u32 data_offset; + u32 objects_size; + u32 objects_offset; + }; + static_assert(sizeof(Header) == 16, "ParcelHeader has wrong size"); + + mutable std::vector buffer; + std::size_t read_index = 0; + std::size_t write_index = sizeof(Header); +}; + +} // namespace android