diff options
Diffstat (limited to 'src/core/hle')
| -rw-r--r-- | src/core/hle/kernel/code_set.cpp | 12 | ||||
| -rw-r--r-- | src/core/hle/kernel/code_set.h | 90 | ||||
| -rw-r--r-- | src/core/hle/kernel/process.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/kernel/process.h | 43 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 3 | ||||
| -rw-r--r-- | src/core/hle/service/audio/hwopus.cpp | 82 |
6 files changed, 156 insertions, 80 deletions
diff --git a/src/core/hle/kernel/code_set.cpp b/src/core/hle/kernel/code_set.cpp new file mode 100644 index 000000000..1f434e9af --- /dev/null +++ b/src/core/hle/kernel/code_set.cpp @@ -0,0 +1,12 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/kernel/code_set.h" + +namespace Kernel { + +CodeSet::CodeSet() = default; +CodeSet::~CodeSet() = default; + +} // namespace Kernel diff --git a/src/core/hle/kernel/code_set.h b/src/core/hle/kernel/code_set.h new file mode 100644 index 000000000..834fd23d2 --- /dev/null +++ b/src/core/hle/kernel/code_set.h @@ -0,0 +1,90 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <cstddef> +#include <memory> +#include <vector> + +#include "common/common_types.h" + +namespace Kernel { + +/** + * Represents executable data that may be loaded into a kernel process. + * + * A code set consists of three basic segments: + * - A code (AKA text) segment, + * - A read-only data segment (rodata) + * - A data segment + * + * The code segment is the portion of the object file that contains + * executable instructions. + * + * The read-only data segment in the portion of the object file that + * contains (as one would expect) read-only data, such as fixed constant + * values and data structures. + * + * The data segment is similar to the read-only data segment -- it contains + * variables and data structures that have predefined values, however, + * entities within this segment can be modified. + */ +struct CodeSet final { + /// A single segment within a code set. + struct Segment final { + /// The byte offset that this segment is located at. + std::size_t offset = 0; + + /// The address to map this segment to. + VAddr addr = 0; + + /// The size of this segment in bytes. + u32 size = 0; + }; + + explicit CodeSet(); + ~CodeSet(); + + CodeSet(const CodeSet&) = delete; + CodeSet& operator=(const CodeSet&) = delete; + + CodeSet(CodeSet&&) = default; + CodeSet& operator=(CodeSet&&) = default; + + Segment& CodeSegment() { + return segments[0]; + } + + const Segment& CodeSegment() const { + return segments[0]; + } + + Segment& RODataSegment() { + return segments[1]; + } + + const Segment& RODataSegment() const { + return segments[1]; + } + + Segment& DataSegment() { + return segments[2]; + } + + const Segment& DataSegment() const { + return segments[2]; + } + + /// The overall data that backs this code set. + std::shared_ptr<std::vector<u8>> memory; + + /// The segments that comprise this code set. + std::array<Segment, 3> segments; + + /// The entry point address for this code set. + VAddr entrypoint = 0; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 65c51003d..15a16ae14 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -9,6 +9,7 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/file_sys/program_metadata.h" +#include "core/hle/kernel/code_set.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" @@ -50,9 +51,6 @@ void SetupMainThread(Process& owner_process, KernelCore& kernel, VAddr entry_poi } } // Anonymous namespace -CodeSet::CodeSet() = default; -CodeSet::~CodeSet() = default; - SharedPtr<Process> Process::Create(Core::System& system, std::string&& name) { auto& kernel = system.Kernel(); @@ -212,7 +210,7 @@ void Process::FreeTLSSlot(VAddr tls_address) { } void Process::LoadModule(CodeSet module_, VAddr base_addr) { - const auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions, + const auto MapSegment = [&](const CodeSet::Segment& segment, VMAPermission permissions, MemoryState memory_state) { const auto vma = vm_manager .MapMemoryBlock(segment.addr + base_addr, module_.memory, diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 47ffd4ad3..3ae7c922c 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -7,7 +7,6 @@ #include <array> #include <bitset> #include <cstddef> -#include <memory> #include <string> #include <vector> #include <boost/container/static_vector.hpp> @@ -33,6 +32,8 @@ class KernelCore; class ResourceLimit; class Thread; +struct CodeSet; + struct AddressMapping { // Address and size must be page-aligned VAddr address; @@ -65,46 +66,6 @@ enum class ProcessStatus { DebugBreak, }; -struct CodeSet final { - struct Segment { - std::size_t offset = 0; - VAddr addr = 0; - u32 size = 0; - }; - - explicit CodeSet(); - ~CodeSet(); - - Segment& CodeSegment() { - return segments[0]; - } - - const Segment& CodeSegment() const { - return segments[0]; - } - - Segment& RODataSegment() { - return segments[1]; - } - - const Segment& RODataSegment() const { - return segments[1]; - } - - Segment& DataSegment() { - return segments[2]; - } - - const Segment& DataSegment() const { - return segments[2]; - } - - std::shared_ptr<std::vector<u8>> memory; - - std::array<Segment, 3> segments; - VAddr entrypoint = 0; -}; - class Process final : public WaitObject { public: enum : u64 { diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index d9ffebc3f..3b22e8e0d 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -314,8 +314,9 @@ void Thread::UpdatePriority() { } // Ensure that the thread is within the correct location in the waiting list. + auto old_owner = lock_owner; lock_owner->RemoveMutexWaiter(this); - lock_owner->AddMutexWaiter(this); + old_owner->AddMutexWaiter(this); // Recursively update the priority of the thread that depends on the priority of this one. lock_owner->UpdatePriority(); diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp index 377e12cfa..cb4a1160d 100644 --- a/src/core/hle/service/audio/hwopus.cpp +++ b/src/core/hle/service/audio/hwopus.cpp @@ -8,6 +8,7 @@ #include <vector> #include <opus.h> +#include <opus_multistream.h> #include "common/assert.h" #include "common/logging/log.h" @@ -18,12 +19,12 @@ namespace Service::Audio { namespace { struct OpusDeleter { - void operator()(void* ptr) const { - operator delete(ptr); + void operator()(OpusMSDecoder* ptr) const { + opus_multistream_decoder_destroy(ptr); } }; -using OpusDecoderPtr = std::unique_ptr<OpusDecoder, OpusDeleter>; +using OpusDecoderPtr = std::unique_ptr<OpusMSDecoder, OpusDeleter>; struct OpusPacketHeader { // Packet size in bytes. @@ -33,7 +34,7 @@ struct OpusPacketHeader { }; static_assert(sizeof(OpusPacketHeader) == 0x8, "OpusHeader is an invalid size"); -class OpusDecoderStateBase { +class OpusDecoderState { public: /// Describes extra behavior that may be asked of the decoding context. enum class ExtraBehavior { @@ -49,22 +50,13 @@ public: Enabled, }; - virtual ~OpusDecoderStateBase() = default; - - // Decodes interleaved Opus packets. Optionally allows reporting time taken to - // perform the decoding, as well as any relevant extra behavior. - virtual void DecodeInterleaved(Kernel::HLERequestContext& ctx, PerfTime perf_time, - ExtraBehavior extra_behavior) = 0; -}; - -// Represents the decoder state for a non-multistream decoder. -class OpusDecoderState final : public OpusDecoderStateBase { -public: explicit OpusDecoderState(OpusDecoderPtr decoder, u32 sample_rate, u32 channel_count) : decoder{std::move(decoder)}, sample_rate{sample_rate}, channel_count{channel_count} {} + // Decodes interleaved Opus packets. Optionally allows reporting time taken to + // perform the decoding, as well as any relevant extra behavior. void DecodeInterleaved(Kernel::HLERequestContext& ctx, PerfTime perf_time, - ExtraBehavior extra_behavior) override { + ExtraBehavior extra_behavior) { if (perf_time == PerfTime::Disabled) { DecodeInterleavedHelper(ctx, nullptr, extra_behavior); } else { @@ -135,7 +127,7 @@ private: const int frame_size = (static_cast<int>(raw_output_sz / sizeof(s16) / channel_count)); const auto out_sample_count = - opus_decode(decoder.get(), frame, hdr.size, output.data(), frame_size, 0); + opus_multistream_decode(decoder.get(), frame, hdr.size, output.data(), frame_size, 0); if (out_sample_count < 0) { LOG_ERROR(Audio, "Incorrect sample count received from opus_decode, " @@ -158,7 +150,7 @@ private: void ResetDecoderContext() { ASSERT(decoder != nullptr); - opus_decoder_ctl(decoder.get(), OPUS_RESET_STATE); + opus_multistream_decoder_ctl(decoder.get(), OPUS_RESET_STATE); } OpusDecoderPtr decoder; @@ -168,7 +160,7 @@ private: class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> { public: - explicit IHardwareOpusDecoderManager(std::unique_ptr<OpusDecoderStateBase> decoder_state) + explicit IHardwareOpusDecoderManager(OpusDecoderState decoder_state) : ServiceFramework("IHardwareOpusDecoderManager"), decoder_state{std::move(decoder_state)} { // clang-format off static const FunctionInfo functions[] = { @@ -190,35 +182,51 @@ private: void DecodeInterleavedOld(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Audio, "called"); - decoder_state->DecodeInterleaved(ctx, OpusDecoderStateBase::PerfTime::Disabled, - OpusDecoderStateBase::ExtraBehavior::None); + decoder_state.DecodeInterleaved(ctx, OpusDecoderState::PerfTime::Disabled, + OpusDecoderState::ExtraBehavior::None); } void DecodeInterleavedWithPerfOld(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Audio, "called"); - decoder_state->DecodeInterleaved(ctx, OpusDecoderStateBase::PerfTime::Enabled, - OpusDecoderStateBase::ExtraBehavior::None); + decoder_state.DecodeInterleaved(ctx, OpusDecoderState::PerfTime::Enabled, + OpusDecoderState::ExtraBehavior::None); } void DecodeInterleaved(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Audio, "called"); IPC::RequestParser rp{ctx}; - const auto extra_behavior = rp.Pop<bool>() - ? OpusDecoderStateBase::ExtraBehavior::ResetContext - : OpusDecoderStateBase::ExtraBehavior::None; + const auto extra_behavior = rp.Pop<bool>() ? OpusDecoderState::ExtraBehavior::ResetContext + : OpusDecoderState::ExtraBehavior::None; - decoder_state->DecodeInterleaved(ctx, OpusDecoderStateBase::PerfTime::Enabled, - extra_behavior); + decoder_state.DecodeInterleaved(ctx, OpusDecoderState::PerfTime::Enabled, extra_behavior); } - std::unique_ptr<OpusDecoderStateBase> decoder_state; + OpusDecoderState decoder_state; }; std::size_t WorkerBufferSize(u32 channel_count) { ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count"); - return opus_decoder_get_size(static_cast<int>(channel_count)); + constexpr int num_streams = 1; + const int num_stereo_streams = channel_count == 2 ? 1 : 0; + return opus_multistream_decoder_get_size(num_streams, num_stereo_streams); +} + +// Creates the mapping table that maps the input channels to the particular +// output channels. In the stereo case, we map the left and right input channels +// to the left and right output channels respectively. +// +// However, in the monophonic case, we only map the one available channel +// to the sole output channel. We specify 255 for the would-be right channel +// as this is a special value defined by Opus to indicate to the decoder to +// ignore that channel. +std::array<u8, 2> CreateMappingTable(u32 channel_count) { + if (channel_count == 2) { + return {{0, 1}}; + } + + return {{0, 255}}; } } // Anonymous namespace @@ -259,9 +267,15 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) { const std::size_t worker_sz = WorkerBufferSize(channel_count); ASSERT_MSG(buffer_sz >= worker_sz, "Worker buffer too large"); - OpusDecoderPtr decoder{static_cast<OpusDecoder*>(operator new(worker_sz))}; - if (const int err = opus_decoder_init(decoder.get(), sample_rate, channel_count)) { - LOG_ERROR(Audio, "Failed to init opus decoder with error={}", err); + const int num_stereo_streams = channel_count == 2 ? 1 : 0; + const auto mapping_table = CreateMappingTable(channel_count); + + int error = 0; + OpusDecoderPtr decoder{ + opus_multistream_decoder_create(sample_rate, static_cast<int>(channel_count), 1, + num_stereo_streams, mapping_table.data(), &error)}; + if (error != OPUS_OK || decoder == nullptr) { + LOG_ERROR(Audio, "Failed to create Opus decoder (error={}).", error); IPC::ResponseBuilder rb{ctx, 2}; // TODO(ogniK): Use correct error code rb.Push(ResultCode(-1)); @@ -271,7 +285,7 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<IHardwareOpusDecoderManager>( - std::make_unique<OpusDecoderState>(std::move(decoder), sample_rate, channel_count)); + OpusDecoderState{std::move(decoder), sample_rate, channel_count}); } HwOpus::HwOpus() : ServiceFramework("hwopus") { |
