diff options
Diffstat (limited to '')
58 files changed, 1362 insertions, 167 deletions
diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt index f00a55994..81121167d 100644 --- a/src/audio_core/CMakeLists.txt +++ b/src/audio_core/CMakeLists.txt @@ -2,10 +2,22 @@ add_library(audio_core STATIC audio_out.cpp audio_out.h buffer.h + cubeb_sink.cpp + cubeb_sink.h + null_sink.h stream.cpp stream.h + sink.h + sink_details.cpp + sink_details.h + sink_stream.h ) create_target_directory_groups(audio_core) target_link_libraries(audio_core PUBLIC common core) + +if(ENABLE_CUBEB) + target_link_libraries(audio_core PRIVATE cubeb) + target_compile_definitions(audio_core PRIVATE -DHAVE_CUBEB=1) +endif() diff --git a/src/audio_core/audio_out.cpp b/src/audio_core/audio_out.cpp index 6d418a05b..77cedb6ba 100644 --- a/src/audio_core/audio_out.cpp +++ b/src/audio_core/audio_out.cpp @@ -3,13 +3,15 @@ // Refer to the license.txt file included. #include "audio_core/audio_out.h" +#include "audio_core/sink.h" +#include "audio_core/sink_details.h" #include "common/assert.h" #include "common/logging/log.h" namespace AudioCore { /// Returns the stream format from the specified number of channels -static Stream::Format ChannelsToStreamFormat(int num_channels) { +static Stream::Format ChannelsToStreamFormat(u32 num_channels) { switch (num_channels) { case 1: return Stream::Format::Mono16; @@ -24,11 +26,16 @@ static Stream::Format ChannelsToStreamFormat(int num_channels) { return {}; } -StreamPtr AudioOut::OpenStream(int sample_rate, int num_channels, +StreamPtr AudioOut::OpenStream(u32 sample_rate, u32 num_channels, Stream::ReleaseCallback&& release_callback) { - streams.push_back(std::make_shared<Stream>(sample_rate, ChannelsToStreamFormat(num_channels), - std::move(release_callback))); - return streams.back(); + if (!sink) { + const SinkDetails& sink_details = GetSinkDetails("auto"); + sink = sink_details.factory(""); + } + + return std::make_shared<Stream>(sample_rate, ChannelsToStreamFormat(num_channels), + std::move(release_callback), + sink->AcquireSinkStream(sample_rate, num_channels)); } std::vector<u64> AudioOut::GetTagsAndReleaseBuffers(StreamPtr stream, size_t max_count) { diff --git a/src/audio_core/audio_out.h b/src/audio_core/audio_out.h index a86499d10..8d9b695d4 100644 --- a/src/audio_core/audio_out.h +++ b/src/audio_core/audio_out.h @@ -8,20 +8,19 @@ #include <vector> #include "audio_core/buffer.h" +#include "audio_core/sink.h" #include "audio_core/stream.h" #include "common/common_types.h" namespace AudioCore { -using StreamPtr = std::shared_ptr<Stream>; - /** * Represents an audio playback interface, used to open and play audio streams */ class AudioOut { public: /// Opens a new audio stream - StreamPtr OpenStream(int sample_rate, int num_channels, + StreamPtr OpenStream(u32 sample_rate, u32 num_channels, Stream::ReleaseCallback&& release_callback); /// Returns a vector of recently released buffers specified by tag for the specified stream @@ -37,8 +36,7 @@ public: bool QueueBuffer(StreamPtr stream, Buffer::Tag tag, std::vector<u8>&& data); private: - /// Active audio streams on the interface - std::vector<StreamPtr> streams; + SinkPtr sink; }; } // namespace AudioCore diff --git a/src/audio_core/buffer.h b/src/audio_core/buffer.h index 874ec787e..4bf5fd58a 100644 --- a/src/audio_core/buffer.h +++ b/src/audio_core/buffer.h @@ -4,6 +4,7 @@ #pragma once +#include <memory> #include <vector> #include "common/common_types.h" @@ -34,4 +35,6 @@ private: std::vector<u8> data; }; +using BufferPtr = std::shared_ptr<Buffer>; + } // namespace AudioCore diff --git a/src/audio_core/cubeb_sink.cpp b/src/audio_core/cubeb_sink.cpp new file mode 100644 index 000000000..34ae5b062 --- /dev/null +++ b/src/audio_core/cubeb_sink.cpp @@ -0,0 +1,190 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <algorithm> +#include <cstring> + +#include "audio_core/cubeb_sink.h" +#include "audio_core/stream.h" +#include "common/logging/log.h" + +namespace AudioCore { + +class SinkStreamImpl final : public SinkStream { +public: + SinkStreamImpl(cubeb* ctx, cubeb_devid output_device) : ctx{ctx} { + cubeb_stream_params params; + params.rate = 48000; + params.channels = GetNumChannels(); + params.format = CUBEB_SAMPLE_S16NE; + params.layout = CUBEB_LAYOUT_STEREO; + + u32 minimum_latency = 0; + if (cubeb_get_min_latency(ctx, ¶ms, &minimum_latency) != CUBEB_OK) { + LOG_CRITICAL(Audio_Sink, "Error getting minimum latency"); + } + + if (cubeb_stream_init(ctx, &stream_backend, "yuzu Audio Output", nullptr, nullptr, + output_device, ¶ms, std::max(512u, minimum_latency), + &SinkStreamImpl::DataCallback, &SinkStreamImpl::StateCallback, + this) != CUBEB_OK) { + LOG_CRITICAL(Audio_Sink, "Error initializing cubeb stream"); + return; + } + + if (cubeb_stream_start(stream_backend) != CUBEB_OK) { + LOG_CRITICAL(Audio_Sink, "Error starting cubeb stream"); + return; + } + } + + ~SinkStreamImpl() { + if (!ctx) { + return; + } + + if (cubeb_stream_stop(stream_backend) != CUBEB_OK) { + LOG_CRITICAL(Audio_Sink, "Error stopping cubeb stream"); + } + + cubeb_stream_destroy(stream_backend); + } + + void EnqueueSamples(u32 num_channels, const s16* samples, size_t sample_count) override { + if (!ctx) { + return; + } + + queue.reserve(queue.size() + sample_count * GetNumChannels()); + + if (num_channels == 2) { + // Copy as-is + std::copy(samples, samples + sample_count * GetNumChannels(), + std::back_inserter(queue)); + } else if (num_channels == 6) { + // Downsample 6 channels to 2 + const size_t sample_count_copy_size = sample_count * num_channels * 2; + queue.reserve(sample_count_copy_size); + for (size_t i = 0; i < sample_count * num_channels; i += num_channels) { + queue.push_back(samples[i]); + queue.push_back(samples[i + 1]); + } + } else { + ASSERT_MSG(false, "Unimplemented"); + } + } + + u32 GetNumChannels() const { + // Only support 2-channel stereo output for now + return 2; + } + +private: + std::vector<std::string> device_list; + + cubeb* ctx{}; + cubeb_stream* stream_backend{}; + + std::vector<s16> queue; + + static long DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer, + void* output_buffer, long num_frames); + static void StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state); +}; + +CubebSink::CubebSink(std::string target_device_name) { + if (cubeb_init(&ctx, "yuzu", nullptr) != CUBEB_OK) { + LOG_CRITICAL(Audio_Sink, "cubeb_init failed"); + return; + } + + if (target_device_name != auto_device_name && !target_device_name.empty()) { + cubeb_device_collection collection; + if (cubeb_enumerate_devices(ctx, CUBEB_DEVICE_TYPE_OUTPUT, &collection) != CUBEB_OK) { + LOG_WARNING(Audio_Sink, "Audio output device enumeration not supported"); + } else { + const auto collection_end{collection.device + collection.count}; + const auto device{std::find_if(collection.device, collection_end, + [&](const cubeb_device_info& device) { + return target_device_name == device.friendly_name; + })}; + if (device != collection_end) { + output_device = device->devid; + } + cubeb_device_collection_destroy(ctx, &collection); + } + } +} + +CubebSink::~CubebSink() { + if (!ctx) { + return; + } + + for (auto& sink_stream : sink_streams) { + sink_stream.reset(); + } + + cubeb_destroy(ctx); +} + +SinkStream& CubebSink::AcquireSinkStream(u32 sample_rate, u32 num_channels) { + sink_streams.push_back(std::make_unique<SinkStreamImpl>(ctx, output_device)); + return *sink_streams.back(); +} + +long SinkStreamImpl::DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer, + void* output_buffer, long num_frames) { + SinkStreamImpl* impl = static_cast<SinkStreamImpl*>(user_data); + u8* buffer = reinterpret_cast<u8*>(output_buffer); + + if (!impl) { + return {}; + } + + const size_t frames_to_write{ + std::min(impl->queue.size() / impl->GetNumChannels(), static_cast<size_t>(num_frames))}; + + memcpy(buffer, impl->queue.data(), frames_to_write * sizeof(s16) * impl->GetNumChannels()); + impl->queue.erase(impl->queue.begin(), + impl->queue.begin() + frames_to_write * impl->GetNumChannels()); + + if (frames_to_write < num_frames) { + // Fill the rest of the frames with silence + memset(buffer + frames_to_write * sizeof(s16) * impl->GetNumChannels(), 0, + (num_frames - frames_to_write) * sizeof(s16) * impl->GetNumChannels()); + } + + return num_frames; +} + +void SinkStreamImpl::StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state) {} + +std::vector<std::string> ListCubebSinkDevices() { + std::vector<std::string> device_list; + cubeb* ctx; + + if (cubeb_init(&ctx, "Citra Device Enumerator", nullptr) != CUBEB_OK) { + LOG_CRITICAL(Audio_Sink, "cubeb_init failed"); + return {}; + } + + cubeb_device_collection collection; + if (cubeb_enumerate_devices(ctx, CUBEB_DEVICE_TYPE_OUTPUT, &collection) != CUBEB_OK) { + LOG_WARNING(Audio_Sink, "Audio output device enumeration not supported"); + } else { + for (size_t i = 0; i < collection.count; i++) { + const cubeb_device_info& device = collection.device[i]; + if (device.friendly_name) { + device_list.emplace_back(device.friendly_name); + } + } + cubeb_device_collection_destroy(ctx, &collection); + } + + cubeb_destroy(ctx); + return device_list; +} + +} // namespace AudioCore diff --git a/src/audio_core/cubeb_sink.h b/src/audio_core/cubeb_sink.h new file mode 100644 index 000000000..d07113f1f --- /dev/null +++ b/src/audio_core/cubeb_sink.h @@ -0,0 +1,31 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <string> +#include <vector> + +#include <cubeb/cubeb.h> + +#include "audio_core/sink.h" + +namespace AudioCore { + +class CubebSink final : public Sink { +public: + explicit CubebSink(std::string device_id); + ~CubebSink() override; + + SinkStream& AcquireSinkStream(u32 sample_rate, u32 num_channels) override; + +private: + cubeb* ctx{}; + cubeb_devid output_device{}; + std::vector<SinkStreamPtr> sink_streams; +}; + +std::vector<std::string> ListCubebSinkDevices(); + +} // namespace AudioCore diff --git a/src/audio_core/null_sink.h b/src/audio_core/null_sink.h new file mode 100644 index 000000000..2e04438f7 --- /dev/null +++ b/src/audio_core/null_sink.h @@ -0,0 +1,27 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "audio_core/sink.h" + +namespace AudioCore { + +class NullSink final : public Sink { +public: + explicit NullSink(std::string){}; + ~NullSink() override = default; + + SinkStream& AcquireSinkStream(u32 /*sample_rate*/, u32 /*num_channels*/) override { + return null_sink_stream; + } + +private: + struct NullSinkStreamImpl final : SinkStream { + void EnqueueSamples(u32 /*num_channels*/, const s16* /*samples*/, + size_t /*sample_count*/) override {} + } null_sink_stream; +}; + +} // namespace AudioCore diff --git a/src/audio_core/sink.h b/src/audio_core/sink.h new file mode 100644 index 000000000..d1bb98c3d --- /dev/null +++ b/src/audio_core/sink.h @@ -0,0 +1,29 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> + +#include "audio_core/sink_stream.h" +#include "common/common_types.h" + +namespace AudioCore { + +constexpr char auto_device_name[] = "auto"; + +/** + * This class is an interface for an audio sink. An audio sink accepts samples in stereo signed + * PCM16 format to be output. Sinks *do not* handle resampling and expect the correct sample rate. + * They are dumb outputs. + */ +class Sink { +public: + virtual ~Sink() = default; + virtual SinkStream& AcquireSinkStream(u32 sample_rate, u32 num_channels) = 0; +}; + +using SinkPtr = std::unique_ptr<Sink>; + +} // namespace AudioCore diff --git a/src/audio_core/sink_details.cpp b/src/audio_core/sink_details.cpp new file mode 100644 index 000000000..955ba20fb --- /dev/null +++ b/src/audio_core/sink_details.cpp @@ -0,0 +1,44 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <algorithm> +#include <memory> +#include <string> +#include <vector> +#include "audio_core/null_sink.h" +#include "audio_core/sink_details.h" +#ifdef HAVE_CUBEB +#include "audio_core/cubeb_sink.h" +#endif +#include "common/logging/log.h" + +namespace AudioCore { + +// g_sink_details is ordered in terms of desirability, with the best choice at the top. +const std::vector<SinkDetails> g_sink_details = { +#ifdef HAVE_CUBEB + SinkDetails{"cubeb", &std::make_unique<CubebSink, std::string>, &ListCubebSinkDevices}, +#endif + SinkDetails{"null", &std::make_unique<NullSink, std::string>, + [] { return std::vector<std::string>{"null"}; }}, +}; + +const SinkDetails& GetSinkDetails(std::string sink_id) { + auto iter = + std::find_if(g_sink_details.begin(), g_sink_details.end(), + [sink_id](const auto& sink_detail) { return sink_detail.id == sink_id; }); + + if (sink_id == "auto" || iter == g_sink_details.end()) { + if (sink_id != "auto") { + LOG_ERROR(Audio, "AudioCore::SelectSink given invalid sink_id {}", sink_id); + } + // Auto-select. + // g_sink_details is ordered in terms of desirability, with the best choice at the front. + iter = g_sink_details.begin(); + } + + return *iter; +} + +} // namespace AudioCore diff --git a/src/audio_core/sink_details.h b/src/audio_core/sink_details.h new file mode 100644 index 000000000..aa8aae1a9 --- /dev/null +++ b/src/audio_core/sink_details.h @@ -0,0 +1,32 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <functional> +#include <memory> +#include <vector> + +namespace AudioCore { + +class Sink; + +struct SinkDetails { + SinkDetails(const char* id_, std::function<std::unique_ptr<Sink>(std::string)> factory_, + std::function<std::vector<std::string>()> list_devices_) + : id(id_), factory(factory_), list_devices(list_devices_) {} + + /// Name for this sink. + const char* id; + /// A method to call to construct an instance of this type of sink. + std::function<std::unique_ptr<Sink>(std::string device_id)> factory; + /// A method to call to list available devices. + std::function<std::vector<std::string>()> list_devices; +}; + +extern const std::vector<SinkDetails> g_sink_details; + +const SinkDetails& GetSinkDetails(std::string sink_id); + +} // namespace AudioCore diff --git a/src/audio_core/sink_stream.h b/src/audio_core/sink_stream.h new file mode 100644 index 000000000..e7a3f01b0 --- /dev/null +++ b/src/audio_core/sink_stream.h @@ -0,0 +1,32 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> + +#include "common/common_types.h" + +namespace AudioCore { + +/** + * Accepts samples in stereo signed PCM16 format to be output. Sinks *do not* handle resampling and + * expect the correct sample rate. They are dumb outputs. + */ +class SinkStream { +public: + virtual ~SinkStream() = default; + + /** + * Feed stereo samples to sink. + * @param num_channels Number of channels used. + * @param samples Samples in interleaved stereo PCM16 format. + * @param sample_count Number of samples. + */ + virtual void EnqueueSamples(u32 num_channels, const s16* samples, size_t sample_count) = 0; +}; + +using SinkStreamPtr = std::unique_ptr<SinkStream>; + +} // namespace AudioCore diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp index 82bff4b9e..689f51a1d 100644 --- a/src/audio_core/stream.cpp +++ b/src/audio_core/stream.cpp @@ -7,30 +7,37 @@ #include "core/core_timing.h" #include "core/core_timing_util.h" +#include "audio_core/sink.h" +#include "audio_core/sink_details.h" #include "audio_core/stream.h" namespace AudioCore { constexpr size_t MaxAudioBufferCount{32}; -/// Returns the sample size for the specified audio stream format -static size_t SampleSizeFromFormat(Stream::Format format) { +u32 Stream::GetNumChannels() const { switch (format) { - case Stream::Format::Mono16: + case Format::Mono16: + return 1; + case Format::Stereo16: return 2; - case Stream::Format::Stereo16: - return 4; - case Stream::Format::Multi51Channel16: - return 12; - }; - + case Format::Multi51Channel16: + return 6; + } LOG_CRITICAL(Audio, "Unimplemented format={}", static_cast<u32>(format)); UNREACHABLE(); return {}; } -Stream::Stream(int sample_rate, Format format, ReleaseCallback&& release_callback) - : sample_rate{sample_rate}, format{format}, release_callback{std::move(release_callback)} { +u32 Stream::GetSampleSize() const { + return GetNumChannels() * 2; +} + +Stream::Stream(u32 sample_rate, Format format, ReleaseCallback&& release_callback, + SinkStream& sink_stream) + : sample_rate{sample_rate}, format{format}, release_callback{std::move(release_callback)}, + sink_stream{sink_stream} { + release_event = CoreTiming::RegisterEvent( "Stream::Release", [this](u64 userdata, int cycles_late) { ReleaseActiveBuffer(); }); } @@ -45,7 +52,7 @@ void Stream::Stop() { } s64 Stream::GetBufferReleaseCycles(const Buffer& buffer) const { - const size_t num_samples{buffer.GetData().size() / SampleSizeFromFormat(format)}; + const size_t num_samples{buffer.GetData().size() / GetSampleSize()}; return CoreTiming::usToCycles((static_cast<u64>(num_samples) * 1000000) / sample_rate); } @@ -68,6 +75,10 @@ void Stream::PlayNextBuffer() { active_buffer = queued_buffers.front(); queued_buffers.pop(); + sink_stream.EnqueueSamples(GetNumChannels(), + reinterpret_cast<const s16*>(active_buffer->GetData().data()), + active_buffer->GetData().size() / GetSampleSize()); + CoreTiming::ScheduleEventThreadsafe(GetBufferReleaseCycles(*active_buffer), release_event, {}); } diff --git a/src/audio_core/stream.h b/src/audio_core/stream.h index 5f43b0798..35253920e 100644 --- a/src/audio_core/stream.h +++ b/src/audio_core/stream.h @@ -10,14 +10,13 @@ #include <queue> #include "audio_core/buffer.h" +#include "audio_core/sink_stream.h" #include "common/assert.h" #include "common/common_types.h" #include "core/core_timing.h" namespace AudioCore { -using BufferPtr = std::shared_ptr<Buffer>; - /** * Represents an audio stream, which is a sequence of queued buffers, to be outputed by AudioOut */ @@ -33,7 +32,8 @@ public: /// Callback function type, used to change guest state on a buffer being released using ReleaseCallback = std::function<void()>; - Stream(int sample_rate, Format format, ReleaseCallback&& release_callback); + Stream(u32 sample_rate, Format format, ReleaseCallback&& release_callback, + SinkStream& sink_stream); /// Plays the audio stream void Play(); @@ -60,6 +60,17 @@ public: return queued_buffers.size(); } + /// Gets the sample rate + u32 GetSampleRate() const { + return sample_rate; + } + + /// Gets the number of channels + u32 GetNumChannels() const; + + /// Gets the sample size in bytes + u32 GetSampleSize() const; + private: /// Current state of the stream enum class State { @@ -76,7 +87,7 @@ private: /// Gets the number of core cycles when the specified buffer will be released s64 GetBufferReleaseCycles(const Buffer& buffer) const; - int sample_rate; ///< Sample rate of the stream + u32 sample_rate; ///< Sample rate of the stream Format format; ///< Format of the stream ReleaseCallback release_callback; ///< Buffer release callback for the stream State state{State::Stopped}; ///< Playback state of the stream @@ -84,6 +95,9 @@ private: BufferPtr active_buffer; ///< Actively playing buffer in the stream std::queue<BufferPtr> queued_buffers; ///< Buffers queued to be played in the stream std::queue<BufferPtr> released_buffers; ///< Buffers recently released from the stream + SinkStream& sink_stream; ///< Output sink for the stream }; +using StreamPtr = std::shared_ptr<Stream>; + } // namespace AudioCore diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h index 93f1c0044..8b0d34da6 100644 --- a/src/common/common_funcs.h +++ b/src/common/common_funcs.h @@ -6,7 +6,7 @@ #include <string> -#if !defined(ARCHITECTURE_x86_64) && !defined(ARCHITECTURE_ARM) +#if !defined(ARCHITECTURE_x86_64) #include <cstdlib> // for exit #endif #include "common/common_types.h" @@ -32,8 +32,6 @@ #ifdef ARCHITECTURE_x86_64 #define Crash() __asm__ __volatile__("int $3") -#elif defined(ARCHITECTURE_ARM) -#define Crash() __asm__ __volatile__("trap") #else #define Crash() exit(1) #endif diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 38cc85e23..d86c40d26 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp @@ -169,7 +169,9 @@ void FileBackend::Write(const Entry& entry) { SUB(Service, AOC) \ SUB(Service, APM) \ SUB(Service, BCAT) \ + SUB(Service, BTM) \ SUB(Service, Fatal) \ + SUB(Service, FGM) \ SUB(Service, Friend) \ SUB(Service, FS) \ SUB(Service, HID) \ @@ -184,6 +186,7 @@ void FileBackend::Write(const Entry& entry) { SUB(Service, NIFM) \ SUB(Service, NS) \ SUB(Service, NVDRV) \ + SUB(Service, PCIE) \ SUB(Service, PCTL) \ SUB(Service, PREPO) \ SUB(Service, SET) \ @@ -192,6 +195,7 @@ void FileBackend::Write(const Entry& entry) { SUB(Service, SSL) \ SUB(Service, Time) \ SUB(Service, VI) \ + SUB(Service, WLAN) \ CLS(HW) \ SUB(HW, Memory) \ SUB(HW, LCD) \ diff --git a/src/common/logging/log.h b/src/common/logging/log.h index db4a80d0a..140cd8e47 100644 --- a/src/common/logging/log.h +++ b/src/common/logging/log.h @@ -56,7 +56,9 @@ enum class Class : ClassType { Service_APM, ///< The APM (Performance) service Service_Audio, ///< The Audio (Audio control) service Service_BCAT, ///< The BCAT service + Service_BTM, ///< The BTM service Service_Fatal, ///< The Fatal service + Service_FGM, ///< The FGM service Service_Friend, ///< The friend service Service_FS, ///< The FS (Filesystem) service Service_HID, ///< The HID (Human interface device) service @@ -71,6 +73,7 @@ enum class Class : ClassType { Service_NIFM, ///< The NIFM (Network interface) service Service_NS, ///< The NS services Service_NVDRV, ///< The NVDRV (Nvidia driver) service + Service_PCIE, ///< The PCIe service Service_PCTL, ///< The PCTL (Parental control) service Service_PREPO, ///< The PREPO (Play report) service Service_SET, ///< The SET (Settings) service @@ -79,6 +82,7 @@ enum class Class : ClassType { Service_SSL, ///< The SSL service Service_Time, ///< The time service Service_VI, ///< The VI (Video interface) service + Service_WLAN, ///< The WLAN (Wireless local area network) service HW, ///< Low-level hardware emulation HW_Memory, ///< Memory-map and address translation HW_LCD, ///< LCD register emulation diff --git a/src/common/logging/text_formatter.h b/src/common/logging/text_formatter.h index c587faefb..9609cec7c 100644 --- a/src/common/logging/text_formatter.h +++ b/src/common/logging/text_formatter.h @@ -5,6 +5,7 @@ #pragma once #include <cstddef> +#include <string> namespace Log { diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index 1f0456aee..0ca663032 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp @@ -2,12 +2,12 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <algorithm> #include <cctype> #include <cerrno> #include <cstdio> #include <cstdlib> #include <cstring> -#include <boost/range/algorithm/transform.hpp> #include "common/common_paths.h" #include "common/logging/log.h" #include "common/string_util.h" @@ -24,13 +24,15 @@ namespace Common { /// Make a string lowercase std::string ToLower(std::string str) { - boost::transform(str, str.begin(), ::tolower); + std::transform(str.begin(), str.end(), str.begin(), + [](unsigned char c) { return std::tolower(c); }); return str; } /// Make a string uppercase std::string ToUpper(std::string str) { - boost::transform(str, str.begin(), ::toupper); + std::transform(str.begin(), str.end(), str.begin(), + [](unsigned char c) { return std::toupper(c); }); return str; } diff --git a/src/common/swap.h b/src/common/swap.h index fc7af4280..32af0b6ac 100644 --- a/src/common/swap.h +++ b/src/common/swap.h @@ -69,7 +69,7 @@ inline u32 swap32(u32 _data) { inline u64 swap64(u64 _data) { return _byteswap_uint64(_data); } -#elif ARCHITECTURE_ARM +#elif defined(ARCHITECTURE_ARM) && (__ARM_ARCH >= 6) inline u16 swap16(u16 _data) { u32 data = _data; __asm__("rev16 %0, %1\n" : "=l"(data) : "l"(data)); diff --git a/src/common/timer.cpp b/src/common/timer.cpp index f0c5b1a43..2dc15e434 100644 --- a/src/common/timer.cpp +++ b/src/common/timer.cpp @@ -3,31 +3,16 @@ // Refer to the license.txt file included. #include <ctime> - #include <fmt/format.h> - -#ifdef _WIN32 -#include <windows.h> -// windows.h needs to be included before other windows headers -#include <mmsystem.h> -#include <sys/timeb.h> -#else -#include <sys/time.h> -#endif #include "common/common_types.h" #include "common/string_util.h" #include "common/timer.h" namespace Common { -u32 Timer::GetTimeMs() { -#ifdef _WIN32 - return timeGetTime(); -#else - struct timeval t; - (void)gettimeofday(&t, nullptr); - return ((u32)(t.tv_sec * 1000 + t.tv_usec / 1000)); -#endif +std::chrono::milliseconds Timer::GetTimeMs() { + return std::chrono::duration_cast<std::chrono::milliseconds>( + std::chrono::system_clock::now().time_since_epoch()); } // -------------------------------------------- @@ -63,7 +48,7 @@ void Timer::Update() { // ------------------------------------- // Get the number of milliseconds since the last Update() -u64 Timer::GetTimeDifference() { +std::chrono::milliseconds Timer::GetTimeDifference() { return GetTimeMs() - m_LastTime; } @@ -74,11 +59,11 @@ void Timer::AddTimeDifference() { } // Get the time elapsed since the Start() -u64 Timer::GetTimeElapsed() { +std::chrono::milliseconds Timer::GetTimeElapsed() { // If we have not started yet, return 1 (because then I don't // have to change the FPS calculation in CoreRerecording.cpp . - if (m_StartTime == 0) - return 1; + if (m_StartTime.count() == 0) + return std::chrono::milliseconds(1); // Return the final timer time if the timer is stopped if (!m_Running) @@ -90,49 +75,34 @@ u64 Timer::GetTimeElapsed() { // Get the formatted time elapsed since the Start() std::string Timer::GetTimeElapsedFormatted() const { // If we have not started yet, return zero - if (m_StartTime == 0) + if (m_StartTime.count() == 0) return "00:00:00:000"; // The number of milliseconds since the start. // Use a different value if the timer is stopped. - u64 Milliseconds; + std::chrono::milliseconds Milliseconds; if (m_Running) Milliseconds = GetTimeMs() - m_StartTime; else Milliseconds = m_LastTime - m_StartTime; // Seconds - u32 Seconds = (u32)(Milliseconds / 1000); + std::chrono::seconds Seconds = std::chrono::duration_cast<std::chrono::seconds>(Milliseconds); // Minutes - u32 Minutes = Seconds / 60; + std::chrono::minutes Minutes = std::chrono::duration_cast<std::chrono::minutes>(Milliseconds); // Hours - u32 Hours = Minutes / 60; + std::chrono::hours Hours = std::chrono::duration_cast<std::chrono::hours>(Milliseconds); - std::string TmpStr = fmt::format("{:02}:{:02}:{:02}:{:03}", Hours, Minutes % 60, Seconds % 60, - Milliseconds % 1000); + std::string TmpStr = fmt::format("{:02}:{:02}:{:02}:{:03}", Hours.count(), Minutes.count() % 60, + Seconds.count() % 60, Milliseconds.count() % 1000); return TmpStr; } -// Get current time -void Timer::IncreaseResolution() { -#ifdef _WIN32 - timeBeginPeriod(1); -#endif -} - -void Timer::RestoreResolution() { -#ifdef _WIN32 - timeEndPeriod(1); -#endif -} - // Get the number of seconds since January 1 1970 -u64 Timer::GetTimeSinceJan1970() { - time_t ltime; - time(<ime); - return ((u64)ltime); +std::chrono::seconds Timer::GetTimeSinceJan1970() { + return std::chrono::duration_cast<std::chrono::seconds>(GetTimeMs()); } -u64 Timer::GetLocalTimeSinceJan1970() { +std::chrono::seconds Timer::GetLocalTimeSinceJan1970() { time_t sysTime, tzDiff, tzDST; struct tm* gmTime; @@ -149,7 +119,7 @@ u64 Timer::GetLocalTimeSinceJan1970() { gmTime = gmtime(&sysTime); tzDiff = sysTime - mktime(gmTime); - return (u64)(sysTime + tzDiff + tzDST); + return std::chrono::seconds(sysTime + tzDiff + tzDST); } // Return the current time formatted as Minutes:Seconds:Milliseconds @@ -164,30 +134,16 @@ std::string Timer::GetTimeFormatted() { strftime(tmp, 6, "%M:%S", gmTime); -// Now tack on the milliseconds -#ifdef _WIN32 - struct timeb tp; - (void)::ftime(&tp); - return fmt::format("{}:{:03}", tmp, tp.millitm); -#else - struct timeval t; - (void)gettimeofday(&t, nullptr); - return fmt::format("{}:{:03}", tmp, static_cast<int>(t.tv_usec / 1000)); -#endif + u64 milliseconds = static_cast<u64>(GetTimeMs().count()) % 1000; + return fmt::format("{}:{:03}", tmp, milliseconds); } // Returns a timestamp with decimals for precise time comparisons // ---------------- double Timer::GetDoubleTime() { -#ifdef _WIN32 - struct timeb tp; - (void)::ftime(&tp); -#else - struct timeval t; - (void)gettimeofday(&t, nullptr); -#endif // Get continuous timestamp - u64 TmpSeconds = Common::Timer::GetTimeSinceJan1970(); + u64 TmpSeconds = static_cast<u64>(Common::Timer::GetTimeSinceJan1970().count()); + double ms = static_cast<u64>(GetTimeMs().count()) % 1000; // Remove a few years. We only really want enough seconds to make // sure that we are detecting actual actions, perhaps 60 seconds is @@ -196,12 +152,7 @@ double Timer::GetDoubleTime() { TmpSeconds = TmpSeconds - (38 * 365 * 24 * 60 * 60); // Make a smaller integer that fits in the double - u32 Seconds = (u32)TmpSeconds; -#ifdef _WIN32 - double ms = tp.millitm / 1000.0 / 1000.0; -#else - double ms = t.tv_usec / 1000000.0; -#endif + u32 Seconds = static_cast<u32>(TmpSeconds); double TmpTime = Seconds + ms; return TmpTime; diff --git a/src/common/timer.h b/src/common/timer.h index 78d37426b..27b521baa 100644 --- a/src/common/timer.h +++ b/src/common/timer.h @@ -4,6 +4,7 @@ #pragma once +#include <chrono> #include <string> #include "common/common_types.h" @@ -18,24 +19,22 @@ public: // The time difference is always returned in milliseconds, regardless of alternative internal // representation - u64 GetTimeDifference(); + std::chrono::milliseconds GetTimeDifference(); void AddTimeDifference(); - static void IncreaseResolution(); - static void RestoreResolution(); - static u64 GetTimeSinceJan1970(); - static u64 GetLocalTimeSinceJan1970(); + static std::chrono::seconds GetTimeSinceJan1970(); + static std::chrono::seconds GetLocalTimeSinceJan1970(); static double GetDoubleTime(); static std::string GetTimeFormatted(); std::string GetTimeElapsedFormatted() const; - u64 GetTimeElapsed(); + std::chrono::milliseconds GetTimeElapsed(); - static u32 GetTimeMs(); + static std::chrono::milliseconds GetTimeMs(); private: - u64 m_LastTime; - u64 m_StartTime; + std::chrono::milliseconds m_LastTime; + std::chrono::milliseconds m_StartTime; bool m_Running; }; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index f1e7e2593..3e13fc25b 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -114,6 +114,12 @@ add_library(core STATIC hle/service/am/applet_ae.h hle/service/am/applet_oe.cpp hle/service/am/applet_oe.h + hle/service/am/idle.cpp + hle/service/am/idle.h + hle/service/am/omm.cpp + hle/service/am/omm.h + hle/service/am/spsm.cpp + hle/service/am/spsm.h hle/service/aoc/aoc_u.cpp hle/service/aoc/aoc_u.h hle/service/apm/apm.cpp @@ -142,6 +148,8 @@ add_library(core STATIC hle/service/bcat/module.h hle/service/btdrv/btdrv.cpp hle/service/btdrv/btdrv.h + hle/service/btm/btm.cpp + hle/service/btm/btm.h hle/service/erpt/erpt.cpp hle/service/erpt/erpt.h hle/service/es/es.cpp @@ -158,6 +166,8 @@ add_library(core STATIC hle/service/filesystem/filesystem.h hle/service/filesystem/fsp_srv.cpp hle/service/filesystem/fsp_srv.h + hle/service/fgm/fgm.cpp + hle/service/fgm/fgm.h hle/service/friend/friend.cpp hle/service/friend/friend.h hle/service/friend/interface.cpp @@ -223,6 +233,8 @@ add_library(core STATIC hle/service/nvflinger/buffer_queue.h hle/service/nvflinger/nvflinger.cpp hle/service/nvflinger/nvflinger.h + hle/service/pcie/pcie.cpp + hle/service/pcie/pcie.h hle/service/pctl/module.cpp hle/service/pctl/module.h hle/service/pctl/pctl.cpp @@ -277,6 +289,8 @@ add_library(core STATIC hle/service/vi/vi_s.h hle/service/vi/vi_u.cpp hle/service/vi/vi_u.h + hle/service/wlan/wlan.cpp + hle/service/wlan/wlan.h hw/hw.cpp hw/hw.h hw/lcd.cpp @@ -314,7 +328,7 @@ add_library(core STATIC create_target_directory_groups(core) target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) -target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt lz4_static unicorn) +target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt lz4_static opus unicorn) if (ARCHITECTURE_x86_64) target_sources(core PRIVATE diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index 57b8634b9..1d8c15d97 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -139,14 +139,12 @@ void ARM_Dynarmic::Step() { } ARM_Dynarmic::ARM_Dynarmic(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, size_t core_index) - : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), - jit(MakeJit()), exclusive_monitor{std::dynamic_pointer_cast<DynarmicExclusiveMonitor>( - exclusive_monitor)}, - core_index{core_index} { - ARM_Interface::ThreadContext ctx; + : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), core_index{core_index}, + exclusive_monitor{std::dynamic_pointer_cast<DynarmicExclusiveMonitor>(exclusive_monitor)} { + ThreadContext ctx; inner_unicorn.SaveContext(ctx); - LoadContext(ctx); PageTableChanged(); + LoadContext(ctx); } ARM_Dynarmic::~ARM_Dynarmic() = default; @@ -205,7 +203,7 @@ u64 ARM_Dynarmic::GetTlsAddress() const { return cb->tpidrro_el0; } -void ARM_Dynarmic::SetTlsAddress(u64 address) { +void ARM_Dynarmic::SetTlsAddress(VAddr address) { cb->tpidrro_el0 = address; } @@ -217,7 +215,7 @@ void ARM_Dynarmic::SetTPIDR_EL0(u64 value) { cb->tpidr_el0 = value; } -void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& ctx) { +void ARM_Dynarmic::SaveContext(ThreadContext& ctx) { ctx.cpu_registers = jit->GetRegisters(); ctx.sp = jit->GetSP(); ctx.pc = jit->GetPC(); @@ -226,7 +224,7 @@ void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& ctx) { ctx.fpscr = jit->GetFpcr(); } -void ARM_Dynarmic::LoadContext(const ARM_Interface::ThreadContext& ctx) { +void ARM_Dynarmic::LoadContext(const ThreadContext& ctx) { jit->SetRegisters(ctx.cpu_registers); jit->SetSP(ctx.sp); jit->SetPC(ctx.pc); diff --git a/src/core/core.cpp b/src/core/core.cpp index 186fa46df..b7f4b4532 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -177,7 +177,6 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) { } gpu_core = std::make_unique<Tegra::GPU>(); - audio_core = std::make_unique<AudioCore::AudioOut>(); telemetry_session = std::make_unique<Core::TelemetrySession>(); service_manager = std::make_shared<Service::SM::ServiceManager>(); @@ -229,7 +228,6 @@ void System::Shutdown() { service_manager.reset(); telemetry_session.reset(); gpu_core.reset(); - audio_core.reset(); // Close all CPU/threading state cpu_barrier->NotifyEnd(); diff --git a/src/core/core.h b/src/core/core.h index 6f4df775f..c123fe401 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -8,7 +8,6 @@ #include <memory> #include <string> #include <thread> -#include "audio_core/audio_out.h" #include "common/common_types.h" #include "core/arm/exclusive_monitor.h" #include "core/core_cpu.h" @@ -132,11 +131,6 @@ public: return *gpu_core; } - /// Gets the AudioCore interface - AudioCore::AudioOut& AudioCore() { - return *audio_core; - } - /// Gets the scheduler for the CPU core that is currently running Kernel::Scheduler& CurrentScheduler() { return *CurrentCpuCore().Scheduler(); @@ -201,7 +195,6 @@ private: /// AppLoader used to load the current executing application std::unique_ptr<Loader::AppLoader> app_loader; std::unique_ptr<Tegra::GPU> gpu_core; - std::unique_ptr<AudioCore::AudioOut> audio_core; std::shared_ptr<Tegra::DebugContext> debug_context; Kernel::SharedPtr<Kernel::Process> current_process; std::shared_ptr<ExclusiveMonitor> cpu_exclusive_monitor; diff --git a/src/core/file_sys/partition_filesystem.cpp b/src/core/file_sys/partition_filesystem.cpp index 521e21078..47e032b19 100644 --- a/src/core/file_sys/partition_filesystem.cpp +++ b/src/core/file_sys/partition_filesystem.cpp @@ -97,9 +97,8 @@ void PartitionFilesystem::PrintDebugInfo() const { LOG_DEBUG(Service_FS, "Magic: {:.4}", pfs_header.magic); LOG_DEBUG(Service_FS, "Files: {}", pfs_header.num_entries); for (u32 i = 0; i < pfs_header.num_entries; i++) { - LOG_DEBUG(Service_FS, " > File {}: {} (0x{:X} bytes, at 0x{:X})", i, - pfs_files[i]->GetName(), pfs_files[i]->GetSize(), - dynamic_cast<OffsetVfsFile*>(pfs_files[i].get())->GetOffset()); + LOG_DEBUG(Service_FS, " > File {}: {} (0x{:X} bytes)", i, + pfs_files[i]->GetName(), pfs_files[i]->GetSize()); } } diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 97ef07bf9..94d2a973d 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -11,6 +11,9 @@ #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_ae.h" #include "core/hle/service/am/applet_oe.h" +#include "core/hle/service/am/idle.h" +#include "core/hle/service/am/omm.h" +#include "core/hle/service/am/spsm.h" #include "core/hle/service/apm/apm.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/nvflinger/nvflinger.h" @@ -689,6 +692,9 @@ void InstallInterfaces(SM::ServiceManager& service_manager, std::shared_ptr<NVFlinger::NVFlinger> nvflinger) { std::make_shared<AppletAE>(nvflinger)->InstallAsService(service_manager); std::make_shared<AppletOE>(nvflinger)->InstallAsService(service_manager); + std::make_shared<IdleSys>()->InstallAsService(service_manager); + std::make_shared<OMM>()->InstallAsService(service_manager); + std::make_shared<SPSM>()->InstallAsService(service_manager); } IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions") { diff --git a/src/core/hle/service/am/idle.cpp b/src/core/hle/service/am/idle.cpp new file mode 100644 index 000000000..af46e9494 --- /dev/null +++ b/src/core/hle/service/am/idle.cpp @@ -0,0 +1,24 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/am/idle.h" + +namespace Service::AM { + +IdleSys::IdleSys() : ServiceFramework{"idle:sys"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetAutoPowerDownEvent"}, + {1, nullptr, "Unknown1"}, + {2, nullptr, "Unknown2"}, + {3, nullptr, "Unknown3"}, + {4, nullptr, "Unknown4"}, + {5, nullptr, "Unknown5"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/idle.h b/src/core/hle/service/am/idle.h new file mode 100644 index 000000000..1eb68d2c9 --- /dev/null +++ b/src/core/hle/service/am/idle.h @@ -0,0 +1,16 @@ +// 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::AM { + +class IdleSys final : public ServiceFramework<IdleSys> { +public: + explicit IdleSys(); +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/omm.cpp b/src/core/hle/service/am/omm.cpp new file mode 100644 index 000000000..447fe8669 --- /dev/null +++ b/src/core/hle/service/am/omm.cpp @@ -0,0 +1,42 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/am/omm.h" + +namespace Service::AM { + +OMM::OMM() : ServiceFramework{"omm"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetOperationMode"}, + {1, nullptr, "GetOperationModeChangeEvent"}, + {2, nullptr, "EnableAudioVisual"}, + {3, nullptr, "DisableAudioVisual"}, + {4, nullptr, "EnterSleepAndWait"}, + {5, nullptr, "GetCradleStatus"}, + {6, nullptr, "FadeInDisplay"}, + {7, nullptr, "FadeOutDisplay"}, + {8, nullptr, "Unknown1"}, + {9, nullptr, "Unknown2"}, + {10, nullptr, "Unknown3"}, + {11, nullptr, "Unknown4"}, + {12, nullptr, "Unknown5"}, + {13, nullptr, "Unknown6"}, + {14, nullptr, "Unknown7"}, + {15, nullptr, "Unknown8"}, + {16, nullptr, "Unknown9"}, + {17, nullptr, "Unknown10"}, + {18, nullptr, "Unknown11"}, + {19, nullptr, "Unknown12"}, + {20, nullptr, "Unknown13"}, + {21, nullptr, "Unknown14"}, + {22, nullptr, "Unknown15"}, + {23, nullptr, "Unknown16"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/omm.h b/src/core/hle/service/am/omm.h new file mode 100644 index 000000000..49e5d331c --- /dev/null +++ b/src/core/hle/service/am/omm.h @@ -0,0 +1,16 @@ +// 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::AM { + +class OMM final : public ServiceFramework<OMM> { +public: + explicit OMM(); +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/spsm.cpp b/src/core/hle/service/am/spsm.cpp new file mode 100644 index 000000000..a05d433d0 --- /dev/null +++ b/src/core/hle/service/am/spsm.cpp @@ -0,0 +1,30 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/am/spsm.h" + +namespace Service::AM { + +SPSM::SPSM() : ServiceFramework{"spsm"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetState"}, + {1, nullptr, "SleepSystemAndWaitAwake"}, + {2, nullptr, "Unknown1"}, + {3, nullptr, "Unknown2"}, + {4, nullptr, "GetNotificationMessageEventHandle"}, + {5, nullptr, "Unknown3"}, + {6, nullptr, "Unknown4"}, + {7, nullptr, "Unknown5"}, + {8, nullptr, "AnalyzePerformanceLogForLastSleepWakeSequence"}, + {9, nullptr, "ChangeHomeButtonLongPressingTime"}, + {10, nullptr, "Unknown6"}, + {11, nullptr, "Unknown7"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/spsm.h b/src/core/hle/service/am/spsm.h new file mode 100644 index 000000000..57dde62e1 --- /dev/null +++ b/src/core/hle/service/am/spsm.h @@ -0,0 +1,16 @@ +// 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::AM { + +class SPSM final : public ServiceFramework<SPSM> { +public: + explicit SPSM(); +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index a15d53ff8..ab37c2a69 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp @@ -25,9 +25,8 @@ constexpr int DefaultSampleRate{48000}; class IAudioOut final : public ServiceFramework<IAudioOut> { public: - IAudioOut(AudoutParams audio_params) - : ServiceFramework("IAudioOut"), audio_params(audio_params), - audio_core(Core::System::GetInstance().AudioCore()) { + IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core) + : ServiceFramework("IAudioOut"), audio_params(audio_params), audio_core(audio_core) { static const FunctionInfo functions[] = { {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, @@ -195,7 +194,7 @@ void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) { // TODO(bunnei): Support more than one IAudioOut interface. When we add this, ListAudioOutsImpl // will likely need to be updated as well. ASSERT_MSG(!audio_out_interface, "Unimplemented"); - audio_out_interface = std::make_shared<IAudioOut>(std::move(params)); + audio_out_interface = std::make_shared<IAudioOut>(std::move(params), *audio_core); IPC::ResponseBuilder rb{ctx, 6, 0, 1}; rb.Push(RESULT_SUCCESS); @@ -212,6 +211,7 @@ AudOutU::AudOutU() : ServiceFramework("audout:u") { {2, &AudOutU::ListAudioOutsImpl, "ListAudioOutsAuto"}, {3, &AudOutU::OpenAudioOutImpl, "OpenAudioOutAuto"}}; RegisterHandlers(functions); + audio_core = std::make_unique<AudioCore::AudioOut>(); } } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h index bc43f1f44..e5c2184d5 100644 --- a/src/core/hle/service/audio/audout_u.h +++ b/src/core/hle/service/audio/audout_u.h @@ -4,6 +4,7 @@ #pragma once +#include "audio_core/audio_out.h" #include "core/hle/service/service.h" namespace Kernel { @@ -33,6 +34,7 @@ public: private: std::shared_ptr<IAudioOut> audio_out_interface; + std::unique_ptr<AudioCore::AudioOut> audio_core; void ListAudioOutsImpl(Kernel::HLERequestContext& ctx); void OpenAudioOutImpl(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp index 844df382c..371cd4997 100644 --- a/src/core/hle/service/audio/hwopus.cpp +++ b/src/core/hle/service/audio/hwopus.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <cstring> +#include <opus.h> #include "common/logging/log.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/hle_ipc.h" @@ -9,19 +11,142 @@ namespace Service::Audio { +struct OpusDeleter { + void operator()(void* ptr) const { + operator delete(ptr); + } +}; + +class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> { +public: + IHardwareOpusDecoderManager(std::unique_ptr<OpusDecoder, OpusDeleter> decoder, u32 sample_rate, + u32 channel_count) + : ServiceFramework("IHardwareOpusDecoderManager"), decoder(std::move(decoder)), + sample_rate(sample_rate), channel_count(channel_count) { + static const FunctionInfo functions[] = { + {0, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleaved"}, + {1, nullptr, "SetContext"}, + {2, nullptr, "DecodeInterleavedForMultiStream"}, + {3, nullptr, "SetContextForMultiStream"}, + {4, nullptr, "Unknown4"}, + {5, nullptr, "Unknown5"}, + {6, nullptr, "Unknown6"}, + {7, nullptr, "Unknown7"}, + }; + RegisterHandlers(functions); + } + +private: + void DecodeInterleaved(Kernel::HLERequestContext& ctx) { + u32 consumed = 0; + u32 sample_count = 0; + std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16)); + if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples)) { + IPC::ResponseBuilder rb{ctx, 2}; + // TODO(ogniK): Use correct error code + rb.Push(ResultCode(-1)); + return; + } + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(consumed); + rb.Push<u32>(sample_count); + ctx.WriteBuffer(samples.data(), samples.size() * sizeof(s16)); + } + + bool Decoder_DecodeInterleaved(u32& consumed, u32& sample_count, const std::vector<u8>& input, + std::vector<opus_int16>& output) { + size_t raw_output_sz = output.size() * sizeof(opus_int16); + if (sizeof(OpusHeader) > input.size()) + return false; + OpusHeader hdr{}; + std::memcpy(&hdr, input.data(), sizeof(OpusHeader)); + if (sizeof(OpusHeader) + static_cast<u32>(hdr.sz) > input.size()) { + return false; + } + auto frame = input.data() + sizeof(OpusHeader); + auto decoded_sample_count = opus_packet_get_nb_samples( + frame, static_cast<opus_int32>(input.size() - sizeof(OpusHeader)), + static_cast<opus_int32>(sample_rate)); + if (decoded_sample_count * channel_count * sizeof(u16) > raw_output_sz) + return false; + auto out_sample_count = + opus_decode(decoder.get(), frame, hdr.sz, output.data(), + (static_cast<int>(raw_output_sz / sizeof(s16) / channel_count)), 0); + if (out_sample_count < 0) + return false; + sample_count = out_sample_count; + consumed = static_cast<u32>(sizeof(OpusHeader) + hdr.sz); + return true; + } + + struct OpusHeader { + u32_be sz; // Needs to be BE for some odd reason + INSERT_PADDING_WORDS(1); + }; + static_assert(sizeof(OpusHeader) == 0x8, "OpusHeader is an invalid size"); + + std::unique_ptr<OpusDecoder, OpusDeleter> decoder; + u32 sample_rate; + u32 channel_count; +}; + +static 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)); +} + void HwOpus::GetWorkBufferSize(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_Audio, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + auto sample_rate = rp.Pop<u32>(); + auto channel_count = rp.Pop<u32>(); + ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 || + sample_rate == 12000 || sample_rate == 8000, + "Invalid sample rate"); + ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count"); + u32 worker_buffer_sz = static_cast<u32>(WorkerBufferSize(channel_count)); + LOG_DEBUG(Audio, "called worker_buffer_sz={}", worker_buffer_sz); + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push<u32>(0x4000); + rb.Push<u32>(worker_buffer_sz); +} + +void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + auto sample_rate = rp.Pop<u32>(); + auto channel_count = rp.Pop<u32>(); + auto buffer_sz = rp.Pop<u32>(); + LOG_DEBUG(Audio, "called sample_rate={}, channel_count={}, buffer_size={}", sample_rate, + channel_count, buffer_sz); + ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 || + sample_rate == 12000 || sample_rate == 8000, + "Invalid sample rate"); + ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count"); + + size_t worker_sz = WorkerBufferSize(channel_count); + ASSERT_MSG(buffer_sz < worker_sz, "Worker buffer too large"); + std::unique_ptr<OpusDecoder, OpusDeleter> decoder{ + static_cast<OpusDecoder*>(operator new(worker_sz))}; + if (opus_decoder_init(decoder.get(), sample_rate, channel_count)) { + IPC::ResponseBuilder rb{ctx, 2}; + // TODO(ogniK): Use correct error code + rb.Push(ResultCode(-1)); + return; + } + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IHardwareOpusDecoderManager>(std::move(decoder), sample_rate, + channel_count); } HwOpus::HwOpus() : ServiceFramework("hwopus") { static const FunctionInfo functions[] = { - {0, nullptr, "Initialize"}, + {0, &HwOpus::OpenOpusDecoder, "OpenOpusDecoder"}, {1, &HwOpus::GetWorkBufferSize, "GetWorkBufferSize"}, - {2, nullptr, "InitializeMultiStream"}, - {3, nullptr, "GetWorkBufferSizeMultiStream"}, + {2, nullptr, "OpenOpusDecoderForMultiStream"}, + {3, nullptr, "GetWorkBufferSizeForMultiStream"}, }; RegisterHandlers(functions); } diff --git a/src/core/hle/service/audio/hwopus.h b/src/core/hle/service/audio/hwopus.h index 090b8c825..5258d59f3 100644 --- a/src/core/hle/service/audio/hwopus.h +++ b/src/core/hle/service/audio/hwopus.h @@ -14,6 +14,7 @@ public: ~HwOpus() = default; private: + void OpenOpusDecoder(Kernel::HLERequestContext& ctx); void GetWorkBufferSize(Kernel::HLERequestContext& ctx); }; diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp new file mode 100644 index 000000000..b949bfabd --- /dev/null +++ b/src/core/hle/service/btm/btm.cpp @@ -0,0 +1,121 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <memory> + +#include "common/logging/log.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/hle_ipc.h" +#include "core/hle/service/btm/btm.h" +#include "core/hle/service/service.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::BTM { + +class BTM final : public ServiceFramework<BTM> { +public: + explicit BTM() : ServiceFramework{"btm"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Unknown1"}, + {1, nullptr, "Unknown2"}, + {2, nullptr, "RegisterSystemEventForConnectedDeviceConditionImpl"}, + {3, nullptr, "Unknown3"}, + {4, nullptr, "Unknown4"}, + {5, nullptr, "Unknown5"}, + {6, nullptr, "Unknown6"}, + {7, nullptr, "Unknown7"}, + {8, nullptr, "RegisterSystemEventForRegisteredDeviceInfoImpl"}, + {9, nullptr, "Unknown8"}, + {10, nullptr, "Unknown9"}, + {11, nullptr, "Unknown10"}, + {12, nullptr, "Unknown11"}, + {13, nullptr, "Unknown12"}, + {14, nullptr, "EnableRadioImpl"}, + {15, nullptr, "DisableRadioImpl"}, + {16, nullptr, "Unknown13"}, + {17, nullptr, "Unknown14"}, + {18, nullptr, "Unknown15"}, + {19, nullptr, "Unknown16"}, + {20, nullptr, "Unknown17"}, + {21, nullptr, "Unknown18"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class BTM_DBG final : public ServiceFramework<BTM_DBG> { +public: + explicit BTM_DBG() : ServiceFramework{"btm:dbg"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "RegisterSystemEventForDiscoveryImpl"}, + {1, nullptr, "Unknown1"}, + {2, nullptr, "Unknown2"}, + {3, nullptr, "Unknown3"}, + {4, nullptr, "Unknown4"}, + {5, nullptr, "Unknown5"}, + {6, nullptr, "Unknown6"}, + {7, nullptr, "Unknown7"}, + {8, nullptr, "Unknown8"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class IBtmSystemCore final : public ServiceFramework<IBtmSystemCore> { +public: + explicit IBtmSystemCore() : ServiceFramework{"IBtmSystemCore"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "StartGamepadPairingImpl"}, + {1, nullptr, "CancelGamepadPairingImpl"}, + {2, nullptr, "ClearGamepadPairingDatabaseImpl"}, + {3, nullptr, "GetPairedGamepadCountImpl"}, + {4, nullptr, "EnableRadioImpl"}, + {5, nullptr, "DisableRadioImpl"}, + {6, nullptr, "GetRadioOnOffImpl"}, + {7, nullptr, "AcquireRadioEventImpl"}, + {8, nullptr, "AcquireGamepadPairingEventImpl"}, + {9, nullptr, "IsGamepadPairingStartedImpl"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class BTM_SYS final : public ServiceFramework<BTM_SYS> { +public: + explicit BTM_SYS() : ServiceFramework{"btm:sys"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &BTM_SYS::GetCoreImpl, "GetCoreImpl"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void GetCoreImpl(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IBtmSystemCore>(); + + LOG_DEBUG(Service_BTM, "called"); + } +}; + +void InstallInterfaces(SM::ServiceManager& sm) { + std::make_shared<BTM>()->InstallAsService(sm); + std::make_shared<BTM_DBG>()->InstallAsService(sm); + std::make_shared<BTM_SYS>()->InstallAsService(sm); +} + +} // namespace Service::BTM diff --git a/src/core/hle/service/btm/btm.h b/src/core/hle/service/btm/btm.h new file mode 100644 index 000000000..e6425a7e3 --- /dev/null +++ b/src/core/hle/service/btm/btm.h @@ -0,0 +1,15 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Service::SM { +class ServiceManager; +} + +namespace Service::BTM { + +void InstallInterfaces(SM::ServiceManager& sm); + +} // namespace Service::BTM diff --git a/src/core/hle/service/fgm/fgm.cpp b/src/core/hle/service/fgm/fgm.cpp new file mode 100644 index 000000000..566fbf924 --- /dev/null +++ b/src/core/hle/service/fgm/fgm.cpp @@ -0,0 +1,75 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <memory> + +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/hle_ipc.h" +#include "core/hle/service/fgm/fgm.h" +#include "core/hle/service/service.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::FGM { + +class IRequest final : public ServiceFramework<IRequest> { +public: + explicit IRequest() : ServiceFramework{"IRequest"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Initialize"}, + {1, nullptr, "Set"}, + {2, nullptr, "Get"}, + {3, nullptr, "Cancel"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class FGM final : public ServiceFramework<FGM> { +public: + explicit FGM(const char* name) : ServiceFramework{name} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &FGM::Initialize, "Initialize"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void Initialize(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IRequest>(); + + LOG_DEBUG(Service_FGM, "called"); + } +}; + +class FGM_DBG final : public ServiceFramework<FGM_DBG> { +public: + explicit FGM_DBG() : ServiceFramework{"fgm:dbg"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Initialize"}, + {1, nullptr, "Read"}, + {2, nullptr, "Cancel"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +void InstallInterfaces(SM::ServiceManager& sm) { + std::make_shared<FGM>("fgm")->InstallAsService(sm); + std::make_shared<FGM>("fgm:0")->InstallAsService(sm); + std::make_shared<FGM>("fgm:9")->InstallAsService(sm); + std::make_shared<FGM_DBG>()->InstallAsService(sm); +} + +} // namespace Service::FGM diff --git a/src/core/hle/service/fgm/fgm.h b/src/core/hle/service/fgm/fgm.h new file mode 100644 index 000000000..e59691264 --- /dev/null +++ b/src/core/hle/service/fgm/fgm.h @@ -0,0 +1,15 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Service::SM { +class ServiceManager; +} + +namespace Service::FGM { + +void InstallInterfaces(SM::ServiceManager& sm); + +} // namespace Service::FGM diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index e4619a547..ed53f96c5 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -326,7 +326,7 @@ public: {79, &Hid::SetGyroscopeZeroDriftMode, "SetGyroscopeZeroDriftMode"}, {80, nullptr, "GetGyroscopeZeroDriftMode"}, {81, nullptr, "ResetGyroscopeZeroDriftMode"}, - {82, nullptr, "IsSixAxisSensorAtRest"}, + {82, &Hid::IsSixAxisSensorAtRest, "IsSixAxisSensorAtRest"}, {91, nullptr, "ActivateGesture"}, {100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"}, {101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"}, @@ -343,7 +343,7 @@ public: "SetNpadJoyAssignmentModeSingleByDefault"}, {123, nullptr, "SetNpadJoyAssignmentModeSingleByDefault"}, {124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"}, - {125, nullptr, "MergeSingleJoyAsDualJoy"}, + {125, &Hid::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"}, {126, nullptr, "StartLrAssignmentMode"}, {127, nullptr, "StopLrAssignmentMode"}, {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"}, @@ -455,6 +455,14 @@ private: LOG_WARNING(Service_HID, "(STUBBED) called"); } + void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + // TODO (Hexagon12): Properly implement reading gyroscope values from controllers. + rb.Push(true); + LOG_WARNING(Service_HID, "(STUBBED) called"); + } + void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -530,6 +538,12 @@ private: LOG_WARNING(Service_HID, "(STUBBED) called"); } + void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + LOG_WARNING(Service_HID, "(STUBBED) called"); + } + void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index 44e062f50..010072a5b 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -97,7 +97,9 @@ u32 nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) { LOG_DEBUG(Service_NVDRV, "called"); IoctlActiveSlotMask params{}; - std::memcpy(¶ms, input.data(), input.size()); + if (input.size() > 0) { + std::memcpy(¶ms, input.data(), input.size()); + } params.slot = 0x07; params.mask = 0x01; std::memcpy(output.data(), ¶ms, output.size()); @@ -107,7 +109,9 @@ u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) { LOG_DEBUG(Service_NVDRV, "called"); IoctlZcullGetCtxSize params{}; - std::memcpy(¶ms, input.data(), input.size()); + if (input.size() > 0) { + std::memcpy(¶ms, input.data(), input.size()); + } params.size = 0x1; std::memcpy(output.data(), ¶ms, output.size()); return 0; @@ -116,7 +120,11 @@ 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_DEBUG(Service_NVDRV, "called"); IoctlNvgpuGpuZcullGetInfoArgs params{}; - std::memcpy(¶ms, input.data(), input.size()); + + if (input.size() > 0) { + std::memcpy(¶ms, input.data(), input.size()); + } + params.width_align_pixels = 0x20; params.height_align_pixels = 0x20; params.pixel_squares_by_aliquots = 0x400; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 126782573..5a1123ad2 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -132,9 +132,12 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address, params.num_entries, params.flags); - auto entries = std::vector<IoctlGpfifoEntry>(); - entries.resize(params.num_entries); - std::memcpy(&entries[0], &input.data()[sizeof(IoctlSubmitGpfifo)], + ASSERT_MSG(input.size() == + sizeof(IoctlSubmitGpfifo) + params.num_entries * sizeof(IoctlGpfifoEntry), + "Incorrect input size"); + + std::vector<IoctlGpfifoEntry> entries(params.num_entries); + std::memcpy(entries.data(), &input[sizeof(IoctlSubmitGpfifo)], params.num_entries * sizeof(IoctlGpfifoEntry)); for (auto entry : entries) { Tegra::GPUVAddr va_addr = entry.Address(); diff --git a/src/core/hle/service/pcie/pcie.cpp b/src/core/hle/service/pcie/pcie.cpp new file mode 100644 index 000000000..39cf05eba --- /dev/null +++ b/src/core/hle/service/pcie/pcie.cpp @@ -0,0 +1,64 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <memory> + +#include "core/hle/service/pcie/pcie.h" +#include "core/hle/service/service.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::PCIe { + +class ISession final : public ServiceFramework<ISession> { +public: + explicit ISession() : ServiceFramework{"ISession"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "QueryFunctions"}, + {1, nullptr, "AcquireFunction"}, + {2, nullptr, "ReleaseFunction"}, + {3, nullptr, "GetFunctionState"}, + {4, nullptr, "GetBarProfile"}, + {5, nullptr, "ReadConfig"}, + {6, nullptr, "WriteConfig"}, + {7, nullptr, "ReadBarRegion"}, + {8, nullptr, "WriteBarRegion"}, + {9, nullptr, "FindCapability"}, + {10, nullptr, "FindExtendedCapability"}, + {11, nullptr, "MapDma"}, + {12, nullptr, "UnmapDma"}, + {13, nullptr, "UnmapDmaBusAddress"}, + {14, nullptr, "GetDmaBusAddress"}, + {15, nullptr, "GetDmaBusAddressRange"}, + {16, nullptr, "SetDmaEnable"}, + {17, nullptr, "AcquireIrq"}, + {18, nullptr, "ReleaseIrq"}, + {19, nullptr, "SetIrqEnable"}, + {20, nullptr, "SetAspmEnable"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class PCIe final : public ServiceFramework<PCIe> { +public: + explicit PCIe() : ServiceFramework{"pcie"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "RegisterClassDriver"}, + {1, nullptr, "QueryFunctionsUnregistered"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +void InstallInterfaces(SM::ServiceManager& sm) { + std::make_shared<PCIe>()->InstallAsService(sm); +} + +} // namespace Service::PCIe diff --git a/src/core/hle/service/pcie/pcie.h b/src/core/hle/service/pcie/pcie.h new file mode 100644 index 000000000..59c22ca45 --- /dev/null +++ b/src/core/hle/service/pcie/pcie.h @@ -0,0 +1,15 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Service::SM { +class ServiceManager; +} + +namespace Service::PCIe { + +void InstallInterfaces(SM::ServiceManager& sm); + +} // namespace Service::PCIe diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 5180a0c93..fccc4c461 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -22,10 +22,12 @@ #include "core/hle/service/audio/audio.h" #include "core/hle/service/bcat/bcat.h" #include "core/hle/service/btdrv/btdrv.h" +#include "core/hle/service/btm/btm.h" #include "core/hle/service/erpt/erpt.h" #include "core/hle/service/es/es.h" #include "core/hle/service/eupld/eupld.h" #include "core/hle/service/fatal/fatal.h" +#include "core/hle/service/fgm/fgm.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/friend/friend.h" #include "core/hle/service/grc/grc.h" @@ -43,6 +45,7 @@ #include "core/hle/service/nim/nim.h" #include "core/hle/service/ns/ns.h" #include "core/hle/service/nvdrv/nvdrv.h" +#include "core/hle/service/pcie/pcie.h" #include "core/hle/service/pctl/pctl.h" #include "core/hle/service/pm/pm.h" #include "core/hle/service/prepo/prepo.h" @@ -55,6 +58,7 @@ #include "core/hle/service/ssl/ssl.h" #include "core/hle/service/time/time.h" #include "core/hle/service/vi/vi.h" +#include "core/hle/service/wlan/wlan.h" using Kernel::ClientPort; using Kernel::ServerPort; @@ -201,10 +205,12 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm) { Audio::InstallInterfaces(*sm); BCAT::InstallInterfaces(*sm); BtDrv::InstallInterfaces(*sm); + BTM::InstallInterfaces(*sm); ERPT::InstallInterfaces(*sm); ES::InstallInterfaces(*sm); EUPLD::InstallInterfaces(*sm); Fatal::InstallInterfaces(*sm); + FGM::InstallInterfaces(*sm); FileSystem::InstallInterfaces(*sm); Friend::InstallInterfaces(*sm); GRC::InstallInterfaces(*sm); @@ -222,15 +228,17 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm) { NIM::InstallInterfaces(*sm); NS::InstallInterfaces(*sm); Nvidia::InstallInterfaces(*sm); + PCIe::InstallInterfaces(*sm); PCTL::InstallInterfaces(*sm); PlayReport::InstallInterfaces(*sm); PM::InstallInterfaces(*sm); + Set::InstallInterfaces(*sm); Sockets::InstallInterfaces(*sm); SPL::InstallInterfaces(*sm); SSL::InstallInterfaces(*sm); Time::InstallInterfaces(*sm); VI::InstallInterfaces(*sm, nv_flinger); - Set::InstallInterfaces(*sm); + WLAN::InstallInterfaces(*sm); LOG_DEBUG(Service, "initialized OK"); } diff --git a/src/core/hle/service/wlan/wlan.cpp b/src/core/hle/service/wlan/wlan.cpp new file mode 100644 index 000000000..2654594c1 --- /dev/null +++ b/src/core/hle/service/wlan/wlan.cpp @@ -0,0 +1,172 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <memory> + +#include "core/hle/service/service.h" +#include "core/hle/service/sm/sm.h" +#include "core/hle/service/wlan/wlan.h" + +namespace Service::WLAN { + +class WLANInfra final : public ServiceFramework<WLANInfra> { +public: + explicit WLANInfra() : ServiceFramework{"wlan:inf"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Unknown1"}, + {1, nullptr, "Unknown2"}, + {2, nullptr, "GetMacAddress"}, + {3, nullptr, "StartScan"}, + {4, nullptr, "StopScan"}, + {5, nullptr, "Connect"}, + {6, nullptr, "CancelConnect"}, + {7, nullptr, "Disconnect"}, + {8, nullptr, "Unknown3"}, + {9, nullptr, "Unknown4"}, + {10, nullptr, "GetState"}, + {11, nullptr, "GetScanResult"}, + {12, nullptr, "GetRssi"}, + {13, nullptr, "ChangeRxAntenna"}, + {14, nullptr, "Unknown5"}, + {15, nullptr, "Unknown6"}, + {16, nullptr, "RequestWakeUp"}, + {17, nullptr, "RequestIfUpDown"}, + {18, nullptr, "Unknown7"}, + {19, nullptr, "Unknown8"}, + {20, nullptr, "Unknown9"}, + {21, nullptr, "Unknown10"}, + {22, nullptr, "Unknown11"}, + {23, nullptr, "Unknown12"}, + {24, nullptr, "Unknown13"}, + {25, nullptr, "Unknown14"}, + {26, nullptr, "Unknown15"}, + {27, nullptr, "Unknown16"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class WLANLocal final : public ServiceFramework<WLANLocal> { +public: + explicit WLANLocal() : ServiceFramework{"wlan:lcl"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Unknown1"}, + {1, nullptr, "Unknown2"}, + {2, nullptr, "Unknown3"}, + {3, nullptr, "Unknown4"}, + {4, nullptr, "Unknown5"}, + {5, nullptr, "Unknown6"}, + {6, nullptr, "GetMacAddress"}, + {7, nullptr, "CreateBss"}, + {8, nullptr, "DestroyBss"}, + {9, nullptr, "StartScan"}, + {10, nullptr, "StopScan"}, + {11, nullptr, "Connect"}, + {12, nullptr, "CancelConnect"}, + {13, nullptr, "Join"}, + {14, nullptr, "CancelJoin"}, + {15, nullptr, "Disconnect"}, + {16, nullptr, "SetBeaconLostCount"}, + {17, nullptr, "Unknown7"}, + {18, nullptr, "Unknown8"}, + {19, nullptr, "Unknown9"}, + {20, nullptr, "GetBssIndicationEvent"}, + {21, nullptr, "GetBssIndicationInfo"}, + {22, nullptr, "GetState"}, + {23, nullptr, "GetAllowedChannels"}, + {24, nullptr, "AddIe"}, + {25, nullptr, "DeleteIe"}, + {26, nullptr, "Unknown10"}, + {27, nullptr, "Unknown11"}, + {28, nullptr, "CreateRxEntry"}, + {29, nullptr, "DeleteRxEntry"}, + {30, nullptr, "Unknown12"}, + {31, nullptr, "Unknown13"}, + {32, nullptr, "AddMatchingDataToRxEntry"}, + {33, nullptr, "RemoveMatchingDataFromRxEntry"}, + {34, nullptr, "GetScanResult"}, + {35, nullptr, "Unknown14"}, + {36, nullptr, "SetActionFrameWithBeacon"}, + {37, nullptr, "CancelActionFrameWithBeacon"}, + {38, nullptr, "CreateRxEntryForActionFrame"}, + {39, nullptr, "DeleteRxEntryForActionFrame"}, + {40, nullptr, "Unknown15"}, + {41, nullptr, "Unknown16"}, + {42, nullptr, "CancelGetActionFrame"}, + {43, nullptr, "GetRssi"}, + {44, nullptr, "Unknown17"}, + {45, nullptr, "Unknown18"}, + {46, nullptr, "Unknown19"}, + {47, nullptr, "Unknown20"}, + {48, nullptr, "Unknown21"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class WLANLocalGetFrame final : public ServiceFramework<WLANLocalGetFrame> { +public: + explicit WLANLocalGetFrame() : ServiceFramework{"wlan:lg"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Unknown"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class WLANSocketGetFrame final : public ServiceFramework<WLANSocketGetFrame> { +public: + explicit WLANSocketGetFrame() : ServiceFramework{"wlan:sg"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Unknown"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class WLANSocketManager final : public ServiceFramework<WLANSocketManager> { +public: + explicit WLANSocketManager() : ServiceFramework{"wlan:soc"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Unknown1"}, + {1, nullptr, "Unknown2"}, + {2, nullptr, "Unknown3"}, + {3, nullptr, "Unknown4"}, + {4, nullptr, "Unknown5"}, + {5, nullptr, "Unknown6"}, + {6, nullptr, "GetMacAddress"}, + {7, nullptr, "SwitchTsfTimerFunction"}, + {8, nullptr, "Unknown7"}, + {9, nullptr, "Unknown8"}, + {10, nullptr, "Unknown9"}, + {11, nullptr, "Unknown10"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +void InstallInterfaces(SM::ServiceManager& sm) { + std::make_shared<WLANInfra>()->InstallAsService(sm); + std::make_shared<WLANLocal>()->InstallAsService(sm); + std::make_shared<WLANLocalGetFrame>()->InstallAsService(sm); + std::make_shared<WLANSocketGetFrame>()->InstallAsService(sm); + std::make_shared<WLANSocketManager>()->InstallAsService(sm); +} + +} // namespace Service::WLAN diff --git a/src/core/hle/service/wlan/wlan.h b/src/core/hle/service/wlan/wlan.h new file mode 100644 index 000000000..054ea928a --- /dev/null +++ b/src/core/hle/service/wlan/wlan.h @@ -0,0 +1,15 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Service::SM { +class ServiceManager; +} + +namespace Service::WLAN { + +void InstallInterfaces(SM::ServiceManager& sm); + +} // namespace Service::WLAN diff --git a/src/video_core/macro_interpreter.cpp b/src/video_core/macro_interpreter.cpp index 44ece01c1..377bd66ab 100644 --- a/src/video_core/macro_interpreter.cpp +++ b/src/video_core/macro_interpreter.cpp @@ -102,11 +102,11 @@ bool MacroInterpreter::Step(const std::vector<u32>& code, bool is_delay_slot) { if (taken) { // Ignore the delay slot if the branch has the annul bit. if (opcode.branch_annul) { - pc = base_address + (opcode.immediate << 2); + pc = base_address + opcode.GetBranchTarget(); return true; } - delayed_pc = base_address + (opcode.immediate << 2); + delayed_pc = base_address + opcode.GetBranchTarget(); // Execute one more instruction due to the delay slot. return Step(code, true); } diff --git a/src/video_core/macro_interpreter.h b/src/video_core/macro_interpreter.h index a71e359d8..7d836b816 100644 --- a/src/video_core/macro_interpreter.h +++ b/src/video_core/macro_interpreter.h @@ -91,6 +91,10 @@ private: u32 GetBitfieldMask() const { return (1 << bf_size) - 1; } + + s32 GetBranchTarget() const { + return static_cast<s32>(immediate * sizeof(u32)); + } }; union MethodAddress { diff --git a/src/yuzu/about_dialog.cpp b/src/yuzu/about_dialog.cpp index d6647eeea..39ed3bccf 100644 --- a/src/yuzu/about_dialog.cpp +++ b/src/yuzu/about_dialog.cpp @@ -10,8 +10,9 @@ AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent), ui(new Ui::AboutDialog) { ui->setupUi(this); ui->labelLogo->setPixmap(QIcon::fromTheme("yuzu").pixmap(200)); - ui->labelBuildInfo->setText(ui->labelBuildInfo->text().arg( - Common::g_build_name, Common::g_scm_branch, Common::g_scm_desc)); + ui->labelBuildInfo->setText( + ui->labelBuildInfo->text().arg(Common::g_build_name, Common::g_scm_branch, + Common::g_scm_desc, QString(Common::g_build_date).left(10))); } AboutDialog::~AboutDialog() {} diff --git a/src/yuzu/aboutdialog.ui b/src/yuzu/aboutdialog.ui index 2680480cc..f122ba39d 100644 --- a/src/yuzu/aboutdialog.ui +++ b/src/yuzu/aboutdialog.ui @@ -70,7 +70,7 @@ </sizepolicy> </property> <property name="text"> - <string><html><head/><body><p>%1 | %2-%3</p></body></html></string> + <string><html><head/><body><p>%1 | %2-%3 (%4)</p></body></html></string> </property> </widget> </item> @@ -115,7 +115,7 @@ p, li { white-space: pre-wrap; } <item> <widget class="QLabel" name="labelLinks"> <property name="text"> - <string><html><head/><body><p><a href="https://yuzu-emu.org/"><span style=" text-decoration: underline; color:#0000ff;">Website</span></a> | <a href="https://github.com/yuzu-emu"><span style=" text-decoration: underline; color:#0000ff;">Source Code</span></a> | <a href="https://github.com/yuzu-emu/yuzu/graphs/contributors"><span style=" text-decoration: underline; color:#0000ff;">Contributors</span></a> | <a href="https://github.com/yuzu-emu/yuzu/blob/master/license.txt"><span style=" text-decoration: underline; color:#0000ff;">License</span></a></p></body></html></string> + <string><html><head/><body><p><a href="https://yuzu-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/yuzu-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/yuzu-emu/yuzu/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/yuzu-emu/yuzu/blob/master/license.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></string> </property> <property name="openExternalLinks"> <bool>true</bool> diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp index 5e66239ff..7fd07539a 100644 --- a/src/yuzu/configuration/configure_debug.cpp +++ b/src/yuzu/configuration/configure_debug.cpp @@ -44,5 +44,4 @@ void ConfigureDebug::applyConfiguration() { Log::Filter filter; filter.ParseFilterString(Settings::values.log_filter); Log::SetGlobalFilter(filter); - Settings::Apply(); } diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index baa558667..cb7d3f8bf 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -44,5 +44,4 @@ void ConfigureGeneral::applyConfiguration() { Settings::values.use_cpu_jit = ui->use_cpu_jit->isChecked(); Settings::values.use_multi_core = ui->use_multi_core->isChecked(); Settings::values.use_docked_mode = ui->use_docked_mode->isChecked(); - Settings::Apply(); } diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index 7664880d5..3379b7963 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp @@ -67,5 +67,4 @@ void ConfigureGraphics::applyConfiguration() { ToResolutionFactor(static_cast<Resolution>(ui->resolution_factor_combobox->currentIndex())); Settings::values.toggle_framelimit = ui->toggle_framelimit->isChecked(); Settings::values.use_accurate_framebuffers = ui->use_accurate_framebuffers->isChecked(); - Settings::Apply(); } diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index 78559e2bb..5e7badedf 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -191,8 +191,6 @@ void ConfigureInput::applyConfiguration() { [](const Common::ParamPackage& param) { return param.Serialize(); }); std::transform(analogs_param.begin(), analogs_param.end(), Settings::values.analogs.begin(), [](const Common::ParamPackage& param) { return param.Serialize(); }); - - Settings::Apply(); } void ConfigureInput::loadConfiguration() { diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 96998643e..be38cfa9b 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -723,10 +723,12 @@ void GMainWindow::ToggleWindowMode() { void GMainWindow::OnConfigure() { ConfigureDialog configureDialog(this); + auto old_theme = UISettings::values.theme; auto result = configureDialog.exec(); if (result == QDialog::Accepted) { configureDialog.applyConfiguration(); - UpdateUITheme(); + if (UISettings::values.theme != old_theme) + UpdateUITheme(); config->Save(); } } @@ -957,7 +959,6 @@ int main(int argc, char* argv[]) { QCoreApplication::setOrganizationName("yuzu team"); QCoreApplication::setApplicationName("yuzu"); - QApplication::setAttribute(Qt::AA_X11InitThreads); QApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity); QApplication app(argc, argv); |