diff options
Diffstat (limited to 'src')
161 files changed, 1987 insertions, 511 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0ac3d254e..140415474 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -82,8 +82,9 @@ if (MSVC) /wd4324 # 'struct_name': structure was padded due to __declspec(align()) ) - if (USE_CCACHE) + if (USE_CCACHE OR YUZU_USE_PRECOMPILED_HEADERS) # when caching, we need to use /Z7 to downgrade debug info to use an older but more cachable format + # Precompiled headers are deleted if not using /Z7. See https://github.com/nanoant/CMakePCHCompiler/issues/21 add_compile_options(/Z7) else() add_compile_options(/Zi) @@ -112,6 +113,8 @@ else() $<$<CXX_COMPILER_ID:Clang>:-Wno-braced-scalar-init> $<$<CXX_COMPILER_ID:Clang>:-Wno-unused-private-field> + $<$<CXX_COMPILER_ID:AppleClang>:-Wno-braced-scalar-init> + $<$<CXX_COMPILER_ID:AppleClang>:-Wno-unused-private-field> ) if (ARCHITECTURE_x86_64) diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt index 8e3a8f5a8..0a9d9ec29 100644 --- a/src/audio_core/CMakeLists.txt +++ b/src/audio_core/CMakeLists.txt @@ -31,6 +31,7 @@ add_library(audio_core STATIC out/audio_out.h out/audio_out_system.cpp out/audio_out_system.h + precompiled_headers.h renderer/adsp/adsp.cpp renderer/adsp/adsp.h renderer/adsp/audio_renderer.cpp @@ -226,6 +227,14 @@ if(ENABLE_CUBEB) target_compile_definitions(audio_core PRIVATE -DHAVE_CUBEB=1) endif() if(ENABLE_SDL2) - target_link_libraries(audio_core PRIVATE SDL2) + if (YUZU_USE_EXTERNAL_SDL2) + target_link_libraries(audio_core PRIVATE SDL2-static) + else() + target_link_libraries(audio_core PRIVATE SDL2) + endif() target_compile_definitions(audio_core PRIVATE HAVE_SDL2) endif() + +if (YUZU_USE_PRECOMPILED_HEADERS) + target_precompile_headers(audio_core PRIVATE precompiled_headers.h) +endif() diff --git a/src/audio_core/audio_event.cpp b/src/audio_core/audio_event.cpp index 424049c7a..d15568e1f 100644 --- a/src/audio_core/audio_event.cpp +++ b/src/audio_core/audio_event.cpp @@ -3,6 +3,7 @@ #include "audio_core/audio_event.h" #include "common/assert.h" +#include "common/polyfill_ranges.h" namespace AudioCore { diff --git a/src/audio_core/audio_manager.h b/src/audio_core/audio_manager.h index abf077de4..02270242a 100644 --- a/src/audio_core/audio_manager.h +++ b/src/audio_core/audio_manager.h @@ -9,6 +9,8 @@ #include <mutex> #include <thread> +#include "common/polyfill_thread.h" + #include "audio_core/audio_event.h" union Result; diff --git a/src/audio_core/audio_render_manager.h b/src/audio_core/audio_render_manager.h index bf4837190..fffa5944d 100644 --- a/src/audio_core/audio_render_manager.h +++ b/src/audio_core/audio_render_manager.h @@ -7,6 +7,8 @@ #include <memory> #include <mutex> +#include "common/polyfill_thread.h" + #include "audio_core/common/common.h" #include "audio_core/renderer/system_manager.h" #include "core/hle/service/audio/errors.h" diff --git a/src/audio_core/common/feature_support.h b/src/audio_core/common/feature_support.h index 55c9e690d..e71905ae8 100644 --- a/src/audio_core/common/feature_support.h +++ b/src/audio_core/common/feature_support.h @@ -10,6 +10,7 @@ #include "common/assert.h" #include "common/common_funcs.h" #include "common/common_types.h" +#include "common/polyfill_ranges.h" namespace AudioCore { constexpr u32 CurrentRevision = 11; diff --git a/src/audio_core/precompiled_headers.h b/src/audio_core/precompiled_headers.h new file mode 100644 index 000000000..aabae730b --- /dev/null +++ b/src/audio_core/precompiled_headers.h @@ -0,0 +1,6 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_precompiled_headers.h" diff --git a/src/audio_core/renderer/command/effect/i3dl2_reverb.cpp b/src/audio_core/renderer/command/effect/i3dl2_reverb.cpp index c4bf3943a..2187d8a65 100644 --- a/src/audio_core/renderer/command/effect/i3dl2_reverb.cpp +++ b/src/audio_core/renderer/command/effect/i3dl2_reverb.cpp @@ -5,6 +5,7 @@ #include "audio_core/renderer/adsp/command_list_processor.h" #include "audio_core/renderer/command/effect/i3dl2_reverb.h" +#include "common/polyfill_ranges.h" namespace AudioCore::AudioRenderer { diff --git a/src/audio_core/renderer/command/effect/reverb.cpp b/src/audio_core/renderer/command/effect/reverb.cpp index fe2b1eb43..427489214 100644 --- a/src/audio_core/renderer/command/effect/reverb.cpp +++ b/src/audio_core/renderer/command/effect/reverb.cpp @@ -6,6 +6,7 @@ #include "audio_core/renderer/adsp/command_list_processor.h" #include "audio_core/renderer/command/effect/reverb.h" +#include "common/polyfill_ranges.h" namespace AudioCore::AudioRenderer { diff --git a/src/audio_core/renderer/mix/mix_context.cpp b/src/audio_core/renderer/mix/mix_context.cpp index 2427c83ed..35b748ede 100644 --- a/src/audio_core/renderer/mix/mix_context.cpp +++ b/src/audio_core/renderer/mix/mix_context.cpp @@ -5,6 +5,7 @@ #include "audio_core/renderer/mix/mix_context.h" #include "audio_core/renderer/splitter/splitter_context.h" +#include "common/polyfill_ranges.h" namespace AudioCore::AudioRenderer { diff --git a/src/audio_core/renderer/voice/voice_context.cpp b/src/audio_core/renderer/voice/voice_context.cpp index a501a677d..16a3e839d 100644 --- a/src/audio_core/renderer/voice/voice_context.cpp +++ b/src/audio_core/renderer/voice/voice_context.cpp @@ -4,6 +4,7 @@ #include <ranges> #include "audio_core/renderer/voice/voice_context.h" +#include "common/polyfill_ranges.h" namespace AudioCore::AudioRenderer { diff --git a/src/audio_core/sink/sink_stream.cpp b/src/audio_core/sink/sink_stream.cpp index 849f862b0..06c2a876e 100644 --- a/src/audio_core/sink/sink_stream.cpp +++ b/src/audio_core/sink/sink_stream.cpp @@ -170,8 +170,8 @@ void SinkStream::ProcessAudioIn(std::span<const s16> input_buffer, std::size_t n // Get the minimum frames available between the currently playing buffer, and the // amount we have left to fill - size_t frames_available{std::min(playing_buffer.frames - playing_buffer.frames_played, - num_frames - frames_written)}; + size_t frames_available{std::min<u64>(playing_buffer.frames - playing_buffer.frames_played, + num_frames - frames_written)}; samples_buffer.Push(&input_buffer[frames_written * frame_size], frames_available * frame_size); @@ -241,8 +241,8 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz // Get the minimum frames available between the currently playing buffer, and the // amount we have left to fill - size_t frames_available{std::min(playing_buffer.frames - playing_buffer.frames_played, - num_frames - frames_written)}; + size_t frames_available{std::min<u64>(playing_buffer.frames - playing_buffer.frames_played, + num_frames - frames_written)}; samples_buffer.Pop(&output_buffer[frames_written * frame_size], frames_available * frame_size); @@ -266,19 +266,20 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz } void SinkStream::Stall() { - if (stalled) { + std::scoped_lock lk{stall_guard}; + if (stalled_lock) { return; } - stalled = true; - system.StallProcesses(); + stalled_lock = system.StallProcesses(); } void SinkStream::Unstall() { - if (!stalled) { + std::scoped_lock lk{stall_guard}; + if (!stalled_lock) { return; } system.UnstallProcesses(); - stalled = false; + stalled_lock.unlock(); } } // namespace AudioCore::Sink diff --git a/src/audio_core/sink/sink_stream.h b/src/audio_core/sink/sink_stream.h index 38a4b2f51..5fea72ab7 100644 --- a/src/audio_core/sink/sink_stream.h +++ b/src/audio_core/sink/sink_stream.h @@ -6,6 +6,7 @@ #include <array> #include <atomic> #include <memory> +#include <mutex> #include <span> #include <vector> @@ -240,8 +241,8 @@ private: f32 system_volume{1.0f}; /// Set via IAudioDevice service calls f32 device_volume{1.0f}; - /// True if coretiming has been stalled - bool stalled{false}; + std::mutex stall_guard; + std::unique_lock<std::mutex> stalled_lock; }; using SinkStreamPtr = std::unique_ptr<SinkStream>; diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index b7c15c191..a12edc584 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -37,6 +37,7 @@ add_library(common STATIC cache_management.cpp cache_management.h common_funcs.h + common_precompiled_headers.h common_types.h concepts.h div_ceil.h @@ -95,6 +96,7 @@ add_library(common STATIC param_package.h parent_of_member.h point.h + precompiled_headers.h quaternion.h reader_writer_queue.h ring_buffer.h @@ -183,3 +185,7 @@ else() target_link_libraries(common PRIVATE $<IF:$<TARGET_EXISTS:zstd::libzstd_shared>,zstd::libzstd_shared,zstd::libzstd_static>) endif() + +if (YUZU_USE_PRECOMPILED_HEADERS) + target_precompile_headers(common PRIVATE precompiled_headers.h) +endif() diff --git a/src/common/cache_management.cpp b/src/common/cache_management.cpp index 57810b76a..ed353828a 100644 --- a/src/common/cache_management.cpp +++ b/src/common/cache_management.cpp @@ -1,11 +1,10 @@ // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include <cstdint> #include <cstring> -#include "alignment.h" -#include "cache_management.h" -#include "common_types.h" +#include "common/cache_management.h" namespace Common { diff --git a/src/common/cache_management.h b/src/common/cache_management.h index e467b87e4..038323e95 100644 --- a/src/common/cache_management.h +++ b/src/common/cache_management.h @@ -3,7 +3,7 @@ #pragma once -#include "stdlib.h" +#include <cstddef> namespace Common { diff --git a/src/common/common_precompiled_headers.h b/src/common/common_precompiled_headers.h new file mode 100644 index 000000000..be7e5b5f9 --- /dev/null +++ b/src/common/common_precompiled_headers.h @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <algorithm> +#include <array> +#include <chrono> +#include <memory> + +#include <fmt/format.h> + +#include "common/assert.h" +#include "common/common_types.h" diff --git a/src/common/fs/file.cpp b/src/common/fs/file.cpp index fa8422c41..656b03cc5 100644 --- a/src/common/fs/file.cpp +++ b/src/common/fs/file.cpp @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include <vector> + #include "common/fs/file.h" #include "common/fs/fs.h" #include "common/logging/log.h" diff --git a/src/common/fs/fs_util.cpp b/src/common/fs/fs_util.cpp index eb4ac1deb..813a713c3 100644 --- a/src/common/fs/fs_util.cpp +++ b/src/common/fs/fs_util.cpp @@ -4,6 +4,7 @@ #include <algorithm> #include "common/fs/fs_util.h" +#include "common/polyfill_ranges.h" namespace Common::FS { diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp index 1074f2421..defa3e918 100644 --- a/src/common/fs/path_util.cpp +++ b/src/common/fs/path_util.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> +#include <sstream> #include <unordered_map> #include "common/fs/fs.h" diff --git a/src/common/input.h b/src/common/input.h index cb30b7254..fc14fd7bf 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -8,6 +8,7 @@ #include <string> #include <unordered_map> #include <utility> +#include <vector> #include "common/logging/log.h" #include "common/param_package.h" #include "common/uuid.h" @@ -383,6 +384,16 @@ void RegisterFactory(const std::string& name, std::shared_ptr<Factory<InputDevic } } +inline void RegisterInputFactory(const std::string& name, + std::shared_ptr<Factory<InputDevice>> factory) { + RegisterFactory<InputDevice>(name, std::move(factory)); +} + +inline void RegisterOutputFactory(const std::string& name, + std::shared_ptr<Factory<OutputDevice>> factory) { + RegisterFactory<OutputDevice>(name, std::move(factory)); +} + /** * Unregisters an input device factory. * @tparam InputDeviceType the type of input devices the factory can create @@ -395,6 +406,14 @@ void UnregisterFactory(const std::string& name) { } } +inline void UnregisterInputFactory(const std::string& name) { + UnregisterFactory<InputDevice>(name); +} + +inline void UnregisterOutputFactory(const std::string& name) { + UnregisterFactory<OutputDevice>(name); +} + /** * Create an input device from given paramters. * @tparam InputDeviceType the type of input devices to create @@ -416,13 +435,21 @@ std::unique_ptr<InputDeviceType> CreateDeviceFromString(const std::string& param return pair->second->Create(package); } +inline std::unique_ptr<InputDevice> CreateInputDeviceFromString(const std::string& params) { + return CreateDeviceFromString<InputDevice>(params); +} + +inline std::unique_ptr<OutputDevice> CreateOutputDeviceFromString(const std::string& params) { + return CreateDeviceFromString<OutputDevice>(params); +} + /** - * Create an input device from given paramters. + * Create an input device from given parameters. * @tparam InputDeviceType the type of input devices to create - * @param A ParamPackage that contains all parameters for creating the device + * @param package A ParamPackage that contains all parameters for creating the device */ template <typename InputDeviceType> -std::unique_ptr<InputDeviceType> CreateDevice(const Common::ParamPackage package) { +std::unique_ptr<InputDeviceType> CreateDevice(const ParamPackage& package) { const std::string engine = package.Get("engine", "null"); const auto& factory_list = Impl::FactoryList<InputDeviceType>::list; const auto pair = factory_list.find(engine); @@ -435,4 +462,12 @@ std::unique_ptr<InputDeviceType> CreateDevice(const Common::ParamPackage package return pair->second->Create(package); } +inline std::unique_ptr<InputDevice> CreateInputDevice(const ParamPackage& package) { + return CreateDevice<InputDevice>(package); +} + +inline std::unique_ptr<OutputDevice> CreateOutputDevice(const ParamPackage& package) { + return CreateDevice<OutputDevice>(package); +} + } // namespace Common::Input diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 15d92505e..2a3bded40 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp @@ -4,7 +4,6 @@ #include <atomic> #include <chrono> #include <climits> -#include <stop_token> #include <thread> #include <fmt/format.h> @@ -18,6 +17,7 @@ #include "common/fs/fs_paths.h" #include "common/fs/path_util.h" #include "common/literals.h" +#include "common/polyfill_thread.h" #include "common/thread.h" #include "common/logging/backend.h" diff --git a/src/common/polyfill_ranges.h b/src/common/polyfill_ranges.h new file mode 100644 index 000000000..ca44bfaef --- /dev/null +++ b/src/common/polyfill_ranges.h @@ -0,0 +1,530 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +// +// TODO: remove this file when ranges are supported by all compilation targets +// + +#pragma once + +#include <algorithm> +#include <utility> +#include <version> + +#ifndef __cpp_lib_ranges + +namespace std { +namespace ranges { + +template <typename T> +concept range = requires(T& t) { + begin(t); + end(t); +}; + +template <typename T> +concept input_range = range<T>; + +template <typename T> +concept output_range = range<T>; + +template <range R> +using range_difference_t = ptrdiff_t; + +// +// find, find_if, find_if_not +// + +struct find_fn { + template <typename Iterator, typename T, typename Proj = std::identity> + constexpr Iterator operator()(Iterator first, Iterator last, const T& value, + Proj proj = {}) const { + for (; first != last; ++first) { + if (std::invoke(proj, *first) == value) { + return first; + } + } + return first; + } + + template <ranges::input_range R, typename T, typename Proj = std::identity> + constexpr ranges::iterator_t<R> operator()(R&& r, const T& value, Proj proj = {}) const { + return operator()(ranges::begin(r), ranges::end(r), value, std::ref(proj)); + } +}; + +struct find_if_fn { + template <typename Iterator, typename Proj = std::identity, typename Pred> + constexpr Iterator operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const { + for (; first != last; ++first) { + if (std::invoke(pred, std::invoke(proj, *first))) { + return first; + } + } + return first; + } + + template <ranges::input_range R, typename Proj = std::identity, typename Pred> + constexpr ranges::iterator_t<R> operator()(R&& r, Pred pred, Proj proj = {}) const { + return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj)); + } +}; + +struct find_if_not_fn { + template <typename Iterator, typename Proj = std::identity, typename Pred> + constexpr Iterator operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const { + for (; first != last; ++first) { + if (!std::invoke(pred, std::invoke(proj, *first))) { + return first; + } + } + return first; + } + + template <ranges::input_range R, typename Proj = std::identity, typename Pred> + constexpr ranges::iterator_t<R> operator()(R&& r, Pred pred, Proj proj = {}) const { + return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj)); + } +}; + +inline constexpr find_fn find; +inline constexpr find_if_fn find_if; +inline constexpr find_if_not_fn find_if_not; + +// +// any_of, all_of, none_of +// + +struct all_of_fn { + template <typename Iterator, typename Proj = std::identity, typename Pred> + constexpr bool operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const { + return ranges::find_if_not(first, last, std::ref(pred), std::ref(proj)) == last; + } + + template <ranges::input_range R, typename Proj = std::identity, typename Pred> + constexpr bool operator()(R&& r, Pred pred, Proj proj = {}) const { + return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj)); + } +}; + +struct any_of_fn { + template <typename Iterator, typename Proj = std::identity, typename Pred> + constexpr bool operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const { + return ranges::find_if(first, last, std::ref(pred), std::ref(proj)) != last; + } + + template <ranges::input_range R, typename Proj = std::identity, typename Pred> + constexpr bool operator()(R&& r, Pred pred, Proj proj = {}) const { + return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj)); + } +}; + +struct none_of_fn { + template <typename Iterator, typename Proj = std::identity, typename Pred> + constexpr bool operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const { + return ranges::find_if(first, last, std::ref(pred), std::ref(proj)) == last; + } + + template <ranges::input_range R, typename Proj = std::identity, typename Pred> + constexpr bool operator()(R&& r, Pred pred, Proj proj = {}) const { + return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj)); + } +}; + +inline constexpr any_of_fn any_of; +inline constexpr all_of_fn all_of; +inline constexpr none_of_fn none_of; + +// +// count, count_if +// + +struct count_fn { + template <typename Iterator, typename T, typename Proj = std::identity> + constexpr ptrdiff_t operator()(Iterator first, Iterator last, const T& value, + Proj proj = {}) const { + ptrdiff_t counter = 0; + for (; first != last; ++first) + if (std::invoke(proj, *first) == value) + ++counter; + return counter; + } + + template <ranges::input_range R, typename T, typename Proj = std::identity> + constexpr ptrdiff_t operator()(R&& r, const T& value, Proj proj = {}) const { + return operator()(ranges::begin(r), ranges::end(r), value, std::ref(proj)); + } +}; + +struct count_if_fn { + template <typename Iterator, typename Proj = std::identity, typename Pred> + constexpr ptrdiff_t operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const { + ptrdiff_t counter = 0; + for (; first != last; ++first) + if (std::invoke(pred, std::invoke(proj, *first))) + ++counter; + return counter; + } + + template <ranges::input_range R, typename Proj = std::identity, typename Pred> + constexpr ptrdiff_t operator()(R&& r, Pred pred, Proj proj = {}) const { + return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj)); + } +}; + +inline constexpr count_fn count; +inline constexpr count_if_fn count_if; + +// +// transform +// + +struct transform_fn { + template <typename InputIterator, typename OutputIterator, typename F, + typename Proj = std::identity> + constexpr void operator()(InputIterator first1, InputIterator last1, OutputIterator result, + F op, Proj proj = {}) const { + for (; first1 != last1; ++first1, (void)++result) { + *result = std::invoke(op, std::invoke(proj, *first1)); + } + } + + template <ranges::input_range R, typename OutputIterator, typename F, + typename Proj = std::identity> + constexpr void operator()(R&& r, OutputIterator result, F op, Proj proj = {}) const { + return operator()(ranges::begin(r), ranges::end(r), result, std::ref(op), std::ref(proj)); + } +}; + +inline constexpr transform_fn transform; + +// +// sort +// + +struct sort_fn { + template <typename Iterator, typename Comp = ranges::less, typename Proj = std::identity> + constexpr void operator()(Iterator first, Iterator last, Comp comp = {}, Proj proj = {}) const { + if (first == last) + return; + + Iterator last_iter = ranges::next(first, last); + std::sort(first, last_iter, + [&](auto& lhs, auto& rhs) { return comp(proj(lhs), proj(rhs)); }); + } + + template <ranges::input_range R, typename Comp = ranges::less, typename Proj = std::identity> + constexpr void operator()(R&& r, Comp comp = {}, Proj proj = {}) const { + return operator()(ranges::begin(r), ranges::end(r), std::move(comp), std::move(proj)); + } +}; + +inline constexpr sort_fn sort; + +// +// fill +// + +struct fill_fn { + template <typename T, typename OutputIterator> + constexpr OutputIterator operator()(OutputIterator first, OutputIterator last, + const T& value) const { + while (first != last) { + *first++ = value; + } + + return first; + } + + template <typename T, ranges::output_range R> + constexpr ranges::iterator_t<R> operator()(R&& r, const T& value) const { + return operator()(ranges::begin(r), ranges::end(r), value); + } +}; + +inline constexpr fill_fn fill; + +// +// for_each +// + +struct for_each_fn { + template <typename Iterator, typename Proj = std::identity, typename Fun> + constexpr void operator()(Iterator first, Iterator last, Fun f, Proj proj = {}) const { + for (; first != last; ++first) { + std::invoke(f, std::invoke(proj, *first)); + } + } + + template <ranges::input_range R, typename Proj = std::identity, typename Fun> + constexpr void operator()(R&& r, Fun f, Proj proj = {}) const { + return operator()(ranges::begin(r), ranges::end(r), std::move(f), std::ref(proj)); + } +}; + +inline constexpr for_each_fn for_each; + +// +// min_element, max_element +// + +struct min_element_fn { + template <typename Iterator, typename Proj = std::identity, typename Comp = ranges::less> + constexpr Iterator operator()(Iterator first, Iterator last, Comp comp = {}, + Proj proj = {}) const { + if (first == last) { + return last; + } + + auto smallest = first; + ++first; + for (; first != last; ++first) { + if (!std::invoke(comp, std::invoke(proj, *smallest), std::invoke(proj, *first))) { + smallest = first; + } + } + return smallest; + } + + template <ranges::input_range R, typename Proj = std::identity, typename Comp = ranges::less> + constexpr ranges::iterator_t<R> operator()(R&& r, Comp comp = {}, Proj proj = {}) const { + return operator()(ranges::begin(r), ranges::end(r), std::ref(comp), std::ref(proj)); + } +}; + +struct max_element_fn { + template <typename Iterator, typename Proj = std::identity, typename Comp = ranges::less> + constexpr Iterator operator()(Iterator first, Iterator last, Comp comp = {}, + Proj proj = {}) const { + if (first == last) { + return last; + } + + auto largest = first; + ++first; + for (; first != last; ++first) { + if (std::invoke(comp, std::invoke(proj, *largest), std::invoke(proj, *first))) { + largest = first; + } + } + return largest; + } + + template <ranges::input_range R, typename Proj = std::identity, typename Comp = ranges::less> + constexpr ranges::iterator_t<R> operator()(R&& r, Comp comp = {}, Proj proj = {}) const { + return operator()(ranges::begin(r), ranges::end(r), std::ref(comp), std::ref(proj)); + } +}; + +inline constexpr min_element_fn min_element; +inline constexpr max_element_fn max_element; + +// +// replace, replace_if +// + +struct replace_fn { + template <typename Iterator, typename T1, typename T2, typename Proj = std::identity> + constexpr Iterator operator()(Iterator first, Iterator last, const T1& old_value, + const T2& new_value, Proj proj = {}) const { + for (; first != last; ++first) { + if (old_value == std::invoke(proj, *first)) { + *first = new_value; + } + } + return first; + } + + template <ranges::input_range R, typename T1, typename T2, typename Proj = std::identity> + constexpr ranges::iterator_t<R> operator()(R&& r, const T1& old_value, const T2& new_value, + Proj proj = {}) const { + return operator()(ranges::begin(r), ranges::end(r), old_value, new_value, std::move(proj)); + } +}; + +struct replace_if_fn { + template <typename Iterator, typename T, typename Proj = std::identity, typename Pred> + constexpr Iterator operator()(Iterator first, Iterator last, Pred pred, const T& new_value, + Proj proj = {}) const { + for (; first != last; ++first) { + if (!!std::invoke(pred, std::invoke(proj, *first))) { + *first = new_value; + } + } + return std::move(first); + } + + template <ranges::input_range R, typename T, typename Proj = std::identity, typename Pred> + constexpr ranges::iterator_t<R> operator()(R&& r, Pred pred, const T& new_value, + Proj proj = {}) const { + return operator()(ranges::begin(r), ranges::end(r), std::move(pred), new_value, + std::move(proj)); + } +}; + +inline constexpr replace_fn replace; +inline constexpr replace_if_fn replace_if; + +// +// copy, copy_if +// + +struct copy_fn { + template <typename InputIterator, typename OutputIterator> + constexpr void operator()(InputIterator first, InputIterator last, + OutputIterator result) const { + for (; first != last; ++first, (void)++result) { + *result = *first; + } + } + + template <ranges::input_range R, typename OutputIterator> + constexpr void operator()(R&& r, OutputIterator result) const { + return operator()(ranges::begin(r), ranges::end(r), std::move(result)); + } +}; + +struct copy_if_fn { + template <typename InputIterator, typename OutputIterator, typename Proj = std::identity, + typename Pred> + constexpr void operator()(InputIterator first, InputIterator last, OutputIterator result, + Pred pred, Proj proj = {}) const { + for (; first != last; ++first) { + if (std::invoke(pred, std::invoke(proj, *first))) { + *result = *first; + ++result; + } + } + } + + template <ranges::input_range R, typename OutputIterator, typename Proj = std::identity, + typename Pred> + constexpr void operator()(R&& r, OutputIterator result, Pred pred, Proj proj = {}) const { + return operator()(ranges::begin(r), ranges::end(r), std::move(result), std::ref(pred), + std::ref(proj)); + } +}; + +inline constexpr copy_fn copy; +inline constexpr copy_if_fn copy_if; + +// +// generate +// + +struct generate_fn { + template <typename Iterator, typename F> + constexpr Iterator operator()(Iterator first, Iterator last, F gen) const { + for (; first != last; *first = std::invoke(gen), ++first) + ; + return first; + } + + template <typename R, std::copy_constructible F> + requires std::invocable<F&> && ranges::output_range<R> + constexpr ranges::iterator_t<R> operator()(R&& r, F gen) const { + return operator()(ranges::begin(r), ranges::end(r), std::move(gen)); + } +}; + +inline constexpr generate_fn generate; + +// +// lower_bound, upper_bound +// + +struct lower_bound_fn { + template <typename Iterator, typename T, typename Proj = std::identity, + typename Comp = ranges::less> + constexpr Iterator operator()(Iterator first, Iterator last, const T& value, Comp comp = {}, + Proj proj = {}) const { + Iterator it; + std::ptrdiff_t _count, _step; + _count = std::distance(first, last); + + while (_count > 0) { + it = first; + _step = _count / 2; + ranges::advance(it, _step, last); + if (comp(std::invoke(proj, *it), value)) { + first = ++it; + _count -= _step + 1; + } else { + _count = _step; + } + } + return first; + } + + template <ranges::input_range R, typename T, typename Proj = std::identity, + typename Comp = ranges::less> + constexpr ranges::iterator_t<R> operator()(R&& r, const T& value, Comp comp = {}, + Proj proj = {}) const { + return operator()(ranges::begin(r), ranges::end(r), value, std::ref(comp), std::ref(proj)); + } +}; + +struct upper_bound_fn { + template <typename Iterator, typename T, typename Proj = std::identity, + typename Comp = ranges::less> + constexpr Iterator operator()(Iterator first, Iterator last, const T& value, Comp comp = {}, + Proj proj = {}) const { + Iterator it; + std::ptrdiff_t _count, _step; + _count = std::distance(first, last); + + while (_count > 0) { + it = first; + _step = _count / 2; + ranges::advance(it, _step, last); + if (!comp(value, std::invoke(proj, *it))) { + first = ++it; + _count -= _step + 1; + } else { + _count = _step; + } + } + return first; + } + + template <ranges::input_range R, typename T, typename Proj = std::identity, + typename Comp = ranges::less> + constexpr ranges::iterator_t<R> operator()(R&& r, const T& value, Comp comp = {}, + Proj proj = {}) const { + return operator()(ranges::begin(r), ranges::end(r), value, std::ref(comp), std::ref(proj)); + } +}; + +inline constexpr lower_bound_fn lower_bound; +inline constexpr upper_bound_fn upper_bound; + +// +// adjacent_find +// + +struct adjacent_find_fn { + template <typename Iterator, typename Proj = std::identity, typename Pred = ranges::equal_to> + constexpr Iterator operator()(Iterator first, Iterator last, Pred pred = {}, + Proj proj = {}) const { + if (first == last) + return first; + auto _next = ranges::next(first); + for (; _next != last; ++_next, ++first) + if (std::invoke(pred, std::invoke(proj, *first), std::invoke(proj, *_next))) + return first; + return _next; + } + + template <ranges::input_range R, typename Proj = std::identity, + typename Pred = ranges::equal_to> + constexpr ranges::iterator_t<R> operator()(R&& r, Pred pred = {}, Proj proj = {}) const { + return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj)); + } +}; + +inline constexpr adjacent_find_fn adjacent_find; + +} // namespace ranges +} // namespace std + +#endif diff --git a/src/common/polyfill_thread.h b/src/common/polyfill_thread.h new file mode 100644 index 000000000..5a8d1ce08 --- /dev/null +++ b/src/common/polyfill_thread.h @@ -0,0 +1,323 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +// +// TODO: remove this file when jthread is supported by all compilation targets +// + +#pragma once + +#include <version> + +#ifdef __cpp_lib_jthread + +#include <stop_token> +#include <thread> + +namespace Common { + +template <typename Condvar, typename Lock, typename Pred> +void CondvarWait(Condvar& cv, Lock& lock, std::stop_token token, Pred&& pred) { + cv.wait(lock, token, std::move(pred)); +} + +} // namespace Common + +#else + +#include <atomic> +#include <functional> +#include <list> +#include <memory> +#include <mutex> +#include <optional> +#include <thread> +#include <type_traits> + +namespace std { +namespace polyfill { + +using stop_state_callbacks = list<function<void()>>; + +class stop_state { +public: + stop_state() = default; + ~stop_state() = default; + + bool request_stop() { + stop_state_callbacks callbacks; + + { + scoped_lock lk{m_lock}; + + if (m_stop_requested.load()) { + // Already set, nothing to do + return false; + } + + // Set as requested + m_stop_requested = true; + + // Copy callback list + callbacks = m_callbacks; + } + + for (auto callback : callbacks) { + callback(); + } + + return true; + } + + bool stop_requested() const { + return m_stop_requested.load(); + } + + stop_state_callbacks::const_iterator insert_callback(function<void()> f) { + stop_state_callbacks::const_iterator ret{}; + bool should_run{}; + + { + scoped_lock lk{m_lock}; + should_run = m_stop_requested.load(); + m_callbacks.push_front(f); + ret = m_callbacks.begin(); + } + + if (should_run) { + f(); + } + + return ret; + } + + void remove_callback(stop_state_callbacks::const_iterator it) { + scoped_lock lk{m_lock}; + m_callbacks.erase(it); + } + +private: + mutex m_lock; + atomic<bool> m_stop_requested; + stop_state_callbacks m_callbacks; +}; + +} // namespace polyfill + +class stop_token; +class stop_source; +struct nostopstate_t { + explicit nostopstate_t() = default; +}; +inline constexpr nostopstate_t nostopstate{}; + +template <class Callback> +class stop_callback; + +class stop_token { +public: + stop_token() noexcept = default; + + stop_token(const stop_token&) noexcept = default; + stop_token(stop_token&&) noexcept = default; + stop_token& operator=(const stop_token&) noexcept = default; + stop_token& operator=(stop_token&&) noexcept = default; + ~stop_token() = default; + + void swap(stop_token& other) noexcept { + m_stop_state.swap(other.m_stop_state); + } + + [[nodiscard]] bool stop_requested() const noexcept { + return m_stop_state && m_stop_state->stop_requested(); + } + [[nodiscard]] bool stop_possible() const noexcept { + return m_stop_state != nullptr; + } + +private: + friend class stop_source; + template <typename Callback> + friend class stop_callback; + stop_token(shared_ptr<polyfill::stop_state> stop_state) : m_stop_state(move(stop_state)) {} + +private: + shared_ptr<polyfill::stop_state> m_stop_state; +}; + +class stop_source { +public: + stop_source() : m_stop_state(make_shared<polyfill::stop_state>()) {} + explicit stop_source(nostopstate_t) noexcept {} + + stop_source(const stop_source&) noexcept = default; + stop_source(stop_source&&) noexcept = default; + stop_source& operator=(const stop_source&) noexcept = default; + stop_source& operator=(stop_source&&) noexcept = default; + ~stop_source() = default; + void swap(stop_source& other) noexcept { + m_stop_state.swap(other.m_stop_state); + } + + [[nodiscard]] stop_token get_token() const noexcept { + return stop_token(m_stop_state); + } + [[nodiscard]] bool stop_possible() const noexcept { + return m_stop_state != nullptr; + } + [[nodiscard]] bool stop_requested() const noexcept { + return m_stop_state && m_stop_state->stop_requested(); + } + bool request_stop() noexcept { + return m_stop_state && m_stop_state->request_stop(); + } + +private: + friend class jthread; + explicit stop_source(shared_ptr<polyfill::stop_state> stop_state) + : m_stop_state(move(stop_state)) {} + +private: + shared_ptr<polyfill::stop_state> m_stop_state; +}; + +template <typename Callback> +class stop_callback { + static_assert(is_nothrow_destructible_v<Callback>); + static_assert(is_invocable_v<Callback>); + +public: + using callback_type = Callback; + + template <typename C> + requires constructible_from<Callback, C> + explicit stop_callback(const stop_token& st, + C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>) + : m_stop_state(st.m_stop_state) { + if (m_stop_state) { + m_callback = m_stop_state->insert_callback(move(cb)); + } + } + template <typename C> + requires constructible_from<Callback, C> + explicit stop_callback(stop_token&& st, + C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>) + : m_stop_state(move(st.m_stop_state)) { + if (m_stop_state) { + m_callback = m_stop_state->insert_callback(move(cb)); + } + } + ~stop_callback() { + if (m_stop_state && m_callback) { + m_stop_state->remove_callback(*m_callback); + } + } + + stop_callback(const stop_callback&) = delete; + stop_callback(stop_callback&&) = delete; + stop_callback& operator=(const stop_callback&) = delete; + stop_callback& operator=(stop_callback&&) = delete; + +private: + shared_ptr<polyfill::stop_state> m_stop_state; + optional<polyfill::stop_state_callbacks::const_iterator> m_callback; +}; + +template <typename Callback> +stop_callback(stop_token, Callback) -> stop_callback<Callback>; + +class jthread { +public: + using id = thread::id; + using native_handle_type = thread::native_handle_type; + + jthread() noexcept = default; + + template <typename F, typename... Args, + typename = enable_if_t<!is_same_v<remove_cvref_t<F>, jthread>>> + explicit jthread(F&& f, Args&&... args) + : m_stop_state(make_shared<polyfill::stop_state>()), + m_thread(make_thread(move(f), move(args)...)) {} + + ~jthread() { + if (joinable()) { + request_stop(); + join(); + } + } + + jthread(const jthread&) = delete; + jthread(jthread&&) noexcept = default; + jthread& operator=(const jthread&) = delete; + + jthread& operator=(jthread&& other) noexcept { + m_thread.swap(other.m_thread); + m_stop_state.swap(other.m_stop_state); + return *this; + } + + void swap(jthread& other) noexcept { + m_thread.swap(other.m_thread); + m_stop_state.swap(other.m_stop_state); + } + [[nodiscard]] bool joinable() const noexcept { + return m_thread.joinable(); + } + void join() { + m_thread.join(); + } + void detach() { + m_thread.detach(); + m_stop_state.reset(); + } + + [[nodiscard]] id get_id() const noexcept { + return m_thread.get_id(); + } + [[nodiscard]] native_handle_type native_handle() { + return m_thread.native_handle(); + } + [[nodiscard]] stop_source get_stop_source() noexcept { + return stop_source(m_stop_state); + } + [[nodiscard]] stop_token get_stop_token() const noexcept { + return stop_source(m_stop_state).get_token(); + } + bool request_stop() noexcept { + return get_stop_source().request_stop(); + } + [[nodiscard]] static unsigned int hardware_concurrency() noexcept { + return thread::hardware_concurrency(); + } + +private: + template <typename F, typename... Args> + thread make_thread(F&& f, Args&&... args) { + if constexpr (is_invocable_v<decay_t<F>, stop_token, decay_t<Args>...>) { + return thread(move(f), get_stop_token(), move(args)...); + } else { + return thread(move(f), move(args)...); + } + } + + shared_ptr<polyfill::stop_state> m_stop_state; + thread m_thread; +}; + +} // namespace std + +namespace Common { + +template <typename Condvar, typename Lock, typename Pred> +void CondvarWait(Condvar& cv, Lock& lock, std::stop_token token, Pred pred) { + if (token.stop_requested()) { + return; + } + + std::stop_callback callback(token, [&] { cv.notify_all(); }); + cv.wait(lock, [&] { return pred() || token.stop_requested(); }); +} + +} // namespace Common + +#endif diff --git a/src/common/precompiled_headers.h b/src/common/precompiled_headers.h new file mode 100644 index 000000000..aabae730b --- /dev/null +++ b/src/common/precompiled_headers.h @@ -0,0 +1,6 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_precompiled_headers.h" diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index 7a495bc79..b26db4796 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp @@ -141,7 +141,7 @@ static std::wstring CPToUTF16(u32 code_page, const std::string& input) { MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()), nullptr, 0); if (size == 0) { - return L""; + return {}; } std::wstring output(size, L'\0'); @@ -158,7 +158,7 @@ std::string UTF16ToUTF8(const std::wstring& input) { const auto size = WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()), nullptr, 0, nullptr, nullptr); if (size == 0) { - return ""; + return {}; } std::string output(size, '\0'); diff --git a/src/common/thread_worker.h b/src/common/thread_worker.h index 62c60f724..260ad44e4 100644 --- a/src/common/thread_worker.h +++ b/src/common/thread_worker.h @@ -7,13 +7,13 @@ #include <condition_variable> #include <functional> #include <mutex> -#include <stop_token> #include <string> #include <thread> #include <type_traits> #include <vector> #include <queue> +#include "common/polyfill_thread.h" #include "common/thread.h" #include "common/unique_function.h" @@ -47,7 +47,8 @@ public: if (requests.empty()) { wait_condition.notify_all(); } - condition.wait(lock, stop_token, [this] { return !requests.empty(); }); + Common::CondvarWait(condition, lock, stop_token, + [this] { return !requests.empty(); }); if (stop_token.stop_requested()) { break; } diff --git a/src/common/threadsafe_queue.h b/src/common/threadsafe_queue.h index 053798e79..2ef1da064 100644 --- a/src/common/threadsafe_queue.h +++ b/src/common/threadsafe_queue.h @@ -12,6 +12,8 @@ #include <mutex> #include <utility> +#include "common/polyfill_thread.h" + namespace Common { template <typename T, bool with_stop_token = false> class SPSCQueue { @@ -97,7 +99,7 @@ public: T PopWait(std::stop_token stop_token) { if (Empty()) { std::unique_lock lock{cv_mutex}; - cv.wait(lock, stop_token, [this] { return !Empty(); }); + Common::CondvarWait(cv, lock, stop_token, [this] { return !Empty(); }); } if (stop_token.stop_requested()) { return T{}; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 5629980d9..6530d3c60 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -771,6 +771,7 @@ add_library(core STATIC memory.h perf_stats.cpp perf_stats.h + precompiled_headers.h reporter.cpp reporter.h telemetry_session.cpp @@ -825,3 +826,7 @@ if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) ) target_link_libraries(core PRIVATE dynarmic) endif() + +if (YUZU_USE_PRECOMPILED_HEADERS) + target_precompile_headers(core PRIVATE precompiled_headers.h) +endif() diff --git a/src/core/core.cpp b/src/core/core.cpp index d8934be52..94d4e2212 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -189,7 +189,7 @@ struct System::Impl { kernel.Suspend(false); core_timing.SyncPause(false); - is_paused = false; + is_paused.store(false, std::memory_order_relaxed); return status; } @@ -200,14 +200,13 @@ struct System::Impl { core_timing.SyncPause(true); kernel.Suspend(true); - is_paused = true; + is_paused.store(true, std::memory_order_relaxed); return status; } bool IsPaused() const { - std::unique_lock lk(suspend_guard); - return is_paused; + return is_paused.load(std::memory_order_relaxed); } std::unique_lock<std::mutex> StallProcesses() { @@ -218,7 +217,7 @@ struct System::Impl { } void UnstallProcesses() { - if (!is_paused) { + if (!IsPaused()) { core_timing.SyncPause(false); kernel.Suspend(false); } @@ -465,7 +464,7 @@ struct System::Impl { } mutable std::mutex suspend_guard; - bool is_paused{}; + std::atomic_bool is_paused{}; std::atomic<bool> is_shutting_down{}; Timing::CoreTiming core_timing; diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h index 95ea3ef39..374367468 100644 --- a/src/core/cpu_manager.h +++ b/src/core/cpu_manager.h @@ -10,6 +10,7 @@ #include <thread> #include "common/fiber.h" +#include "common/polyfill_thread.h" #include "common/thread.h" #include "core/hardware_properties.h" diff --git a/src/core/debugger/debugger.cpp b/src/core/debugger/debugger.cpp index 1a8e02e6a..a9675df76 100644 --- a/src/core/debugger/debugger.cpp +++ b/src/core/debugger/debugger.cpp @@ -9,6 +9,7 @@ #include <boost/process/async_pipe.hpp> #include "common/logging/log.h" +#include "common/polyfill_thread.h" #include "common/thread.h" #include "core/core.h" #include "core/debugger/debugger.h" diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index 78e56bbbd..50303fe42 100644 --- a/src/core/file_sys/content_archive.cpp +++ b/src/core/file_sys/content_archive.cpp @@ -7,6 +7,7 @@ #include <utility> #include "common/logging/log.h" +#include "common/polyfill_ranges.h" #include "core/crypto/aes_util.h" #include "core/crypto/ctr_encryption_layer.h" #include "core/crypto/key_manager.h" diff --git a/src/core/frontend/applets/controller.h b/src/core/frontend/applets/controller.h index 1d2850ad5..71698df74 100644 --- a/src/core/frontend/applets/controller.h +++ b/src/core/frontend/applets/controller.h @@ -4,6 +4,7 @@ #pragma once #include <functional> +#include <vector> #include "common/common_types.h" diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index ac1906d5e..95363b645 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h @@ -17,6 +17,8 @@ enum class WindowSystemType { Windows, X11, Wayland, + Cocoa, + Android, }; /** diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index fb7e5802a..b6c8cc58d 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -68,7 +68,7 @@ void EmulatedConsole::ReloadInput() { // If you load any device here add the equivalent to the UnloadInput() function SetTouchParams(); - motion_devices = Common::Input::CreateDevice<Common::Input::InputDevice>(motion_params); + motion_devices = Common::Input::CreateInputDevice(motion_params); if (motion_devices) { motion_devices->SetCallback({ .on_change = @@ -79,7 +79,7 @@ void EmulatedConsole::ReloadInput() { // Unique index for identifying touch device source std::size_t index = 0; for (auto& touch_device : touch_devices) { - touch_device = Common::Input::CreateDevice<Common::Input::InputDevice>(touch_params[index]); + touch_device = Common::Input::CreateInputDevice(touch_params[index]); if (!touch_device) { continue; } diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index ec1364452..c96d9eef3 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include <algorithm> + #include "common/thread.h" #include "core/hid/emulated_controller.h" #include "core/hid/input_converter.h" @@ -144,29 +146,23 @@ void EmulatedController::LoadDevices() { LoadTASParams(); - std::transform(button_params.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, - button_params.begin() + Settings::NativeButton::BUTTON_NS_END, - button_devices.begin(), Common::Input::CreateDevice<Common::Input::InputDevice>); - std::transform(stick_params.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, - stick_params.begin() + Settings::NativeAnalog::STICK_HID_END, - stick_devices.begin(), Common::Input::CreateDevice<Common::Input::InputDevice>); - std::transform(motion_params.begin() + Settings::NativeMotion::MOTION_HID_BEGIN, - motion_params.begin() + Settings::NativeMotion::MOTION_HID_END, - motion_devices.begin(), Common::Input::CreateDevice<Common::Input::InputDevice>); - std::transform(trigger_params.begin(), trigger_params.end(), trigger_devices.begin(), - Common::Input::CreateDevice<Common::Input::InputDevice>); - std::transform(battery_params.begin(), battery_params.end(), battery_devices.begin(), - Common::Input::CreateDevice<Common::Input::InputDevice>); - camera_devices = Common::Input::CreateDevice<Common::Input::InputDevice>(camera_params); - nfc_devices = Common::Input::CreateDevice<Common::Input::InputDevice>(nfc_params); - std::transform(output_params.begin(), output_params.end(), output_devices.begin(), - Common::Input::CreateDevice<Common::Input::OutputDevice>); + std::ranges::transform(button_params, button_devices.begin(), Common::Input::CreateInputDevice); + std::ranges::transform(stick_params, stick_devices.begin(), Common::Input::CreateInputDevice); + std::ranges::transform(motion_params, motion_devices.begin(), Common::Input::CreateInputDevice); + std::ranges::transform(trigger_params, trigger_devices.begin(), + Common::Input::CreateInputDevice); + std::ranges::transform(battery_params, battery_devices.begin(), + Common::Input::CreateInputDevice); + camera_devices = Common::Input::CreateInputDevice(camera_params); + nfc_devices = Common::Input::CreateInputDevice(nfc_params); + std::ranges::transform(output_params, output_devices.begin(), + Common::Input::CreateOutputDevice); // Initialize TAS devices - std::transform(tas_button_params.begin(), tas_button_params.end(), tas_button_devices.begin(), - Common::Input::CreateDevice<Common::Input::InputDevice>); - std::transform(tas_stick_params.begin(), tas_stick_params.end(), tas_stick_devices.begin(), - Common::Input::CreateDevice<Common::Input::InputDevice>); + std::ranges::transform(tas_button_params, tas_button_devices.begin(), + Common::Input::CreateInputDevice); + std::ranges::transform(tas_stick_params, tas_stick_devices.begin(), + Common::Input::CreateInputDevice); } void EmulatedController::LoadTASParams() { diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index d004ca56a..3f83108d3 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -8,6 +8,7 @@ #include <memory> #include <mutex> #include <unordered_map> +#include <vector> #include "common/common_types.h" #include "common/input.h" diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp index 658dbd318..e421828d2 100644 --- a/src/core/hid/emulated_devices.cpp +++ b/src/core/hid/emulated_devices.cpp @@ -25,12 +25,12 @@ void EmulatedDevices::ReloadInput() { Common::ParamPackage mouse_params; mouse_params.Set("engine", "mouse"); mouse_params.Set("button", static_cast<int>(key_index)); - mouse_device = Common::Input::CreateDevice<Common::Input::InputDevice>(mouse_params); + mouse_device = Common::Input::CreateInputDevice(mouse_params); key_index++; } - mouse_stick_device = Common::Input::CreateDeviceFromString<Common::Input::InputDevice>( - "engine:mouse,axis_x:0,axis_y:1"); + mouse_stick_device = + Common::Input::CreateInputDeviceFromString("engine:mouse,axis_x:0,axis_y:1"); // First two axis are reserved for mouse position key_index = 2; @@ -38,7 +38,7 @@ void EmulatedDevices::ReloadInput() { Common::ParamPackage mouse_params; mouse_params.Set("engine", "mouse"); mouse_params.Set("axis", static_cast<int>(key_index)); - mouse_device = Common::Input::CreateDevice<Common::Input::InputDevice>(mouse_params); + mouse_device = Common::Input::CreateInputDevice(mouse_params); key_index++; } @@ -50,7 +50,7 @@ void EmulatedDevices::ReloadInput() { keyboard_params.Set("button", static_cast<int>(key_index)); keyboard_params.Set("port", 1); keyboard_params.Set("pad", 0); - keyboard_device = Common::Input::CreateDevice<Common::Input::InputDevice>(keyboard_params); + keyboard_device = Common::Input::CreateInputDevice(keyboard_params); key_index++; } @@ -62,11 +62,11 @@ void EmulatedDevices::ReloadInput() { keyboard_params.Set("button", static_cast<int>(key_index)); keyboard_params.Set("port", 1); keyboard_params.Set("pad", 1); - keyboard_device = Common::Input::CreateDevice<Common::Input::InputDevice>(keyboard_params); + keyboard_device = Common::Input::CreateInputDevice(keyboard_params); key_index++; } - ring_analog_device = Common::Input::CreateDevice<Common::Input::InputDevice>(ring_params); + ring_analog_device = Common::Input::CreateInputDevice(ring_params); for (std::size_t index = 0; index < mouse_button_devices.size(); ++index) { if (!mouse_button_devices[index]) { diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h index 4149eeced..4cdbf9dc6 100644 --- a/src/core/hid/emulated_devices.h +++ b/src/core/hid/emulated_devices.h @@ -8,6 +8,7 @@ #include <memory> #include <mutex> #include <unordered_map> +#include <vector> #include "common/common_types.h" #include "common/input.h" diff --git a/src/core/hle/kernel/k_memory_manager.cpp b/src/core/hle/kernel/k_memory_manager.cpp index c4bf306e8..bd33571da 100644 --- a/src/core/hle/kernel/k_memory_manager.cpp +++ b/src/core/hle/kernel/k_memory_manager.cpp @@ -225,8 +225,8 @@ Result KMemoryManager::AllocatePageGroupImpl(KPageGroup* out, size_t num_pages, ON_RESULT_FAILURE { for (const auto& it : out->Nodes()) { auto& manager = this->GetManager(it.GetAddress()); - const size_t node_num_pages = - std::min(it.GetNumPages(), (manager.GetEndAddress() - it.GetAddress()) / PageSize); + const size_t node_num_pages = std::min<u64>( + it.GetNumPages(), (manager.GetEndAddress() - it.GetAddress()) / PageSize); manager.Free(it.GetAddress(), node_num_pages); } out->Finalize(); diff --git a/src/core/hle/kernel/k_slab_heap.h b/src/core/hle/kernel/k_slab_heap.h index a8c77a7d4..68469b041 100644 --- a/src/core/hle/kernel/k_slab_heap.h +++ b/src/core/hle/kernel/k_slab_heap.h @@ -6,6 +6,7 @@ #include <atomic> #include "common/assert.h" +#include "common/atomic_ops.h" #include "common/common_funcs.h" #include "common/common_types.h" #include "common/spin_lock.h" @@ -82,16 +83,13 @@ private: private: void UpdatePeakImpl(uintptr_t obj) { - static_assert(std::atomic_ref<uintptr_t>::is_always_lock_free); - std::atomic_ref<uintptr_t> peak_ref(m_peak); - const uintptr_t alloc_peak = obj + this->GetObjectSize(); uintptr_t cur_peak = m_peak; do { if (alloc_peak <= cur_peak) { break; } - } while (!peak_ref.compare_exchange_strong(cur_peak, alloc_peak)); + } while (!Common::AtomicCompareAndSwap(&m_peak, alloc_peak, cur_peak, cur_peak)); } public: diff --git a/src/core/hle/kernel/k_thread_local_page.h b/src/core/hle/kernel/k_thread_local_page.h index 5d466ace7..fe0cff084 100644 --- a/src/core/hle/kernel/k_thread_local_page.h +++ b/src/core/hle/kernel/k_thread_local_page.h @@ -10,6 +10,7 @@ #include "common/assert.h" #include "common/common_types.h" #include "common/intrusive_red_black_tree.h" +#include "common/polyfill_ranges.h" #include "core/hle/kernel/memory_types.h" #include "core/hle/kernel/slab_helpers.h" #include "core/hle/result.h" diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp index e6e41ac34..0690f9a1c 100644 --- a/src/core/hle/kernel/service_thread.cpp +++ b/src/core/hle/kernel/service_thread.cpp @@ -7,6 +7,7 @@ #include <thread> #include <vector> +#include "common/polyfill_thread.h" #include "common/scope_exit.h" #include "common/thread.h" #include "core/hle/ipc_helpers.h" diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 3730937fe..1ea8c7fbc 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -82,7 +82,7 @@ void SvcWrap64(Core::System& system) { } // Used by ControlCodeMemory -template <Result func(Core::System&, Handle, u32, u64, u64, Svc::MemoryPermission)> +template <Result func(Core::System&, Handle, u32, VAddr, size_t, Svc::MemoryPermission)> void SvcWrap64(Core::System& system) { FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)), static_cast<u32>(Param(system, 1)), Param(system, 2), Param(system, 3), @@ -327,7 +327,7 @@ void SvcWrap64(Core::System& system) { } // Used by CreateCodeMemory -template <Result func(Core::System&, Handle*, u64, u64)> +template <Result func(Core::System&, Handle*, VAddr, size_t)> void SvcWrap64(Core::System& system) { u32 param_1 = 0; const u32 retval = func(system, ¶m_1, Param(system, 1), Param(system, 2)).raw; diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 85a3f0802..6d1084fd1 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -7,6 +7,7 @@ #include "common/fs/file.h" #include "common/fs/path_util.h" #include "common/logging/log.h" +#include "common/polyfill_ranges.h" #include "common/string_util.h" #include "common/swap.h" #include "core/constants.h" diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index 481e0d141..97f7c6688 100644 --- a/src/core/hle/service/acc/profile_manager.cpp +++ b/src/core/hle/service/acc/profile_manager.cpp @@ -9,6 +9,7 @@ #include "common/fs/file.h" #include "common/fs/fs.h" #include "common/fs/path_util.h" +#include "common/polyfill_ranges.h" #include "common/settings.h" #include "core/hle/service/acc/profile_manager.h" diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 8ea7fd760..22999c942 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -1125,7 +1125,7 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { const u64 offset{rp.Pop<u64>()}; const std::vector<u8> data{ctx.ReadBuffer()}; - const std::size_t size{std::min(data.size(), backing.GetSize() - offset)}; + const std::size_t size{std::min<u64>(data.size(), backing.GetSize() - offset)}; LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); @@ -1149,7 +1149,7 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const u64 offset{rp.Pop<u64>()}; - const std::size_t size{std::min(ctx.GetWriteBufferSize(), backing.GetSize() - offset)}; + const std::size_t size{std::min<u64>(ctx.GetWriteBufferSize(), backing.GetSize() - offset)}; LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 034ee273f..3a1c231b6 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -14,6 +14,7 @@ #include "common/bit_util.h" #include "common/common_funcs.h" #include "common/logging/log.h" +#include "common/polyfill_ranges.h" #include "common/string_util.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index e3ef06481..4fa9f51a6 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp @@ -129,6 +129,9 @@ static_assert(sizeof(NifmNetworkProfileData) == 0x18E, "NifmNetworkProfileData has incorrect size."); #pragma pack(pop) +constexpr Result ResultPendingConnection{ErrorModule::NIFM, 111}; +constexpr Result ResultNetworkCommunicationDisabled{ErrorModule::NIFM, 1111}; + class IScanRequest final : public ServiceFramework<IScanRequest> { public: explicit IScanRequest(Core::System& system_) : ServiceFramework{system_, "IScanRequest"} { @@ -192,6 +195,10 @@ private: void Submit(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_NIFM, "(STUBBED) called"); + if (state == RequestState::NotSubmitted) { + UpdateState(RequestState::Pending); + } + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } @@ -201,19 +208,32 @@ private: IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - - if (Network::GetHostIPv4Address().has_value()) { - rb.PushEnum(RequestState::Connected); - } else { - rb.PushEnum(RequestState::NotSubmitted); - } + rb.PushEnum(state); } void GetResult(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_NIFM, "(STUBBED) called"); + const auto result = [this] { + const auto has_connection = Network::GetHostIPv4Address().has_value(); + switch (state) { + case RequestState::NotSubmitted: + return has_connection ? ResultSuccess : ResultNetworkCommunicationDisabled; + case RequestState::Pending: + if (has_connection) { + UpdateState(RequestState::Connected); + } else { + UpdateState(RequestState::Error); + } + return ResultPendingConnection; + case RequestState::Connected: + default: + return ResultSuccess; + } + }(); + IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void GetSystemEventReadableHandles(Kernel::HLERequestContext& ctx) { @@ -252,8 +272,15 @@ private: rb.Push<u32>(0); } + void UpdateState(RequestState new_state) { + state = new_state; + event1->Signal(); + } + KernelHelpers::ServiceContext service_context; + RequestState state; + Kernel::KEvent* event1; Kernel::KEvent* event2; }; diff --git a/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp b/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp index eda2041a0..aba51d280 100644 --- a/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp +++ b/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp @@ -28,13 +28,15 @@ SyncpointManager::SyncpointManager(Tegra::Host1x::Host1x& host1x_) : host1x{host SyncpointManager::~SyncpointManager() = default; u32 SyncpointManager::ReserveSyncpoint(u32 id, bool client_managed) { - if (syncpoints.at(id).reserved) { + auto& syncpoint = syncpoints.at(id); + + if (syncpoint.reserved) { ASSERT_MSG(false, "Requested syncpoint is in use"); return 0; } - syncpoints.at(id).reserved = true; - syncpoints.at(id).interface_managed = client_managed; + syncpoint.reserved = true; + syncpoint.interface_managed = client_managed; return id; } @@ -56,11 +58,12 @@ u32 SyncpointManager::AllocateSyncpoint(bool client_managed) { void SyncpointManager::FreeSyncpoint(u32 id) { std::lock_guard lock(reservation_lock); - ASSERT(syncpoints.at(id).reserved); - syncpoints.at(id).reserved = false; + auto& syncpoint = syncpoints.at(id); + ASSERT(syncpoint.reserved); + syncpoint.reserved = false; } -bool SyncpointManager::IsSyncpointAllocated(u32 id) { +bool SyncpointManager::IsSyncpointAllocated(u32 id) const { return (id <= SyncpointCount) && syncpoints[id].reserved; } @@ -69,7 +72,7 @@ bool SyncpointManager::HasSyncpointExpired(u32 id, u32 threshold) const { if (!syncpoint.reserved) { ASSERT(false); - return 0; + return false; } // If the interface manages counters then we don't keep track of the maximum value as it handles @@ -82,40 +85,51 @@ bool SyncpointManager::HasSyncpointExpired(u32 id, u32 threshold) const { } u32 SyncpointManager::IncrementSyncpointMaxExt(u32 id, u32 amount) { - if (!syncpoints.at(id).reserved) { + auto& syncpoint = syncpoints.at(id); + + if (!syncpoint.reserved) { ASSERT(false); return 0; } - return syncpoints.at(id).counter_max += amount; + return syncpoint.counter_max += amount; } u32 SyncpointManager::ReadSyncpointMinValue(u32 id) { - if (!syncpoints.at(id).reserved) { + auto& syncpoint = syncpoints.at(id); + + if (!syncpoint.reserved) { ASSERT(false); return 0; } - return syncpoints.at(id).counter_min; + return syncpoint.counter_min; } u32 SyncpointManager::UpdateMin(u32 id) { - if (!syncpoints.at(id).reserved) { + auto& syncpoint = syncpoints.at(id); + + if (!syncpoint.reserved) { ASSERT(false); return 0; } - syncpoints.at(id).counter_min = host1x.GetSyncpointManager().GetHostSyncpointValue(id); - return syncpoints.at(id).counter_min; + syncpoint.counter_min = host1x.GetSyncpointManager().GetHostSyncpointValue(id); + return syncpoint.counter_min; } NvFence SyncpointManager::GetSyncpointFence(u32 id) { - if (!syncpoints.at(id).reserved) { + auto& syncpoint = syncpoints.at(id); + + if (!syncpoint.reserved) { ASSERT(false); return NvFence{}; } - return {.id = static_cast<s32>(id), .value = syncpoints.at(id).counter_max}; + return { + .id = static_cast<s32>(id), + .value = syncpoint.counter_max, + }; } } // namespace Service::Nvidia::NvCore diff --git a/src/core/hle/service/nvdrv/core/syncpoint_manager.h b/src/core/hle/service/nvdrv/core/syncpoint_manager.h index b76ef9032..4f2cefae5 100644 --- a/src/core/hle/service/nvdrv/core/syncpoint_manager.h +++ b/src/core/hle/service/nvdrv/core/syncpoint_manager.h @@ -44,7 +44,7 @@ public: /** * @brief Checks if the given syncpoint is both allocated and below the number of HW syncpoints */ - bool IsSyncpointAllocated(u32 id); + bool IsSyncpointAllocated(u32 id) const; /** * @brief Finds a free syncpoint and reserves it diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 9f4c7c99a..6fc8565c0 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -55,48 +55,40 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger Module::Module(Core::System& system) : container{system.Host1x()}, service_context{system, "nvdrv"}, events_interface{*this} { builders["/dev/nvhost-as-gpu"] = [this, &system](DeviceFD fd) { - std::shared_ptr<Devices::nvdevice> device = - std::make_shared<Devices::nvhost_as_gpu>(system, *this, container); - return open_files.emplace(fd, device).first; + auto device = std::make_shared<Devices::nvhost_as_gpu>(system, *this, container); + return open_files.emplace(fd, std::move(device)).first; }; builders["/dev/nvhost-gpu"] = [this, &system](DeviceFD fd) { - std::shared_ptr<Devices::nvdevice> device = - std::make_shared<Devices::nvhost_gpu>(system, events_interface, container); - return open_files.emplace(fd, device).first; + auto device = std::make_shared<Devices::nvhost_gpu>(system, events_interface, container); + return open_files.emplace(fd, std::move(device)).first; }; builders["/dev/nvhost-ctrl-gpu"] = [this, &system](DeviceFD fd) { - std::shared_ptr<Devices::nvdevice> device = - std::make_shared<Devices::nvhost_ctrl_gpu>(system, events_interface); - return open_files.emplace(fd, device).first; + auto device = std::make_shared<Devices::nvhost_ctrl_gpu>(system, events_interface); + return open_files.emplace(fd, std::move(device)).first; }; builders["/dev/nvmap"] = [this, &system](DeviceFD fd) { - std::shared_ptr<Devices::nvdevice> device = - std::make_shared<Devices::nvmap>(system, container); - return open_files.emplace(fd, device).first; + auto device = std::make_shared<Devices::nvmap>(system, container); + return open_files.emplace(fd, std::move(device)).first; }; builders["/dev/nvdisp_disp0"] = [this, &system](DeviceFD fd) { - std::shared_ptr<Devices::nvdevice> device = - std::make_shared<Devices::nvdisp_disp0>(system, container); - return open_files.emplace(fd, device).first; + auto device = std::make_shared<Devices::nvdisp_disp0>(system, container); + return open_files.emplace(fd, std::move(device)).first; }; builders["/dev/nvhost-ctrl"] = [this, &system](DeviceFD fd) { - std::shared_ptr<Devices::nvdevice> device = - std::make_shared<Devices::nvhost_ctrl>(system, events_interface, container); - return open_files.emplace(fd, device).first; + auto device = std::make_shared<Devices::nvhost_ctrl>(system, events_interface, container); + return open_files.emplace(fd, std::move(device)).first; }; builders["/dev/nvhost-nvdec"] = [this, &system](DeviceFD fd) { - std::shared_ptr<Devices::nvdevice> device = - std::make_shared<Devices::nvhost_nvdec>(system, container); - return open_files.emplace(fd, device).first; + auto device = std::make_shared<Devices::nvhost_nvdec>(system, container); + return open_files.emplace(fd, std::move(device)).first; }; builders["/dev/nvhost-nvjpg"] = [this, &system](DeviceFD fd) { - std::shared_ptr<Devices::nvdevice> device = std::make_shared<Devices::nvhost_nvjpg>(system); - return open_files.emplace(fd, device).first; + auto device = std::make_shared<Devices::nvhost_nvjpg>(system); + return open_files.emplace(fd, std::move(device)).first; }; builders["/dev/nvhost-vic"] = [this, &system](DeviceFD fd) { - std::shared_ptr<Devices::nvdevice> device = - std::make_shared<Devices::nvhost_vic>(system, container); - return open_files.emplace(fd, device).first; + auto device = std::make_shared<Devices::nvhost_vic>(system, container); + return open_files.emplace(fd, std::move(device)).first; }; } diff --git a/src/core/hle/service/nvflinger/buffer_item_consumer.cpp b/src/core/hle/service/nvflinger/buffer_item_consumer.cpp index 6d2c92a2c..152bb5bdf 100644 --- a/src/core/hle/service/nvflinger/buffer_item_consumer.cpp +++ b/src/core/hle/service/nvflinger/buffer_item_consumer.cpp @@ -39,7 +39,7 @@ Status BufferItemConsumer::AcquireBuffer(BufferItem* item, std::chrono::nanoseco return Status::NoError; } -Status BufferItemConsumer::ReleaseBuffer(const BufferItem& item, Fence& release_fence) { +Status BufferItemConsumer::ReleaseBuffer(const BufferItem& item, const Fence& release_fence) { std::scoped_lock lock{mutex}; if (const auto status = AddReleaseFenceLocked(item.buf, item.graphic_buffer, release_fence); diff --git a/src/core/hle/service/nvflinger/buffer_item_consumer.h b/src/core/hle/service/nvflinger/buffer_item_consumer.h index 69046233d..a5c655d9e 100644 --- a/src/core/hle/service/nvflinger/buffer_item_consumer.h +++ b/src/core/hle/service/nvflinger/buffer_item_consumer.h @@ -22,7 +22,7 @@ public: explicit BufferItemConsumer(std::unique_ptr<BufferQueueConsumer> consumer); Status AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when, bool wait_for_fence = true); - Status ReleaseBuffer(const BufferItem& item, Fence& release_fence); + Status ReleaseBuffer(const BufferItem& item, const Fence& release_fence); }; } // namespace Service::android diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp index 1ce67c771..0767e548d 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp @@ -169,7 +169,7 @@ Status BufferQueueConsumer::Connect(std::shared_ptr<IConsumerListener> consumer_ return Status::NoInit; } - core->consumer_listener = consumer_listener; + core->consumer_listener = std::move(consumer_listener); core->consumer_controlled_by_app = controlled_by_app; return Status::NoError; diff --git a/src/core/hle/service/nvflinger/consumer_base.cpp b/src/core/hle/service/nvflinger/consumer_base.cpp index 5b9995854..982531e2d 100644 --- a/src/core/hle/service/nvflinger/consumer_base.cpp +++ b/src/core/hle/service/nvflinger/consumer_base.cpp @@ -83,7 +83,7 @@ Status ConsumerBase::AcquireBufferLocked(BufferItem* item, std::chrono::nanoseco } Status ConsumerBase::AddReleaseFenceLocked(s32 slot, - const std::shared_ptr<GraphicBuffer> graphic_buffer, + const std::shared_ptr<GraphicBuffer>& graphic_buffer, const Fence& fence) { LOG_DEBUG(Service_NVFlinger, "slot={}", slot); @@ -100,7 +100,7 @@ Status ConsumerBase::AddReleaseFenceLocked(s32 slot, } Status ConsumerBase::ReleaseBufferLocked(s32 slot, - const std::shared_ptr<GraphicBuffer> graphic_buffer) { + const std::shared_ptr<GraphicBuffer>& graphic_buffer) { // If consumer no longer tracks this graphic_buffer (we received a new // buffer on the same slot), the buffer producer is definitely no longer // tracking it. @@ -121,7 +121,7 @@ Status ConsumerBase::ReleaseBufferLocked(s32 slot, } bool ConsumerBase::StillTracking(s32 slot, - const std::shared_ptr<GraphicBuffer> graphic_buffer) const { + const std::shared_ptr<GraphicBuffer>& graphic_buffer) const { if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { return false; } diff --git a/src/core/hle/service/nvflinger/consumer_base.h b/src/core/hle/service/nvflinger/consumer_base.h index 90ba07f45..9a8a5f6bb 100644 --- a/src/core/hle/service/nvflinger/consumer_base.h +++ b/src/core/hle/service/nvflinger/consumer_base.h @@ -27,18 +27,18 @@ public: protected: explicit ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_); - virtual ~ConsumerBase(); + ~ConsumerBase() override; - virtual void OnFrameAvailable(const BufferItem& item) override; - virtual void OnFrameReplaced(const BufferItem& item) override; - virtual void OnBuffersReleased() override; - virtual void OnSidebandStreamChanged() override; + void OnFrameAvailable(const BufferItem& item) override; + void OnFrameReplaced(const BufferItem& item) override; + void OnBuffersReleased() override; + void OnSidebandStreamChanged() override; void FreeBufferLocked(s32 slot_index); Status AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when); - Status ReleaseBufferLocked(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer); - bool StillTracking(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer) const; - Status AddReleaseFenceLocked(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer, + Status ReleaseBufferLocked(s32 slot, const std::shared_ptr<GraphicBuffer>& graphic_buffer); + bool StillTracking(s32 slot, const std::shared_ptr<GraphicBuffer>& graphic_buffer) const; + Status AddReleaseFenceLocked(s32 slot, const std::shared_ptr<GraphicBuffer>& graphic_buffer, const Fence& fence); struct Slot final { diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index c3af12c90..d1cbadde4 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -307,8 +307,7 @@ void NVFlinger::Compose() { swap_interval = buffer.swap_interval; - auto fence = android::Fence::NoFence(); - layer.GetConsumer().ReleaseBuffer(buffer, fence); + layer.GetConsumer().ReleaseBuffer(buffer, android::Fence::NoFence()); } } diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 460bef976..9b22397db 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h @@ -11,6 +11,7 @@ #include <vector> #include "common/common_types.h" +#include "common/polyfill_thread.h" #include "core/hle/result.h" #include "core/hle/service/kernel_helpers.h" diff --git a/src/core/hle/service/nvflinger/producer_listener.h b/src/core/hle/service/nvflinger/producer_listener.h index 1c4d5db0e..6bf8aaf1e 100644 --- a/src/core/hle/service/nvflinger/producer_listener.h +++ b/src/core/hle/service/nvflinger/producer_listener.h @@ -10,6 +10,7 @@ namespace Service::android { class IProducerListener { public: + virtual ~IProducerListener() = default; virtual void OnBufferReleased() = 0; }; diff --git a/src/core/internal_network/network_interface.cpp b/src/core/internal_network/network_interface.cpp index 057fd3661..7b8e510a2 100644 --- a/src/core/internal_network/network_interface.cpp +++ b/src/core/internal_network/network_interface.cpp @@ -9,6 +9,7 @@ #include "common/bit_cast.h" #include "common/common_types.h" #include "common/logging/log.h" +#include "common/polyfill_ranges.h" #include "common/settings.h" #include "common/string_util.h" #include "core/internal_network/network_interface.h" diff --git a/src/core/precompiled_headers.h b/src/core/precompiled_headers.h new file mode 100644 index 000000000..30a31001d --- /dev/null +++ b/src/core/precompiled_headers.h @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <boost/container/flat_map.hpp> // used by service.h which is heavily included +#include <boost/intrusive/rbtree.hpp> // used by k_auto_object.h which is heavily included + +#include "common/common_precompiled_headers.h" + +#include "core/hle/kernel/k_process.h" diff --git a/src/dedicated_room/CMakeLists.txt b/src/dedicated_room/CMakeLists.txt index 2d9731f19..5bbe1d4b5 100644 --- a/src/dedicated_room/CMakeLists.txt +++ b/src/dedicated_room/CMakeLists.txt @@ -4,6 +4,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules) add_executable(yuzu-room + precompiled_headers.h yuzu_room.cpp yuzu_room.rc ) @@ -25,3 +26,7 @@ target_link_libraries(yuzu-room PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) if(UNIX AND NOT APPLE) install(TARGETS yuzu-room) endif() + +if (YUZU_USE_PRECOMPILED_HEADERS) + target_precompile_headers(yuzu-room PRIVATE precompiled_headers.h) +endif() diff --git a/src/dedicated_room/precompiled_headers.h b/src/dedicated_room/precompiled_headers.h new file mode 100644 index 000000000..aabae730b --- /dev/null +++ b/src/dedicated_room/precompiled_headers.h @@ -0,0 +1,6 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_precompiled_headers.h" diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index cc6f0ffc0..e41da2726 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -34,6 +34,7 @@ add_library(input_common STATIC input_poller.h main.cpp main.h + precompiled_headers.h ) if (MSVC) @@ -55,7 +56,11 @@ if (ENABLE_SDL2) drivers/sdl_driver.cpp drivers/sdl_driver.h ) - target_link_libraries(input_common PRIVATE SDL2) + if (YUZU_USE_EXTERNAL_SDL2) + target_link_libraries(input_common PRIVATE SDL2-static) + else() + target_link_libraries(input_common PRIVATE SDL2) + endif() target_compile_definitions(input_common PRIVATE HAVE_SDL2) endif() @@ -63,3 +68,7 @@ target_link_libraries(input_common PRIVATE usb) create_target_directory_groups(input_common) target_link_libraries(input_common PUBLIC core PRIVATE common Boost::boost) + +if (YUZU_USE_PRECOMPILED_HEADERS) + target_precompile_headers(input_common PRIVATE precompiled_headers.h) +endif() diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h index 7f81767f7..b5270fd0b 100644 --- a/src/input_common/drivers/gc_adapter.h +++ b/src/input_common/drivers/gc_adapter.h @@ -5,10 +5,10 @@ #include <array> #include <memory> -#include <stop_token> #include <string> #include <thread> +#include "common/polyfill_thread.h" #include "input_common/input_engine.h" struct libusb_context; diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp index 98c3157a8..faf9cbdc3 100644 --- a/src/input_common/drivers/mouse.cpp +++ b/src/input_common/drivers/mouse.cpp @@ -1,7 +1,6 @@ // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include <stop_token> #include <thread> #include <fmt/format.h> diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h index 286ce1cf6..72073cc23 100644 --- a/src/input_common/drivers/mouse.h +++ b/src/input_common/drivers/mouse.h @@ -3,9 +3,9 @@ #pragma once -#include <stop_token> #include <thread> +#include "common/polyfill_thread.h" #include "common/vector_math.h" #include "input_common/input_engine.h" diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index 45ce588f0..8de86b61e 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -361,6 +361,12 @@ void SDLDriver::CloseJoystick(SDL_Joystick* sdl_joystick) { } } +void SDLDriver::PumpEvents() const { + if (initialized) { + SDL_PumpEvents(); + } +} + void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) { switch (event.type) { case SDL_JOYBUTTONUP: { @@ -451,14 +457,6 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en initialized = true; if (start_thread) { - poll_thread = std::thread([this] { - Common::SetCurrentThreadName("SDL_MainLoop"); - using namespace std::chrono_literals; - while (initialized) { - SDL_PumpEvents(); - std::this_thread::sleep_for(1ms); - } - }); vibration_thread = std::thread([this] { Common::SetCurrentThreadName("SDL_Vibration"); using namespace std::chrono_literals; @@ -481,7 +479,6 @@ SDLDriver::~SDLDriver() { initialized = false; if (start_thread) { - poll_thread.join(); vibration_thread.join(); SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER); } diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h index d1b4471cf..366bcc496 100644 --- a/src/input_common/drivers/sdl_driver.h +++ b/src/input_common/drivers/sdl_driver.h @@ -36,6 +36,8 @@ public: /// Unregisters SDL device factories and shut them down. ~SDLDriver() override; + void PumpEvents() const; + /// Handle SDL_Events for joysticks from SDL_PollEvent void HandleGameControllerEvent(const SDL_Event& event); @@ -128,7 +130,6 @@ private: bool start_thread = false; std::atomic<bool> initialized = false; - std::thread poll_thread; std::thread vibration_thread; }; } // namespace InputCommon diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index 21c6ed405..f3ade90da 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include <cstring> +#include <sstream> #include <fmt/format.h> #include "common/fs/file.h" diff --git a/src/input_common/helpers/stick_from_buttons.cpp b/src/input_common/helpers/stick_from_buttons.cpp index 536d413a5..82aa6ac2f 100644 --- a/src/input_common/helpers/stick_from_buttons.cpp +++ b/src/input_common/helpers/stick_from_buttons.cpp @@ -294,6 +294,15 @@ public: } private: + static constexpr Common::Input::AnalogProperties properties{ + .deadzone = 0.0f, + .range = 1.0f, + .threshold = 0.5f, + .offset = 0.0f, + .inverted = false, + .toggle = false, + }; + Button up; Button down; Button left; @@ -311,23 +320,17 @@ private: float last_x_axis_value{}; float last_y_axis_value{}; Common::Input::ButtonStatus modifier_status{}; - const Common::Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; std::chrono::time_point<std::chrono::steady_clock> last_update; }; std::unique_ptr<Common::Input::InputDevice> StickFromButton::Create( const Common::ParamPackage& params) { const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize(); - auto up = Common::Input::CreateDeviceFromString<Common::Input::InputDevice>( - params.Get("up", null_engine)); - auto down = Common::Input::CreateDeviceFromString<Common::Input::InputDevice>( - params.Get("down", null_engine)); - auto left = Common::Input::CreateDeviceFromString<Common::Input::InputDevice>( - params.Get("left", null_engine)); - auto right = Common::Input::CreateDeviceFromString<Common::Input::InputDevice>( - params.Get("right", null_engine)); - auto modifier = Common::Input::CreateDeviceFromString<Common::Input::InputDevice>( - params.Get("modifier", null_engine)); + auto up = Common::Input::CreateInputDeviceFromString(params.Get("up", null_engine)); + auto down = Common::Input::CreateInputDeviceFromString(params.Get("down", null_engine)); + auto left = Common::Input::CreateInputDeviceFromString(params.Get("left", null_engine)); + auto right = Common::Input::CreateInputDeviceFromString(params.Get("right", null_engine)); + auto modifier = Common::Input::CreateInputDeviceFromString(params.Get("modifier", null_engine)); auto modifier_scale = params.Get("modifier_scale", 0.5f); auto modifier_angle = params.Get("modifier_angle", 5.5f); return std::make_unique<Stick>(std::move(up), std::move(down), std::move(left), diff --git a/src/input_common/helpers/touch_from_buttons.cpp b/src/input_common/helpers/touch_from_buttons.cpp index 003a38da5..e064b13d9 100644 --- a/src/input_common/helpers/touch_from_buttons.cpp +++ b/src/input_common/helpers/touch_from_buttons.cpp @@ -59,18 +59,25 @@ public: } private: + static constexpr Common::Input::AnalogProperties properties{ + .deadzone = 0.0f, + .range = 1.0f, + .threshold = 0.5f, + .offset = 0.0f, + .inverted = false, + .toggle = false, + }; + Button button; bool last_button_value; const float x; const float y; - const Common::Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; }; std::unique_ptr<Common::Input::InputDevice> TouchFromButton::Create( const Common::ParamPackage& params) { const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize(); - auto button = Common::Input::CreateDeviceFromString<Common::Input::InputDevice>( - params.Get("button", null_engine)); + auto button = Common::Input::CreateInputDeviceFromString(params.Get("button", null_engine)); const float x = params.Get("x", 0.0f) / 1280.0f; const float y = params.Get("y", 0.0f) / 720.0f; return std::make_unique<TouchFromButtonDevice>(std::move(button), x, y); diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 76df133f3..942a13535 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -33,129 +33,113 @@ struct InputSubsystem::Impl { keyboard->SetMappingCallback(mapping_callback); keyboard_factory = std::make_shared<InputFactory>(keyboard); keyboard_output_factory = std::make_shared<OutputFactory>(keyboard); - Common::Input::RegisterFactory<Common::Input::InputDevice>(keyboard->GetEngineName(), - keyboard_factory); - Common::Input::RegisterFactory<Common::Input::OutputDevice>(keyboard->GetEngineName(), - keyboard_output_factory); + Common::Input::RegisterInputFactory(keyboard->GetEngineName(), keyboard_factory); + Common::Input::RegisterOutputFactory(keyboard->GetEngineName(), keyboard_output_factory); mouse = std::make_shared<Mouse>("mouse"); mouse->SetMappingCallback(mapping_callback); mouse_factory = std::make_shared<InputFactory>(mouse); mouse_output_factory = std::make_shared<OutputFactory>(mouse); - Common::Input::RegisterFactory<Common::Input::InputDevice>(mouse->GetEngineName(), - mouse_factory); - Common::Input::RegisterFactory<Common::Input::OutputDevice>(mouse->GetEngineName(), - mouse_output_factory); + Common::Input::RegisterInputFactory(mouse->GetEngineName(), mouse_factory); + Common::Input::RegisterOutputFactory(mouse->GetEngineName(), mouse_output_factory); touch_screen = std::make_shared<TouchScreen>("touch"); touch_screen_factory = std::make_shared<InputFactory>(touch_screen); - Common::Input::RegisterFactory<Common::Input::InputDevice>(touch_screen->GetEngineName(), - touch_screen_factory); + Common::Input::RegisterInputFactory(touch_screen->GetEngineName(), touch_screen_factory); gcadapter = std::make_shared<GCAdapter>("gcpad"); gcadapter->SetMappingCallback(mapping_callback); gcadapter_input_factory = std::make_shared<InputFactory>(gcadapter); gcadapter_output_factory = std::make_shared<OutputFactory>(gcadapter); - Common::Input::RegisterFactory<Common::Input::InputDevice>(gcadapter->GetEngineName(), - gcadapter_input_factory); - Common::Input::RegisterFactory<Common::Input::OutputDevice>(gcadapter->GetEngineName(), - gcadapter_output_factory); + Common::Input::RegisterInputFactory(gcadapter->GetEngineName(), gcadapter_input_factory); + Common::Input::RegisterOutputFactory(gcadapter->GetEngineName(), gcadapter_output_factory); udp_client = std::make_shared<CemuhookUDP::UDPClient>("cemuhookudp"); udp_client->SetMappingCallback(mapping_callback); udp_client_input_factory = std::make_shared<InputFactory>(udp_client); udp_client_output_factory = std::make_shared<OutputFactory>(udp_client); - Common::Input::RegisterFactory<Common::Input::InputDevice>(udp_client->GetEngineName(), - udp_client_input_factory); - Common::Input::RegisterFactory<Common::Input::OutputDevice>(udp_client->GetEngineName(), - udp_client_output_factory); + Common::Input::RegisterInputFactory(udp_client->GetEngineName(), udp_client_input_factory); + Common::Input::RegisterOutputFactory(udp_client->GetEngineName(), + udp_client_output_factory); tas_input = std::make_shared<TasInput::Tas>("tas"); tas_input->SetMappingCallback(mapping_callback); tas_input_factory = std::make_shared<InputFactory>(tas_input); tas_output_factory = std::make_shared<OutputFactory>(tas_input); - Common::Input::RegisterFactory<Common::Input::InputDevice>(tas_input->GetEngineName(), - tas_input_factory); - Common::Input::RegisterFactory<Common::Input::OutputDevice>(tas_input->GetEngineName(), - tas_output_factory); + Common::Input::RegisterInputFactory(tas_input->GetEngineName(), tas_input_factory); + Common::Input::RegisterOutputFactory(tas_input->GetEngineName(), tas_output_factory); camera = std::make_shared<Camera>("camera"); camera->SetMappingCallback(mapping_callback); camera_input_factory = std::make_shared<InputFactory>(camera); camera_output_factory = std::make_shared<OutputFactory>(camera); - Common::Input::RegisterFactory<Common::Input::InputDevice>(camera->GetEngineName(), - camera_input_factory); - Common::Input::RegisterFactory<Common::Input::OutputDevice>(camera->GetEngineName(), - camera_output_factory); + Common::Input::RegisterInputFactory(camera->GetEngineName(), camera_input_factory); + Common::Input::RegisterOutputFactory(camera->GetEngineName(), camera_output_factory); virtual_amiibo = std::make_shared<VirtualAmiibo>("virtual_amiibo"); virtual_amiibo->SetMappingCallback(mapping_callback); virtual_amiibo_input_factory = std::make_shared<InputFactory>(virtual_amiibo); virtual_amiibo_output_factory = std::make_shared<OutputFactory>(virtual_amiibo); - Common::Input::RegisterFactory<Common::Input::InputDevice>(virtual_amiibo->GetEngineName(), - virtual_amiibo_input_factory); - Common::Input::RegisterFactory<Common::Input::OutputDevice>(virtual_amiibo->GetEngineName(), - virtual_amiibo_output_factory); + Common::Input::RegisterInputFactory(virtual_amiibo->GetEngineName(), + virtual_amiibo_input_factory); + Common::Input::RegisterOutputFactory(virtual_amiibo->GetEngineName(), + virtual_amiibo_output_factory); #ifdef HAVE_SDL2 sdl = std::make_shared<SDLDriver>("sdl"); sdl->SetMappingCallback(mapping_callback); sdl_input_factory = std::make_shared<InputFactory>(sdl); sdl_output_factory = std::make_shared<OutputFactory>(sdl); - Common::Input::RegisterFactory<Common::Input::InputDevice>(sdl->GetEngineName(), - sdl_input_factory); - Common::Input::RegisterFactory<Common::Input::OutputDevice>(sdl->GetEngineName(), - sdl_output_factory); + Common::Input::RegisterInputFactory(sdl->GetEngineName(), sdl_input_factory); + Common::Input::RegisterOutputFactory(sdl->GetEngineName(), sdl_output_factory); #endif - Common::Input::RegisterFactory<Common::Input::InputDevice>( - "touch_from_button", std::make_shared<TouchFromButton>()); - Common::Input::RegisterFactory<Common::Input::InputDevice>( - "analog_from_button", std::make_shared<StickFromButton>()); + Common::Input::RegisterInputFactory("touch_from_button", + std::make_shared<TouchFromButton>()); + Common::Input::RegisterInputFactory("analog_from_button", + std::make_shared<StickFromButton>()); } void Shutdown() { - Common::Input::UnregisterFactory<Common::Input::InputDevice>(keyboard->GetEngineName()); - Common::Input::UnregisterFactory<Common::Input::OutputDevice>(keyboard->GetEngineName()); + Common::Input::UnregisterInputFactory(keyboard->GetEngineName()); + Common::Input::UnregisterOutputFactory(keyboard->GetEngineName()); keyboard.reset(); - Common::Input::UnregisterFactory<Common::Input::InputDevice>(mouse->GetEngineName()); - Common::Input::UnregisterFactory<Common::Input::OutputDevice>(mouse->GetEngineName()); + Common::Input::UnregisterInputFactory(mouse->GetEngineName()); + Common::Input::UnregisterOutputFactory(mouse->GetEngineName()); mouse.reset(); - Common::Input::UnregisterFactory<Common::Input::InputDevice>(touch_screen->GetEngineName()); + Common::Input::UnregisterInputFactory(touch_screen->GetEngineName()); touch_screen.reset(); - Common::Input::UnregisterFactory<Common::Input::InputDevice>(gcadapter->GetEngineName()); - Common::Input::UnregisterFactory<Common::Input::OutputDevice>(gcadapter->GetEngineName()); + Common::Input::UnregisterInputFactory(gcadapter->GetEngineName()); + Common::Input::UnregisterOutputFactory(gcadapter->GetEngineName()); gcadapter.reset(); - Common::Input::UnregisterFactory<Common::Input::InputDevice>(udp_client->GetEngineName()); - Common::Input::UnregisterFactory<Common::Input::OutputDevice>(udp_client->GetEngineName()); + Common::Input::UnregisterInputFactory(udp_client->GetEngineName()); + Common::Input::UnregisterOutputFactory(udp_client->GetEngineName()); udp_client.reset(); - Common::Input::UnregisterFactory<Common::Input::InputDevice>(tas_input->GetEngineName()); - Common::Input::UnregisterFactory<Common::Input::OutputDevice>(tas_input->GetEngineName()); + Common::Input::UnregisterInputFactory(tas_input->GetEngineName()); + Common::Input::UnregisterOutputFactory(tas_input->GetEngineName()); tas_input.reset(); - Common::Input::UnregisterFactory<Common::Input::InputDevice>(camera->GetEngineName()); - Common::Input::UnregisterFactory<Common::Input::OutputDevice>(camera->GetEngineName()); + Common::Input::UnregisterInputFactory(camera->GetEngineName()); + Common::Input::UnregisterOutputFactory(camera->GetEngineName()); camera.reset(); - Common::Input::UnregisterFactory<Common::Input::InputDevice>( - virtual_amiibo->GetEngineName()); - Common::Input::UnregisterFactory<Common::Input::OutputDevice>( - virtual_amiibo->GetEngineName()); + Common::Input::UnregisterInputFactory(virtual_amiibo->GetEngineName()); + Common::Input::UnregisterOutputFactory(virtual_amiibo->GetEngineName()); virtual_amiibo.reset(); #ifdef HAVE_SDL2 - Common::Input::UnregisterFactory<Common::Input::InputDevice>(sdl->GetEngineName()); - Common::Input::UnregisterFactory<Common::Input::OutputDevice>(sdl->GetEngineName()); + Common::Input::UnregisterInputFactory(sdl->GetEngineName()); + Common::Input::UnregisterOutputFactory(sdl->GetEngineName()); sdl.reset(); #endif - Common::Input::UnregisterFactory<Common::Input::InputDevice>("touch_from_button"); - Common::Input::UnregisterFactory<Common::Input::InputDevice>("analog_from_button"); + Common::Input::UnregisterInputFactory("touch_from_button"); + Common::Input::UnregisterInputFactory("analog_from_button"); } [[nodiscard]] std::vector<Common::ParamPackage> GetInputDevices() const { @@ -334,6 +318,12 @@ struct InputSubsystem::Impl { #endif } + void PumpEvents() const { +#ifdef HAVE_SDL2 + sdl->PumpEvents(); +#endif + } + void RegisterInput(const MappingData& data) { mapping_factory->RegisterInput(data); } @@ -482,6 +472,10 @@ void InputSubsystem::StopMapping() const { impl->mapping_factory->StopMapping(); } +void InputSubsystem::PumpEvents() const { + impl->PumpEvents(); +} + std::string GenerateKeyboardParam(int key_code) { Common::ParamPackage param; param.Set("engine", "keyboard"); diff --git a/src/input_common/main.h b/src/input_common/main.h index ced252383..6218c37f6 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h @@ -147,6 +147,9 @@ public: /// Stop polling from all backends. void StopMapping() const; + /// Signals SDL driver for new input events + void PumpEvents() const; + private: struct Impl; std::unique_ptr<Impl> impl; diff --git a/src/input_common/precompiled_headers.h b/src/input_common/precompiled_headers.h new file mode 100644 index 000000000..aabae730b --- /dev/null +++ b/src/input_common/precompiled_headers.h @@ -0,0 +1,6 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_precompiled_headers.h" diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index 6f8ca4b90..c85c308de 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -8,6 +8,7 @@ add_library(network STATIC network.h packet.cpp packet.h + precompiled_headers.h room.cpp room.h room_member.cpp @@ -23,3 +24,7 @@ if (ENABLE_WEB_SERVICE) target_compile_definitions(network PRIVATE -DENABLE_WEB_SERVICE) target_link_libraries(network PRIVATE web_service) endif() + +if (YUZU_USE_PRECOMPILED_HEADERS) + target_precompile_headers(network PRIVATE precompiled_headers.h) +endif() diff --git a/src/network/precompiled_headers.h b/src/network/precompiled_headers.h new file mode 100644 index 000000000..aabae730b --- /dev/null +++ b/src/network/precompiled_headers.h @@ -0,0 +1,6 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_precompiled_headers.h" diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt index 545d69c7e..525b2363c 100644 --- a/src/shader_recompiler/CMakeLists.txt +++ b/src/shader_recompiler/CMakeLists.txt @@ -221,6 +221,7 @@ add_library(shader_recompiler STATIC ir_opt/dual_vertex_pass.cpp ir_opt/global_memory_to_storage_buffer_pass.cpp ir_opt/identity_removal_pass.cpp + ir_opt/layer_pass.cpp ir_opt/lower_fp16_to_fp32.cpp ir_opt/lower_int64_to_int32.cpp ir_opt/passes.h @@ -230,6 +231,7 @@ add_library(shader_recompiler STATIC ir_opt/texture_pass.cpp ir_opt/verification_pass.cpp object_pool.h + precompiled_headers.h profile.h program_header.h runtime_info.h @@ -254,7 +256,12 @@ else() # Bracket depth determines maximum size of a fold expression in Clang since 9c9974c3ccb6. # And this in turns limits the size of a std::array. $<$<CXX_COMPILER_ID:Clang>:-fbracket-depth=1024> + $<$<CXX_COMPILER_ID:AppleClang>:-fbracket-depth=1024> ) endif() create_target_directory_groups(shader_recompiler) + +if (YUZU_USE_PRECOMPILED_HEADERS) + target_precompile_headers(shader_recompiler PRIVATE precompiled_headers.h) +endif() diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp index 265ac9c85..0f86a8004 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp @@ -402,8 +402,10 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct ctx.AddCapability(spv::Capability::SparseResidency); } if (info.uses_demote_to_helper_invocation && profile.support_demote_to_helper_invocation) { - ctx.AddExtension("SPV_EXT_demote_to_helper_invocation"); - ctx.AddCapability(spv::Capability::DemoteToHelperInvocationEXT); + if (profile.supported_spirv < 0x00010600) { + ctx.AddExtension("SPV_EXT_demote_to_helper_invocation"); + } + ctx.AddCapability(spv::Capability::DemoteToHelperInvocation); } if (info.stores[IR::Attribute::ViewportIndex]) { ctx.AddCapability(spv::Capability::MultiViewport); @@ -426,12 +428,11 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct if ((info.uses_subgroup_vote || info.uses_subgroup_invocation_id || info.uses_subgroup_shuffles) && profile.support_vote) { - ctx.AddExtension("SPV_KHR_shader_ballot"); - ctx.AddCapability(spv::Capability::SubgroupBallotKHR); + ctx.AddCapability(spv::Capability::GroupNonUniformBallot); + ctx.AddCapability(spv::Capability::GroupNonUniformShuffle); if (!profile.warp_size_potentially_larger_than_guest) { // vote ops are only used when not taking the long path - ctx.AddExtension("SPV_KHR_subgroup_vote"); - ctx.AddCapability(spv::Capability::SubgroupVoteKHR); + ctx.AddCapability(spv::Capability::GroupNonUniformVote); } } if (info.uses_int64_bit_atomics && profile.support_int64_atomics) { diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp index 7ad0b08ac..fb2c792c1 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp @@ -12,7 +12,7 @@ void EmitJoin(EmitContext&) { void EmitDemoteToHelperInvocation(EmitContext& ctx) { if (ctx.profile.support_demote_to_helper_invocation) { - ctx.OpDemoteToHelperInvocationEXT(); + ctx.OpDemoteToHelperInvocation(); } else { const Id kill_label{ctx.OpLabel()}; const Id impossible_label{ctx.OpLabel()}; diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp index 7cbbbfaa6..2c90f2368 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp @@ -6,6 +6,10 @@ namespace Shader::Backend::SPIRV { namespace { +Id SubgroupScope(EmitContext& ctx) { + return ctx.Const(static_cast<u32>(spv::Scope::Subgroup)); +} + Id GetThreadId(EmitContext& ctx) { return ctx.OpLoad(ctx.U32[1], ctx.subgroup_local_invocation_id); } @@ -49,8 +53,9 @@ Id GetMaxThreadId(EmitContext& ctx, Id thread_id, Id clamp, Id segmentation_mask } Id SelectValue(EmitContext& ctx, Id in_range, Id value, Id src_thread_id) { - return ctx.OpSelect(ctx.U32[1], in_range, - ctx.OpSubgroupReadInvocationKHR(ctx.U32[1], value, src_thread_id), value); + return ctx.OpSelect( + ctx.U32[1], in_range, + ctx.OpGroupNonUniformShuffle(ctx.U32[1], SubgroupScope(ctx), value, src_thread_id), value); } Id GetUpperClamp(EmitContext& ctx, Id invocation_id, Id clamp) { @@ -71,40 +76,46 @@ Id EmitLaneId(EmitContext& ctx) { Id EmitVoteAll(EmitContext& ctx, Id pred) { if (!ctx.profile.warp_size_potentially_larger_than_guest) { - return ctx.OpSubgroupAllKHR(ctx.U1, pred); + return ctx.OpGroupNonUniformAll(ctx.U1, SubgroupScope(ctx), pred); } - const Id mask_ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], ctx.true_value)}; + const Id mask_ballot{ + ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), ctx.true_value)}; const Id active_mask{WarpExtract(ctx, mask_ballot)}; - const Id ballot{WarpExtract(ctx, ctx.OpSubgroupBallotKHR(ctx.U32[4], pred))}; + const Id ballot{ + WarpExtract(ctx, ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred))}; const Id lhs{ctx.OpBitwiseAnd(ctx.U32[1], ballot, active_mask)}; return ctx.OpIEqual(ctx.U1, lhs, active_mask); } Id EmitVoteAny(EmitContext& ctx, Id pred) { if (!ctx.profile.warp_size_potentially_larger_than_guest) { - return ctx.OpSubgroupAnyKHR(ctx.U1, pred); + return ctx.OpGroupNonUniformAny(ctx.U1, SubgroupScope(ctx), pred); } - const Id mask_ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], ctx.true_value)}; + const Id mask_ballot{ + ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), ctx.true_value)}; const Id active_mask{WarpExtract(ctx, mask_ballot)}; - const Id ballot{WarpExtract(ctx, ctx.OpSubgroupBallotKHR(ctx.U32[4], pred))}; + const Id ballot{ + WarpExtract(ctx, ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred))}; const Id lhs{ctx.OpBitwiseAnd(ctx.U32[1], ballot, active_mask)}; return ctx.OpINotEqual(ctx.U1, lhs, ctx.u32_zero_value); } Id EmitVoteEqual(EmitContext& ctx, Id pred) { if (!ctx.profile.warp_size_potentially_larger_than_guest) { - return ctx.OpSubgroupAllEqualKHR(ctx.U1, pred); + return ctx.OpGroupNonUniformAllEqual(ctx.U1, SubgroupScope(ctx), pred); } - const Id mask_ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], ctx.true_value)}; + const Id mask_ballot{ + ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), ctx.true_value)}; const Id active_mask{WarpExtract(ctx, mask_ballot)}; - const Id ballot{WarpExtract(ctx, ctx.OpSubgroupBallotKHR(ctx.U32[4], pred))}; + const Id ballot{ + WarpExtract(ctx, ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred))}; const Id lhs{ctx.OpBitwiseXor(ctx.U32[1], ballot, active_mask)}; return ctx.OpLogicalOr(ctx.U1, ctx.OpIEqual(ctx.U1, lhs, ctx.u32_zero_value), ctx.OpIEqual(ctx.U1, lhs, active_mask)); } Id EmitSubgroupBallot(EmitContext& ctx, Id pred) { - const Id ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], pred)}; + const Id ballot{ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred)}; if (!ctx.profile.warp_size_potentially_larger_than_guest) { return ctx.OpCompositeExtract(ctx.U32[1], ballot, 0U); } diff --git a/src/shader_recompiler/frontend/ir/opcodes.h b/src/shader_recompiler/frontend/ir/opcodes.h index e70d7745c..d155afd0f 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.h +++ b/src/shader_recompiler/frontend/ir/opcodes.h @@ -8,6 +8,7 @@ #include <fmt/format.h> +#include "common/polyfill_ranges.h" #include "shader_recompiler/frontend/ir/type.h" namespace Shader::IR { diff --git a/src/shader_recompiler/frontend/ir/value.h b/src/shader_recompiler/frontend/ir/value.h index e8bbb93a5..8b34356fd 100644 --- a/src/shader_recompiler/frontend/ir/value.h +++ b/src/shader_recompiler/frontend/ir/value.h @@ -23,7 +23,6 @@ #include "shader_recompiler/frontend/ir/pred.h" #include "shader_recompiler/frontend/ir/reg.h" #include "shader_recompiler/frontend/ir/type.h" -#include "shader_recompiler/frontend/ir/value.h" namespace Shader::IR { diff --git a/src/shader_recompiler/frontend/maxwell/control_flow.cpp b/src/shader_recompiler/frontend/maxwell/control_flow.cpp index 6939692cd..dce414cb4 100644 --- a/src/shader_recompiler/frontend/maxwell/control_flow.cpp +++ b/src/shader_recompiler/frontend/maxwell/control_flow.cpp @@ -9,6 +9,7 @@ #include <fmt/format.h> +#include "common/polyfill_ranges.h" #include "shader_recompiler/exception.h" #include "shader_recompiler/frontend/maxwell/control_flow.h" #include "shader_recompiler/frontend/maxwell/decode.h" diff --git a/src/shader_recompiler/frontend/maxwell/decode.cpp b/src/shader_recompiler/frontend/maxwell/decode.cpp index 455c91470..774f65bc5 100644 --- a/src/shader_recompiler/frontend/maxwell/decode.cpp +++ b/src/shader_recompiler/frontend/maxwell/decode.cpp @@ -7,6 +7,7 @@ #include <memory> #include "common/common_types.h" +#include "common/polyfill_ranges.h" #include "shader_recompiler/exception.h" #include "shader_recompiler/frontend/maxwell/decode.h" #include "shader_recompiler/frontend/maxwell/opcodes.h" diff --git a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp index ce42475d4..80c90fe6a 100644 --- a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp +++ b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp @@ -12,6 +12,7 @@ #include <boost/intrusive/list.hpp> +#include "common/polyfill_ranges.h" #include "shader_recompiler/environment.h" #include "shader_recompiler/frontend/ir/basic_block.h" #include "shader_recompiler/frontend/ir/ir_emitter.h" diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp index 4942878b9..85c18d942 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp @@ -176,12 +176,13 @@ void TranslateF2I(TranslatorVisitor& v, u64 insn, const IR::F16F32F64& src_a) { (f2i.src_format == SrcFormat::F64) != (f2i.dest_format == DestFormat::I64); if (special_nan_cases) { if (f2i.dest_format == DestFormat::I32) { + constexpr u32 nan_value = 0x8000'0000U; handled_special_case = true; - result = IR::U32{v.ir.Select(v.ir.FPIsNan(op_a), v.ir.Imm32(0x8000'0000U), result)}; + result = IR::U32{v.ir.Select(v.ir.FPIsNan(op_a), v.ir.Imm32(nan_value), result)}; } else if (f2i.dest_format == DestFormat::I64) { + constexpr u64 nan_value = 0x8000'0000'0000'0000ULL; handled_special_case = true; - result = IR::U64{ - v.ir.Select(v.ir.FPIsNan(op_a), v.ir.Imm64(0x8000'0000'0000'0000UL), result)}; + result = IR::U64{v.ir.Select(v.ir.FPIsNan(op_a), v.ir.Imm64(nan_value), result)}; } } if (!handled_special_case && is_signed) { diff --git a/src/shader_recompiler/frontend/maxwell/translate_program.cpp b/src/shader_recompiler/frontend/maxwell/translate_program.cpp index 376aae0ea..3adbd2b16 100644 --- a/src/shader_recompiler/frontend/maxwell/translate_program.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate_program.cpp @@ -9,6 +9,7 @@ #include "common/settings.h" #include "shader_recompiler/exception.h" #include "shader_recompiler/frontend/ir/basic_block.h" +#include "shader_recompiler/frontend/ir/ir_emitter.h" #include "shader_recompiler/frontend/ir/post_order.h" #include "shader_recompiler/frontend/maxwell/structured_control_flow.h" #include "shader_recompiler/frontend/maxwell/translate/translate.h" @@ -233,6 +234,8 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo Optimization::VerificationPass(program); } Optimization::CollectShaderInfoPass(env, program); + Optimization::LayerPass(program, host_info); + CollectInterpolationInfo(env, program); AddNVNStorageBuffers(program); return program; @@ -331,4 +334,82 @@ void ConvertLegacyToGeneric(IR::Program& program, const Shader::RuntimeInfo& run } } +IR::Program GenerateGeometryPassthrough(ObjectPool<IR::Inst>& inst_pool, + ObjectPool<IR::Block>& block_pool, + const HostTranslateInfo& host_info, + IR::Program& source_program, + Shader::OutputTopology output_topology) { + IR::Program program; + program.stage = Stage::Geometry; + program.output_topology = output_topology; + switch (output_topology) { + case OutputTopology::PointList: + program.output_vertices = 1; + break; + case OutputTopology::LineStrip: + program.output_vertices = 2; + break; + default: + program.output_vertices = 3; + break; + } + + program.is_geometry_passthrough = false; + program.info.loads.mask = source_program.info.stores.mask; + program.info.stores.mask = source_program.info.stores.mask; + program.info.stores.Set(IR::Attribute::Layer, true); + program.info.stores.Set(source_program.info.emulated_layer, false); + + IR::Block* current_block = block_pool.Create(inst_pool); + auto& node{program.syntax_list.emplace_back()}; + node.type = IR::AbstractSyntaxNode::Type::Block; + node.data.block = current_block; + + IR::IREmitter ir{*current_block}; + for (u32 i = 0; i < program.output_vertices; i++) { + // Assign generics from input + for (u32 j = 0; j < 32; j++) { + if (!program.info.stores.Generic(j)) { + continue; + } + + const IR::Attribute attr = IR::Attribute::Generic0X + (j * 4); + ir.SetAttribute(attr + 0, ir.GetAttribute(attr + 0, ir.Imm32(i)), ir.Imm32(0)); + ir.SetAttribute(attr + 1, ir.GetAttribute(attr + 1, ir.Imm32(i)), ir.Imm32(0)); + ir.SetAttribute(attr + 2, ir.GetAttribute(attr + 2, ir.Imm32(i)), ir.Imm32(0)); + ir.SetAttribute(attr + 3, ir.GetAttribute(attr + 3, ir.Imm32(i)), ir.Imm32(0)); + } + + // Assign position from input + const IR::Attribute attr = IR::Attribute::PositionX; + ir.SetAttribute(attr + 0, ir.GetAttribute(attr + 0, ir.Imm32(i)), ir.Imm32(0)); + ir.SetAttribute(attr + 1, ir.GetAttribute(attr + 1, ir.Imm32(i)), ir.Imm32(0)); + ir.SetAttribute(attr + 2, ir.GetAttribute(attr + 2, ir.Imm32(i)), ir.Imm32(0)); + ir.SetAttribute(attr + 3, ir.GetAttribute(attr + 3, ir.Imm32(i)), ir.Imm32(0)); + + // Assign layer + ir.SetAttribute(IR::Attribute::Layer, ir.GetAttribute(source_program.info.emulated_layer), + ir.Imm32(0)); + + // Emit vertex + ir.EmitVertex(ir.Imm32(0)); + } + ir.EndPrimitive(ir.Imm32(0)); + + IR::Block* return_block{block_pool.Create(inst_pool)}; + IR::IREmitter{*return_block}.Epilogue(); + current_block->AddBranch(return_block); + + auto& merge{program.syntax_list.emplace_back()}; + merge.type = IR::AbstractSyntaxNode::Type::Block; + merge.data.block = return_block; + program.syntax_list.emplace_back().type = IR::AbstractSyntaxNode::Type::Return; + + program.blocks = GenerateBlocks(program.syntax_list); + program.post_order_blocks = PostOrder(program.syntax_list.front()); + Optimization::SsaRewritePass(program); + + return program; +} + } // namespace Shader::Maxwell diff --git a/src/shader_recompiler/frontend/maxwell/translate_program.h b/src/shader_recompiler/frontend/maxwell/translate_program.h index 02ede8c9c..497afe7cb 100644 --- a/src/shader_recompiler/frontend/maxwell/translate_program.h +++ b/src/shader_recompiler/frontend/maxwell/translate_program.h @@ -25,4 +25,13 @@ namespace Shader::Maxwell { void ConvertLegacyToGeneric(IR::Program& program, const RuntimeInfo& runtime_info); +// Maxwell v1 and older Nvidia cards don't support setting gl_Layer from non-geometry stages. +// This creates a workaround by setting the layer as a generic output and creating a +// passthrough geometry shader that reads the generic and sets the layer. +[[nodiscard]] IR::Program GenerateGeometryPassthrough(ObjectPool<IR::Inst>& inst_pool, + ObjectPool<IR::Block>& block_pool, + const HostTranslateInfo& host_info, + IR::Program& source_program, + Shader::OutputTopology output_topology); + } // namespace Shader::Maxwell diff --git a/src/shader_recompiler/host_translate_info.h b/src/shader_recompiler/host_translate_info.h index cc1500690..d5d279554 100644 --- a/src/shader_recompiler/host_translate_info.h +++ b/src/shader_recompiler/host_translate_info.h @@ -13,7 +13,8 @@ struct HostTranslateInfo { bool support_float16{}; ///< True when the device supports 16-bit floats bool support_int64{}; ///< True when the device supports 64-bit integers bool needs_demote_reorder{}; ///< True when the device needs DemoteToHelperInvocation reordered - bool support_snorm_render_buffer{}; ///< True when the device supports SNORM render buffers + bool support_snorm_render_buffer{}; ///< True when the device supports SNORM render buffers + bool support_viewport_index_layer{}; ///< True when the device supports gl_Layer in VS }; } // namespace Shader diff --git a/src/shader_recompiler/ir_opt/layer_pass.cpp b/src/shader_recompiler/ir_opt/layer_pass.cpp new file mode 100644 index 000000000..4574f7cf2 --- /dev/null +++ b/src/shader_recompiler/ir_opt/layer_pass.cpp @@ -0,0 +1,68 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <algorithm> +#include <bit> +#include <optional> + +#include <boost/container/small_vector.hpp> + +#include "shader_recompiler/environment.h" +#include "shader_recompiler/frontend/ir/basic_block.h" +#include "shader_recompiler/frontend/ir/breadth_first_search.h" +#include "shader_recompiler/frontend/ir/ir_emitter.h" +#include "shader_recompiler/host_translate_info.h" +#include "shader_recompiler/ir_opt/passes.h" +#include "shader_recompiler/shader_info.h" + +namespace Shader::Optimization { + +static IR::Attribute EmulatedLayerAttribute(VaryingState& stores) { + for (u32 i = 0; i < 32; i++) { + if (!stores.Generic(i)) { + return IR::Attribute::Generic0X + (i * 4); + } + } + return IR::Attribute::Layer; +} + +static bool PermittedProgramStage(Stage stage) { + switch (stage) { + case Stage::VertexA: + case Stage::VertexB: + case Stage::TessellationControl: + case Stage::TessellationEval: + return true; + default: + return false; + } +} + +void LayerPass(IR::Program& program, const HostTranslateInfo& host_info) { + if (host_info.support_viewport_index_layer || !PermittedProgramStage(program.stage)) { + return; + } + + const auto end{program.post_order_blocks.end()}; + const auto layer_attribute = EmulatedLayerAttribute(program.info.stores); + bool requires_layer_emulation = false; + + for (auto block = program.post_order_blocks.begin(); block != end; ++block) { + for (IR::Inst& inst : (*block)->Instructions()) { + if (inst.GetOpcode() == IR::Opcode::SetAttribute && + inst.Arg(0).Attribute() == IR::Attribute::Layer) { + requires_layer_emulation = true; + inst.SetArg(0, IR::Value{layer_attribute}); + } + } + } + + if (requires_layer_emulation) { + program.info.requires_layer_emulation = true; + program.info.emulated_layer = layer_attribute; + program.info.stores.Set(IR::Attribute::Layer, false); + program.info.stores.Set(layer_attribute, true); + } +} + +} // namespace Shader::Optimization diff --git a/src/shader_recompiler/ir_opt/passes.h b/src/shader_recompiler/ir_opt/passes.h index 586a0668f..11bfe801a 100644 --- a/src/shader_recompiler/ir_opt/passes.h +++ b/src/shader_recompiler/ir_opt/passes.h @@ -23,6 +23,7 @@ void RescalingPass(IR::Program& program); void SsaRewritePass(IR::Program& program); void PositionPass(Environment& env, IR::Program& program); void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo& host_info); +void LayerPass(IR::Program& program, const HostTranslateInfo& host_info); void VerificationPass(const IR::Program& program); // Dual Vertex diff --git a/src/shader_recompiler/precompiled_headers.h b/src/shader_recompiler/precompiled_headers.h new file mode 100644 index 000000000..5dd6b7eca --- /dev/null +++ b/src/shader_recompiler/precompiled_headers.h @@ -0,0 +1,7 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_precompiled_headers.h" +#include "frontend/maxwell/translate/impl/impl.h" diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h index ee6252bb5..d9c6e92db 100644 --- a/src/shader_recompiler/shader_info.h +++ b/src/shader_recompiler/shader_info.h @@ -204,6 +204,9 @@ struct Info { u32 nvn_buffer_base{}; std::bitset<16> nvn_buffer_used{}; + bool requires_layer_emulation{}; + IR::Attribute emulated_layer{}; + boost::container::static_vector<ConstantBufferDescriptor, MAX_CBUFS> constant_buffer_descriptors; boost::container::static_vector<StorageBufferDescriptor, MAX_SSBOS> storage_buffers_descriptors; diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 43ad2c7ff..348d1edf4 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -11,6 +11,7 @@ add_executable(tests common/unique_function.cpp core/core_timing.cpp core/internal_network/network.cpp + precompiled_headers.h tests.cpp video_core/buffer_base.cpp input_common/calibration_configuration_job.cpp @@ -22,3 +23,7 @@ target_link_libraries(tests PRIVATE common core input_common) target_link_libraries(tests PRIVATE ${PLATFORM_LIBRARIES} Catch2::Catch2 Threads::Threads) add_test(NAME tests COMMAND tests) + +if (YUZU_USE_PRECOMPILED_HEADERS) + target_precompile_headers(tests PRIVATE precompiled_headers.h) +endif() diff --git a/src/tests/precompiled_headers.h b/src/tests/precompiled_headers.h new file mode 100644 index 000000000..aabae730b --- /dev/null +++ b/src/tests/precompiled_headers.h @@ -0,0 +1,6 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_precompiled_headers.h" diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 0d6bf1f0d..6ecc8dbff 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -84,6 +84,7 @@ add_library(video_core STATIC gpu_thread.h memory_manager.cpp memory_manager.h + precompiled_headers.h pte_kind.h query_cache.h rasterizer_accelerated.cpp @@ -304,3 +305,7 @@ endif() if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) target_link_libraries(video_core PRIVATE dynarmic) endif() + +if (YUZU_USE_PRECOMPILED_HEADERS) + target_precompile_headers(video_core PRIVATE precompiled_headers.h) +endif() diff --git a/src/video_core/buffer_cache/buffer_base.h b/src/video_core/buffer_cache/buffer_base.h index f9a6472cf..92d77eef2 100644 --- a/src/video_core/buffer_cache/buffer_base.h +++ b/src/video_core/buffer_cache/buffer_base.h @@ -535,7 +535,7 @@ private: const u64* const state_words = Array<type>(); const u64 num_query_words = size / BYTES_PER_WORD + 1; const u64 word_begin = offset / BYTES_PER_WORD; - const u64 word_end = std::min(word_begin + num_query_words, NumWords()); + const u64 word_end = std::min<u64>(word_begin + num_query_words, NumWords()); const u64 page_limit = Common::DivCeil(offset + size, BYTES_PER_PAGE); u64 page_index = (offset / BYTES_PER_PAGE) % PAGES_PER_WORD; for (u64 word_index = word_begin; word_index < word_end; ++word_index, page_index = 0) { diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 5d3a8293b..6881b34c4 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -19,6 +19,7 @@ #include "common/literals.h" #include "common/lru_cache.h" #include "common/microprofile.h" +#include "common/polyfill_ranges.h" #include "common/settings.h" #include "core/memory.h" #include "video_core/buffer_cache/buffer_base.h" diff --git a/src/video_core/control/channel_state_cache.h b/src/video_core/control/channel_state_cache.h index 584a0c26c..cdaf4f8d5 100644 --- a/src/video_core/control/channel_state_cache.h +++ b/src/video_core/control/channel_state_cache.h @@ -35,8 +35,6 @@ public: explicit ChannelInfo(Tegra::Control::ChannelState& state); ChannelInfo(const ChannelInfo& state) = delete; ChannelInfo& operator=(const ChannelInfo&) = delete; - ChannelInfo(ChannelInfo&& other) = default; - ChannelInfo& operator=(ChannelInfo&& other) = default; Tegra::Engines::Maxwell3D& maxwell3d; Tegra::Engines::KeplerCompute& kepler_compute; diff --git a/src/video_core/engines/engine_upload.cpp b/src/video_core/engines/engine_upload.cpp index 28aa85f32..e4f8331ab 100644 --- a/src/video_core/engines/engine_upload.cpp +++ b/src/video_core/engines/engine_upload.cpp @@ -49,10 +49,9 @@ void State::ProcessData(std::span<const u8> read_buffer) { if (regs.line_count == 1) { rasterizer->AccelerateInlineToMemory(address, copy_size, read_buffer); } else { - for (u32 line = 0; line < regs.line_count; ++line) { - const GPUVAddr dest_line = address + static_cast<size_t>(line) * regs.dest.pitch; - std::span<const u8> buffer(read_buffer.data() + - static_cast<size_t>(line) * regs.line_length_in, + for (size_t line = 0; line < regs.line_count; ++line) { + const GPUVAddr dest_line = address + line * regs.dest.pitch; + std::span<const u8> buffer(read_buffer.data() + line * regs.line_length_in, regs.line_length_in); rasterizer->AccelerateInlineToMemory(dest_line, regs.line_length_in, buffer); } diff --git a/src/video_core/engines/engine_upload.h b/src/video_core/engines/engine_upload.h index f08f6e36a..94fafd9dc 100644 --- a/src/video_core/engines/engine_upload.h +++ b/src/video_core/engines/engine_upload.h @@ -39,7 +39,7 @@ struct Registers { u32 y; GPUVAddr Address() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | address_low); + return (GPUVAddr{address_high} << 32) | GPUVAddr{address_low}; } u32 BlockWidth() const { diff --git a/src/video_core/engines/fermi_2d.h b/src/video_core/engines/fermi_2d.h index 24b518cb5..100b21bac 100644 --- a/src/video_core/engines/fermi_2d.h +++ b/src/video_core/engines/fermi_2d.h @@ -97,7 +97,7 @@ public: u32 addr_lower; [[nodiscard]] constexpr GPUVAddr Address() const noexcept { - return (static_cast<GPUVAddr>(addr_upper) << 32) | static_cast<GPUVAddr>(addr_lower); + return (GPUVAddr{addr_upper} << 32) | GPUVAddr{addr_lower}; } }; static_assert(sizeof(Surface) == 0x28, "Surface has incorrect size"); diff --git a/src/video_core/engines/kepler_compute.cpp b/src/video_core/engines/kepler_compute.cpp index 7c50bdbe0..e5c622155 100644 --- a/src/video_core/engines/kepler_compute.cpp +++ b/src/video_core/engines/kepler_compute.cpp @@ -50,11 +50,11 @@ void KeplerCompute::CallMultiMethod(u32 method, const u32* base_start, u32 amoun u32 methods_pending) { switch (method) { case KEPLER_COMPUTE_REG_INDEX(data_upload): - upload_state.ProcessData(base_start, static_cast<size_t>(amount)); + upload_state.ProcessData(base_start, amount); return; default: - for (std::size_t i = 0; i < amount; i++) { - CallMethod(method, base_start[i], methods_pending - static_cast<u32>(i) <= 1); + for (u32 i = 0; i < amount; i++) { + CallMethod(method, base_start[i], methods_pending - i <= 1); } break; } diff --git a/src/video_core/engines/kepler_compute.h b/src/video_core/engines/kepler_compute.h index aab309ecc..e154e3f06 100644 --- a/src/video_core/engines/kepler_compute.h +++ b/src/video_core/engines/kepler_compute.h @@ -68,7 +68,7 @@ public: struct { u32 address; GPUVAddr Address() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address) << 8)); + return GPUVAddr{address} << 8; } } launch_desc_loc; @@ -83,8 +83,7 @@ public: u32 address_low; u32 limit; GPUVAddr Address() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | - address_low); + return (GPUVAddr{address_high} << 32) | GPUVAddr{address_low}; } } tsc; @@ -95,8 +94,7 @@ public: u32 address_low; u32 limit; GPUVAddr Address() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | - address_low); + return (GPUVAddr{address_high} << 32) | GPUVAddr{address_low}; } } tic; @@ -106,8 +104,7 @@ public: u32 address_high; u32 address_low; GPUVAddr Address() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | - address_low); + return (GPUVAddr{address_high} << 32) | GPUVAddr{address_low}; } } code_loc; @@ -162,8 +159,7 @@ public: BitField<15, 17, u32> size; }; GPUVAddr Address() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high.Value()) << 32) | - address_low); + return (GPUVAddr{address_high.Value()} << 32) | GPUVAddr{address_low}; } }; std::array<ConstBufferConfig, NumConstBuffers> const_buffer_config; diff --git a/src/video_core/engines/kepler_memory.cpp b/src/video_core/engines/kepler_memory.cpp index a3fbab1e5..08045d1cf 100644 --- a/src/video_core/engines/kepler_memory.cpp +++ b/src/video_core/engines/kepler_memory.cpp @@ -42,11 +42,11 @@ void KeplerMemory::CallMultiMethod(u32 method, const u32* base_start, u32 amount u32 methods_pending) { switch (method) { case KEPLERMEMORY_REG_INDEX(data): - upload_state.ProcessData(base_start, static_cast<size_t>(amount)); + upload_state.ProcessData(base_start, amount); return; default: - for (std::size_t i = 0; i < amount; i++) { - CallMethod(method, base_start[i], methods_pending - static_cast<u32>(i) <= 1); + for (u32 i = 0; i < amount; i++) { + CallMethod(method, base_start[i], methods_pending - i <= 1); } break; } diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 212427b8b..34bbc72cf 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -126,7 +126,6 @@ void Maxwell3D::InitializeRegisterDefaults() { draw_command[MAXWELL3D_REG_INDEX(draw_inline_index)] = true; draw_command[MAXWELL3D_REG_INDEX(inline_index_2x16.even)] = true; draw_command[MAXWELL3D_REG_INDEX(inline_index_4x8.index0)] = true; - draw_command[MAXWELL3D_REG_INDEX(draw.instance_id)] = true; } void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool is_last_call) { @@ -218,16 +217,19 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume regs.index_buffer.count = regs.index_buffer32_first.count; regs.index_buffer.first = regs.index_buffer32_first.first; dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; + draw_indexed = true; return ProcessDraw(); case MAXWELL3D_REG_INDEX(index_buffer16_first): regs.index_buffer.count = regs.index_buffer16_first.count; regs.index_buffer.first = regs.index_buffer16_first.first; dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; + draw_indexed = true; return ProcessDraw(); case MAXWELL3D_REG_INDEX(index_buffer8_first): regs.index_buffer.count = regs.index_buffer8_first.count; regs.index_buffer.first = regs.index_buffer8_first.first; dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; + draw_indexed = true; return ProcessDraw(); case MAXWELL3D_REG_INDEX(topology_override): use_topology_override = true; @@ -300,21 +302,33 @@ void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) { draw_mode = DrawMode::InlineIndex; }; switch (method) { + case MAXWELL3D_REG_INDEX(draw.begin): { + draw_mode = + (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent) || + (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Unchanged) + ? DrawMode::Instance + : DrawMode::General; + break; + } case MAXWELL3D_REG_INDEX(draw.end): switch (draw_mode) { case DrawMode::General: - ProcessDraw(1); + ProcessDraw(); break; case DrawMode::InlineIndex: regs.index_buffer.count = static_cast<u32>(inline_index_draw_indexes.size() / 4); regs.index_buffer.format = Regs::IndexFormat::UnsignedInt; - ProcessDraw(1); + draw_indexed = true; + ProcessDraw(); inline_index_draw_indexes.clear(); break; case DrawMode::Instance: break; } break; + case MAXWELL3D_REG_INDEX(index_buffer.count): + draw_indexed = true; + break; case MAXWELL3D_REG_INDEX(draw_inline_index): update_inline_index(method_argument); break; @@ -328,13 +342,6 @@ void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) { update_inline_index(regs.inline_index_4x8.index2); update_inline_index(regs.inline_index_4x8.index3); break; - case MAXWELL3D_REG_INDEX(draw.instance_id): - draw_mode = - (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent) || - (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Unchanged) - ? DrawMode::Instance - : DrawMode::General; - break; } } else { ProcessDeferredDraw(); @@ -370,11 +377,11 @@ void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount, ProcessCBMultiData(base_start, amount); break; case MAXWELL3D_REG_INDEX(inline_data): - upload_state.ProcessData(base_start, static_cast<size_t>(amount)); + upload_state.ProcessData(base_start, amount); return; default: - for (std::size_t i = 0; i < amount; i++) { - CallMethod(method, base_start[i], methods_pending - static_cast<u32>(i) <= 1); + for (u32 i = 0; i < amount; i++) { + CallMethod(method, base_start[i], methods_pending - i <= 1); } break; } @@ -624,27 +631,16 @@ void Maxwell3D::ProcessClearBuffers(u32 layer_count) { void Maxwell3D::ProcessDraw(u32 instance_count) { LOG_TRACE(HW_GPU, "called, topology={}, count={}", regs.draw.topology.Value(), - regs.vertex_buffer.count); - - ASSERT_MSG(!(regs.index_buffer.count && regs.vertex_buffer.count), "Both indexed and direct?"); - - // Both instance configuration registers can not be set at the same time. - ASSERT_MSG(regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First || - regs.draw.instance_id != Maxwell3D::Regs::Draw::InstanceId::Unchanged, - "Illegal combination of instancing parameters"); + draw_indexed ? regs.index_buffer.count : regs.vertex_buffer.count); ProcessTopologyOverride(); - const bool is_indexed = regs.index_buffer.count && !regs.vertex_buffer.count; if (ShouldExecute()) { - rasterizer->Draw(is_indexed, instance_count); + rasterizer->Draw(draw_indexed, instance_count); } - if (is_indexed) { - regs.index_buffer.count = 0; - } else { - regs.vertex_buffer.count = 0; - } + draw_indexed = false; + deferred_draw_method.clear(); } void Maxwell3D::ProcessDeferredDraw() { @@ -652,12 +648,12 @@ void Maxwell3D::ProcessDeferredDraw() { return; } - u32 method_count = static_cast<u32>(deferred_draw_method.size()); + const auto method_count = deferred_draw_method.size(); u32 instance_count = 1; u32 vertex_buffer_count = 0; u32 index_buffer_count = 0; - for (u32 index = 0; index < method_count; ++index) { - u32 method = deferred_draw_method[index]; + for (size_t index = 0; index < method_count; ++index) { + const u32 method = deferred_draw_method[index]; if (method == MAXWELL3D_REG_INDEX(vertex_buffer.count)) { instance_count = ++vertex_buffer_count; } else if (method == MAXWELL3D_REG_INDEX(index_buffer.count)) { @@ -667,8 +663,6 @@ void Maxwell3D::ProcessDeferredDraw() { ASSERT_MSG(!(vertex_buffer_count && index_buffer_count), "Instance both indexed and direct?"); ProcessDraw(instance_count); - - deferred_draw_method.clear(); } } // namespace Tegra::Engines diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 84c497ebd..a541cd95f 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -96,8 +96,7 @@ public: u32 type; GPUVAddr Address() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | - address_low); + return (GPUVAddr{address_high} << 32) | GPUVAddr{address_low}; } }; @@ -106,8 +105,7 @@ public: u32 address_low; GPUVAddr Address() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | - address_low); + return (GPUVAddr{address_high} << 32) | GPUVAddr{address_low}; } }; @@ -124,8 +122,7 @@ public: Mode mode; GPUVAddr Address() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(offset_high) << 32) | - offset_low); + return (GPUVAddr{offset_high} << 32) | GPUVAddr{offset_low}; } }; @@ -187,7 +184,7 @@ public: default: // Thresholds begin at 0x10 (1 << 4) // Threshold is in the range 0x1 to 0x13 - return 1 << (4 + threshold.Value() - 1); + return 1U << (4 + threshold.Value() - 1); } } }; @@ -468,8 +465,7 @@ public: INSERT_PADDING_BYTES_NOINIT(0xC); GPUVAddr Address() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | - address_low); + return (GPUVAddr{address_high} << 32) | GPUVAddr{address_low}; } }; static_assert(sizeof(Buffer) == 0x20); @@ -511,12 +507,11 @@ public: u32 default_size_per_warp; GPUVAddr Address() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | - address_low); + return (GPUVAddr{address_high} << 32) | GPUVAddr{address_low}; } u64 Size() const { - return (static_cast<u64>(size_high) << 32) | size_low; + return (u64{size_high} << 32) | u64{size_low}; } }; @@ -538,13 +533,11 @@ public: u32 storage_limit_address_low; GPUVAddr StorageAddress() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(storage_address_high) << 32) | - storage_address_low); + return (GPUVAddr{storage_address_high} << 32) | GPUVAddr{storage_address_low}; } GPUVAddr StorageLimitAddress() const { - return static_cast<GPUVAddr>( - (static_cast<GPUVAddr>(storage_limit_address_high) << 32) | - storage_limit_address_low); + return (GPUVAddr{storage_limit_address_high} << 32) | + GPUVAddr{storage_limit_address_low}; } }; @@ -829,11 +822,11 @@ public: struct CompressionThresholdSamples { u32 samples; - u32 Samples() { + u32 Samples() const { if (samples == 0) { return 0; } - return 1 << (samples - 1); + return 1U << (samples - 1); } }; @@ -1138,8 +1131,7 @@ public: INSERT_PADDING_BYTES_NOINIT(0x18); GPUVAddr Address() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | - address_low); + return (GPUVAddr{address_high} << 32) | GPUVAddr{address_low}; } }; static_assert(sizeof(RenderTargetConfig) == 0x40); @@ -1482,8 +1474,7 @@ public: u32 address_low; GPUVAddr Address() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | - address_low); + return (GPUVAddr{address_high} << 32) | GPUVAddr{address_low}; } }; @@ -1533,8 +1524,7 @@ public: u32 address_low; GPUVAddr Address() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | - address_low); + return (GPUVAddr{address_high} << 32) | GPUVAddr{address_low}; } }; @@ -1561,8 +1551,7 @@ public: u32 array_pitch; GPUVAddr Address() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | - address_low); + return (GPUVAddr{address_high} << 32) | GPUVAddr{address_low}; } }; @@ -1910,8 +1899,7 @@ public: Mode mode; GPUVAddr Address() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | - address_low); + return (GPUVAddr{address_high} << 32) | GPUVAddr{address_low}; } }; @@ -1921,8 +1909,7 @@ public: u32 limit; GPUVAddr Address() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | - address_low); + return (GPUVAddr{address_high} << 32) | GPUVAddr{address_low}; } }; @@ -1932,8 +1919,7 @@ public: u32 limit; GPUVAddr Address() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | - address_low); + return (GPUVAddr{address_high} << 32) | GPUVAddr{address_low}; } }; @@ -1981,8 +1967,7 @@ public: u32 address_low; GPUVAddr Address() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | - address_low); + return (GPUVAddr{address_high} << 32) | GPUVAddr{address_low}; } }; @@ -2027,8 +2012,7 @@ public: u32 address_low; GPUVAddr Address() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | - address_low); + return (GPUVAddr{address_high} << 32) | GPUVAddr{address_low}; } }; @@ -2224,19 +2208,16 @@ public: } GPUVAddr StartAddress() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(start_addr_high) << 32) | - start_addr_low); + return (GPUVAddr{start_addr_high} << 32) | GPUVAddr{start_addr_low}; } GPUVAddr EndAddress() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(limit_addr_high) << 32) | - limit_addr_low); + return (GPUVAddr{limit_addr_high} << 32) | GPUVAddr{limit_addr_low}; } /// Adjust the index buffer offset so it points to the first desired index. GPUVAddr IndexStart() const { - return StartAddress() + - static_cast<size_t>(first) * static_cast<size_t>(FormatSizeInBytes()); + return StartAddress() + size_t{first} * size_t{FormatSizeInBytes()}; } }; @@ -2464,8 +2445,7 @@ public: } query; GPUVAddr Address() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | - address_low); + return (GPUVAddr{address_high} << 32) | GPUVAddr{address_low}; } }; @@ -2479,8 +2459,7 @@ public: u32 frequency; GPUVAddr Address() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | - address_low); + return (GPUVAddr{address_high} << 32) | GPUVAddr{address_low}; } bool IsEnabled() const { @@ -2494,8 +2473,7 @@ public: u32 address_low; GPUVAddr Address() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | - address_low); + return (GPUVAddr{address_high} << 32) | GPUVAddr{address_low}; } }; static_assert(sizeof(VertexStreamLimit) == 0x8); @@ -2543,8 +2521,7 @@ public: std::array<u32, NumCBData> buffer; GPUVAddr Address() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | - address_low); + return (GPUVAddr{address_high} << 32) | GPUVAddr{address_low}; } }; @@ -3182,6 +3159,7 @@ private: std::vector<u32> deferred_draw_method; enum class DrawMode : u32 { General = 0, Instance, InlineIndex }; DrawMode draw_mode{DrawMode::General}; + bool draw_indexed{}; }; #define ASSERT_REG_POSITION(field_name, position) \ diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp index 334429514..a189e60ae 100644 --- a/src/video_core/engines/maxwell_dma.cpp +++ b/src/video_core/engines/maxwell_dma.cpp @@ -41,8 +41,8 @@ void MaxwellDMA::CallMethod(u32 method, u32 method_argument, bool is_last_call) void MaxwellDMA::CallMultiMethod(u32 method, const u32* base_start, u32 amount, u32 methods_pending) { - for (size_t i = 0; i < amount; ++i) { - CallMethod(method, base_start[i], methods_pending - static_cast<u32>(i) <= 1); + for (u32 i = 0; i < amount; ++i) { + CallMethod(method, base_start[i], methods_pending - i <= 1); } } @@ -94,14 +94,14 @@ void MaxwellDMA::Launch() { reinterpret_cast<u8*>(tmp_buffer.data()), regs.line_length_in * sizeof(u32)); } else { - auto convert_linear_2_blocklinear_addr = [](u64 address) { + const auto convert_linear_2_blocklinear_addr = [](u64 address) { return (address & ~0x1f0ULL) | ((address & 0x40) >> 2) | ((address & 0x10) << 1) | ((address & 0x180) >> 1) | ((address & 0x20) << 3); }; - auto src_kind = memory_manager.GetPageKind(regs.offset_in); - auto dst_kind = memory_manager.GetPageKind(regs.offset_out); - const bool is_src_pitch = IsPitchKind(static_cast<PTEKind>(src_kind)); - const bool is_dst_pitch = IsPitchKind(static_cast<PTEKind>(dst_kind)); + const auto src_kind = memory_manager.GetPageKind(regs.offset_in); + const auto dst_kind = memory_manager.GetPageKind(regs.offset_out); + const bool is_src_pitch = IsPitchKind(src_kind); + const bool is_dst_pitch = IsPitchKind(dst_kind); if (!is_src_pitch && is_dst_pitch) { UNIMPLEMENTED_IF(regs.line_length_in % 16 != 0); UNIMPLEMENTED_IF(regs.offset_in % 16 != 0); diff --git a/src/video_core/engines/puller.cpp b/src/video_core/engines/puller.cpp index c308ba3fc..7718a09b3 100644 --- a/src/video_core/engines/puller.cpp +++ b/src/video_core/engines/puller.cpp @@ -31,7 +31,7 @@ void Puller::ProcessBindMethod(const MethodCall& method_call) { LOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", method_call.subchannel, method_call.argument); const auto engine_id = static_cast<EngineID>(method_call.argument); - bound_engines[method_call.subchannel] = static_cast<EngineID>(engine_id); + bound_engines[method_call.subchannel] = engine_id; switch (engine_id) { case EngineID::FERMI_TWOD_A: dma_pusher.BindSubchannel(channel_state.fermi_2d.get(), method_call.subchannel); @@ -285,12 +285,12 @@ void Puller::CallMultiMethod(u32 method, u32 subchannel, const u32* base_start, if (ExecuteMethodOnEngine(method)) { CallEngineMultiMethod(method, subchannel, base_start, amount, methods_pending); } else { - for (std::size_t i = 0; i < amount; i++) { + for (u32 i = 0; i < amount; i++) { CallPullerMethod(MethodCall{ method, base_start[i], subchannel, - methods_pending - static_cast<u32>(i), + methods_pending - i, }); } } diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp index 1bd477011..164a5252a 100644 --- a/src/video_core/gpu_thread.cpp +++ b/src/video_core/gpu_thread.cpp @@ -125,7 +125,7 @@ u64 ThreadManager::PushCommand(CommandData&& command_data, bool block) { state.queue.Push(CommandDataContainer(std::move(command_data), fence, block)); if (block) { - state.cv.wait(lk, thread.get_stop_token(), [this, fence] { + Common::CondvarWait(state.cv, lk, thread.get_stop_token(), [this, fence] { return fence <= state.signaled_fence.load(std::memory_order_relaxed); }); } diff --git a/src/video_core/gpu_thread.h b/src/video_core/gpu_thread.h index 64628d3e3..c71a419c7 100644 --- a/src/video_core/gpu_thread.h +++ b/src/video_core/gpu_thread.h @@ -10,6 +10,7 @@ #include <thread> #include <variant> +#include "common/polyfill_thread.h" #include "common/threadsafe_queue.h" #include "video_core/framebuffer_config.h" diff --git a/src/video_core/host1x/syncpoint_manager.cpp b/src/video_core/host1x/syncpoint_manager.cpp index a44fc83d3..8f23ce527 100644 --- a/src/video_core/host1x/syncpoint_manager.cpp +++ b/src/video_core/host1x/syncpoint_manager.cpp @@ -34,7 +34,7 @@ SyncpointManager::ActionHandle SyncpointManager::RegisterAction( } void SyncpointManager::DeregisterAction(std::list<RegisteredAction>& action_storage, - ActionHandle& handle) { + const ActionHandle& handle) { std::unique_lock lk(guard); // We want to ensure the iterator still exists prior to erasing it @@ -49,11 +49,11 @@ void SyncpointManager::DeregisterAction(std::list<RegisteredAction>& action_stor } } -void SyncpointManager::DeregisterGuestAction(u32 syncpoint_id, ActionHandle& handle) { +void SyncpointManager::DeregisterGuestAction(u32 syncpoint_id, const ActionHandle& handle) { DeregisterAction(guest_action_storage[syncpoint_id], handle); } -void SyncpointManager::DeregisterHostAction(u32 syncpoint_id, ActionHandle& handle) { +void SyncpointManager::DeregisterHostAction(u32 syncpoint_id, const ActionHandle& handle) { DeregisterAction(host_action_storage[syncpoint_id], handle); } diff --git a/src/video_core/host1x/syncpoint_manager.h b/src/video_core/host1x/syncpoint_manager.h index 50a264e23..847ed20c8 100644 --- a/src/video_core/host1x/syncpoint_manager.h +++ b/src/video_core/host1x/syncpoint_manager.h @@ -36,21 +36,19 @@ public: template <typename Func> ActionHandle RegisterGuestAction(u32 syncpoint_id, u32 expected_value, Func&& action) { - std::function<void()> func(action); return RegisterAction(syncpoints_guest[syncpoint_id], guest_action_storage[syncpoint_id], - expected_value, std::move(func)); + expected_value, std::move(action)); } template <typename Func> ActionHandle RegisterHostAction(u32 syncpoint_id, u32 expected_value, Func&& action) { - std::function<void()> func(action); return RegisterAction(syncpoints_host[syncpoint_id], host_action_storage[syncpoint_id], - expected_value, std::move(func)); + expected_value, std::move(action)); } - void DeregisterGuestAction(u32 syncpoint_id, ActionHandle& handle); + void DeregisterGuestAction(u32 syncpoint_id, const ActionHandle& handle); - void DeregisterHostAction(u32 syncpoint_id, ActionHandle& handle); + void DeregisterHostAction(u32 syncpoint_id, const ActionHandle& handle); void IncrementGuest(u32 syncpoint_id); @@ -76,7 +74,7 @@ private: std::list<RegisteredAction>& action_storage, u32 expected_value, std::function<void()>&& action); - void DeregisterAction(std::list<RegisteredAction>& action_storage, ActionHandle& handle); + void DeregisterAction(std::list<RegisteredAction>& action_storage, const ActionHandle& handle); void Wait(std::atomic<u32>& syncpoint, std::condition_variable& wait_cv, u32 expected_value); diff --git a/src/video_core/precompiled_headers.h b/src/video_core/precompiled_headers.h new file mode 100644 index 000000000..aabae730b --- /dev/null +++ b/src/video_core/precompiled_headers.h @@ -0,0 +1,6 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_precompiled_headers.h" diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index cfd872a40..b6907463c 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h @@ -6,8 +6,8 @@ #include <functional> #include <optional> #include <span> -#include <stop_token> #include "common/common_types.h" +#include "common/polyfill_thread.h" #include "video_core/engines/fermi_2d.h" #include "video_core/gpu.h" diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp index 1663e277d..e2e3dac34 100644 --- a/src/video_core/renderer_opengl/gl_device.cpp +++ b/src/video_core/renderer_opengl/gl_device.cpp @@ -14,6 +14,7 @@ #include "common/literals.h" #include "common/logging/log.h" +#include "common/polyfill_ranges.h" #include "common/settings.h" #include "shader_recompiler/stage.h" #include "video_core/renderer_opengl/gl_device.h" diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 3fe04a115..a38060100 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -39,6 +39,7 @@ using Shader::Backend::GLASM::EmitGLASM; using Shader::Backend::GLSL::EmitGLSL; using Shader::Backend::SPIRV::EmitSPIRV; using Shader::Maxwell::ConvertLegacyToGeneric; +using Shader::Maxwell::GenerateGeometryPassthrough; using Shader::Maxwell::MergeDualVertexPrograms; using Shader::Maxwell::TranslateProgram; using VideoCommon::ComputeEnvironment; @@ -56,6 +57,17 @@ auto MakeSpan(Container& container) { return std::span(container.data(), container.size()); } +Shader::OutputTopology MaxwellToOutputTopology(Maxwell::PrimitiveTopology topology) { + switch (topology) { + case Maxwell::PrimitiveTopology::Points: + return Shader::OutputTopology::PointList; + case Maxwell::PrimitiveTopology::LineStrip: + return Shader::OutputTopology::LineStrip; + default: + return Shader::OutputTopology::TriangleStrip; + } +} + Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineKey& key, const Shader::IR::Program& program, const Shader::IR::Program* previous_program, @@ -220,6 +232,7 @@ ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindo .support_int64 = device.HasShaderInt64(), .needs_demote_reorder = device.IsAmd(), .support_snorm_render_buffer = false, + .support_viewport_index_layer = device.HasVertexViewportLayer(), } { if (use_asynchronous_shaders) { workers = CreateWorkers(); @@ -314,9 +327,7 @@ GraphicsPipeline* ShaderCache::CurrentGraphicsPipeline() { const auto& regs{maxwell3d->regs}; graphics_key.raw = 0; graphics_key.early_z.Assign(regs.mandated_early_z != 0 ? 1 : 0); - graphics_key.gs_input_topology.Assign(graphics_key.unique_hashes[4] != 0 - ? regs.draw.topology.Value() - : Maxwell::PrimitiveTopology{}); + graphics_key.gs_input_topology.Assign(regs.draw.topology.Value()); graphics_key.tessellation_primitive.Assign(regs.tessellation.params.domain_type.Value()); graphics_key.tessellation_spacing.Assign(regs.tessellation.params.spacing.Value()); graphics_key.tessellation_clockwise.Assign( @@ -415,7 +426,19 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline( std::array<Shader::IR::Program, Maxwell::MaxShaderProgram> programs; const bool uses_vertex_a{key.unique_hashes[0] != 0}; const bool uses_vertex_b{key.unique_hashes[1] != 0}; + + // Layer passthrough generation for devices without GL_ARB_shader_viewport_layer_array + Shader::IR::Program* layer_source_program{}; + for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { + const bool is_emulated_stage = layer_source_program != nullptr && + index == static_cast<u32>(Maxwell::ShaderType::Geometry); + if (key.unique_hashes[index] == 0 && is_emulated_stage) { + auto topology = MaxwellToOutputTopology(key.gs_input_topology); + programs[index] = GenerateGeometryPassthrough(pools.inst, pools.block, host_info, + *layer_source_program, topology); + continue; + } if (key.unique_hashes[index] == 0) { continue; } @@ -443,6 +466,10 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline( Shader::NumDescriptors(program_vb.info.storage_buffers_descriptors); programs[index] = MergeDualVertexPrograms(program_va, program_vb, env); } + + if (programs[index].info.requires_layer_emulation) { + layer_source_program = &programs[index]; + } } const u32 glasm_storage_buffer_limit{device.GetMaxGLASMStorageBufferBlocks()}; const bool glasm_use_storage_buffers{total_storage_buffers <= glasm_storage_buffer_limit}; @@ -456,7 +483,9 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline( const bool use_glasm{device.UseAssemblyShaders()}; const size_t first_index = uses_vertex_a && uses_vertex_b ? 1 : 0; for (size_t index = first_index; index < Maxwell::MaxShaderProgram; ++index) { - if (key.unique_hashes[index] == 0) { + const bool is_emulated_stage = layer_source_program != nullptr && + index == static_cast<u32>(Maxwell::ShaderType::Geometry); + if (key.unique_hashes[index] == 0 && !is_emulated_stage) { continue; } UNIMPLEMENTED_IF(index == 0); diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h index 89f181fe3..53ffea904 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_cache.h @@ -4,7 +4,6 @@ #pragma once #include <filesystem> -#include <stop_token> #include <unordered_map> #include "common/common_types.h" diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp index 98cc26679..f3f08b42c 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp @@ -7,6 +7,7 @@ #include "common/bit_cast.h" #include "common/cityhash.h" #include "common/common_types.h" +#include "common/polyfill_ranges.h" #include "video_core/renderer_vulkan/fixed_pipeline_state.h" #include "video_core/renderer_vulkan/vk_state_tracker.h" diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index 89426121f..6e5abade4 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp @@ -10,6 +10,7 @@ #include "common/assert.h" #include "common/common_types.h" #include "common/math_util.h" +#include "common/polyfill_ranges.h" #include "common/settings.h" #include "core/core.h" #include "core/frontend/emu_window.h" diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp index c7196b64e..b5ae6443c 100644 --- a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp @@ -7,6 +7,7 @@ #include <vector> #include "common/common_types.h" +#include "common/polyfill_ranges.h" #include "video_core/renderer_vulkan/vk_descriptor_pool.h" #include "video_core/renderer_vulkan/vk_resource_pool.h" #include "video_core/renderer_vulkan/vk_scheduler.h" diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.h b/src/video_core/renderer_vulkan/vk_master_semaphore.h index 362ed579a..689f02ea5 100644 --- a/src/video_core/renderer_vulkan/vk_master_semaphore.h +++ b/src/video_core/renderer_vulkan/vk_master_semaphore.h @@ -7,6 +7,7 @@ #include <thread> #include "common/common_types.h" +#include "common/polyfill_thread.h" #include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index d4b0a542a..29da442fa 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -46,6 +46,7 @@ MICROPROFILE_DECLARE(Vulkan_PipelineCache); namespace { using Shader::Backend::SPIRV::EmitSPIRV; using Shader::Maxwell::ConvertLegacyToGeneric; +using Shader::Maxwell::GenerateGeometryPassthrough; using Shader::Maxwell::MergeDualVertexPrograms; using Shader::Maxwell::TranslateProgram; using VideoCommon::ComputeEnvironment; @@ -53,13 +54,24 @@ using VideoCommon::FileEnvironment; using VideoCommon::GenericEnvironment; using VideoCommon::GraphicsEnvironment; -constexpr u32 CACHE_VERSION = 7; +constexpr u32 CACHE_VERSION = 8; template <typename Container> auto MakeSpan(Container& container) { return std::span(container.data(), container.size()); } +Shader::OutputTopology MaxwellToOutputTopology(Maxwell::PrimitiveTopology topology) { + switch (topology) { + case Maxwell::PrimitiveTopology::Points: + return Shader::OutputTopology::PointList; + case Maxwell::PrimitiveTopology::LineStrip: + return Shader::OutputTopology::LineStrip; + default: + return Shader::OutputTopology::TriangleStrip; + } +} + Shader::CompareFunction MaxwellToCompareFunction(Maxwell::ComparisonOp comparison) { switch (comparison) { case Maxwell::ComparisonOp::Never_D3D: @@ -277,7 +289,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device const auto& float_control{device.FloatControlProperties()}; const VkDriverIdKHR driver_id{device.GetDriverID()}; profile = Shader::Profile{ - .supported_spirv = device.IsKhrSpirv1_4Supported() ? 0x00010400U : 0x00010000U, + .supported_spirv = device.SupportedSpirvVersion(), .unified_descriptor_binding = true, .support_descriptor_aliasing = true, .support_int8 = device.IsInt8Supported(), @@ -327,6 +339,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device .needs_demote_reorder = driver_id == VK_DRIVER_ID_AMD_PROPRIETARY_KHR || driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR, .support_snorm_render_buffer = true, + .support_viewport_index_layer = device.IsExtShaderViewportIndexLayerSupported(), }; } @@ -509,7 +522,19 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline( std::array<Shader::IR::Program, Maxwell::MaxShaderProgram> programs; const bool uses_vertex_a{key.unique_hashes[0] != 0}; const bool uses_vertex_b{key.unique_hashes[1] != 0}; + + // Layer passthrough generation for devices without VK_EXT_shader_viewport_index_layer + Shader::IR::Program* layer_source_program{}; + for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { + const bool is_emulated_stage = layer_source_program != nullptr && + index == static_cast<u32>(Maxwell::ShaderType::Geometry); + if (key.unique_hashes[index] == 0 && is_emulated_stage) { + auto topology = MaxwellToOutputTopology(key.state.topology); + programs[index] = GenerateGeometryPassthrough(pools.inst, pools.block, host_info, + *layer_source_program, topology); + continue; + } if (key.unique_hashes[index] == 0) { continue; } @@ -530,6 +555,10 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline( auto program_vb{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)}; programs[index] = MergeDualVertexPrograms(program_va, program_vb, env); } + + if (programs[index].info.requires_layer_emulation) { + layer_source_program = &programs[index]; + } } std::array<const Shader::Info*, Maxwell::MaxShaderStage> infos{}; std::array<vk::ShaderModule, Maxwell::MaxShaderStage> modules; @@ -538,7 +567,9 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline( Shader::Backend::Bindings binding; for (size_t index = uses_vertex_a && uses_vertex_b ? 1 : 0; index < Maxwell::MaxShaderProgram; ++index) { - if (key.unique_hashes[index] == 0) { + const bool is_emulated_stage = layer_source_program != nullptr && + index == static_cast<u32>(Maxwell::ShaderType::Geometry); + if (key.unique_hashes[index] == 0 && !is_emulated_stage) { continue; } UNIMPLEMENTED_IF(index == 0); diff --git a/src/video_core/renderer_vulkan/vk_render_pass_cache.h b/src/video_core/renderer_vulkan/vk_render_pass_cache.h index dc21b7e69..91ad4bf57 100644 --- a/src/video_core/renderer_vulkan/vk_render_pass_cache.h +++ b/src/video_core/renderer_vulkan/vk_render_pass_cache.h @@ -12,7 +12,7 @@ namespace Vulkan { struct RenderPassKey { - auto operator<=>(const RenderPassKey&) const noexcept = default; + bool operator==(const RenderPassKey&) const noexcept = default; std::array<VideoCore::Surface::PixelFormat, 8> color_formats; VideoCore::Surface::PixelFormat depth_format; diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index 4a7b633b7..c09fb3e98 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -145,7 +145,7 @@ void Scheduler::WorkerThread(std::stop_token stop_token) { if (work_queue.empty()) { wait_cv.notify_all(); } - work_cv.wait(lock, stop_token, [this] { return !work_queue.empty(); }); + Common::CondvarWait(work_cv, lock, stop_token, [&] { return !work_queue.empty(); }); if (stop_token.stop_requested()) { continue; } diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h index 929216749..3858c506c 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_scheduler.h @@ -12,6 +12,7 @@ #include "common/alignment.h" #include "common/common_types.h" +#include "common/polyfill_thread.h" #include "video_core/renderer_vulkan/vk_master_semaphore.h" #include "video_core/vulkan_common/vulkan_wrapper.h" diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index 706d9ba74..d7be417f5 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp @@ -7,6 +7,7 @@ #include <vector> #include "common/logging/log.h" +#include "common/polyfill_ranges.h" #include "common/settings.h" #include "core/core.h" #include "video_core/renderer_vulkan/vk_scheduler.h" diff --git a/src/video_core/shader_cache.h b/src/video_core/shader_cache.h index a4391202d..f3cc4c70b 100644 --- a/src/video_core/shader_cache.h +++ b/src/video_core/shader_cache.h @@ -12,6 +12,7 @@ #include <vector> #include "common/common_types.h" +#include "common/polyfill_ranges.h" #include "video_core/control/channel_state_cache.h" #include "video_core/rasterizer_interface.h" #include "video_core/shader_environment.h" diff --git a/src/video_core/shader_environment.cpp b/src/video_core/shader_environment.cpp index f24f320b6..958810747 100644 --- a/src/video_core/shader_environment.cpp +++ b/src/video_core/shader_environment.cpp @@ -15,6 +15,7 @@ #include "common/fs/fs.h" #include "common/fs/path_util.h" #include "common/logging/log.h" +#include "common/polyfill_ranges.h" #include "shader_recompiler/environment.h" #include "video_core/engines/kepler_compute.h" #include "video_core/memory_manager.h" diff --git a/src/video_core/shader_environment.h b/src/video_core/shader_environment.h index bb55b029f..1342fab1e 100644 --- a/src/video_core/shader_environment.h +++ b/src/video_core/shader_environment.h @@ -10,12 +10,12 @@ #include <memory> #include <optional> #include <span> -#include <stop_token> #include <type_traits> #include <unordered_map> #include <vector> #include "common/common_types.h" +#include "common/polyfill_thread.h" #include "common/unique_function.h" #include "shader_recompiler/environment.h" #include "video_core/engines/maxwell_3d.h" diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp index b618e1a25..1a76d4178 100644 --- a/src/video_core/surface.cpp +++ b/src/video_core/surface.cpp @@ -214,23 +214,16 @@ PixelFormat PixelFormatFromGPUPixelFormat(Service::android::PixelFormat format) } SurfaceType GetFormatType(PixelFormat pixel_format) { - if (static_cast<std::size_t>(pixel_format) < - static_cast<std::size_t>(PixelFormat::MaxColorFormat)) { + if (pixel_format < PixelFormat::MaxColorFormat) { return SurfaceType::ColorTexture; } - - if (static_cast<std::size_t>(pixel_format) < - static_cast<std::size_t>(PixelFormat::MaxDepthFormat)) { + if (pixel_format < PixelFormat::MaxDepthFormat) { return SurfaceType::Depth; } - - if (static_cast<std::size_t>(pixel_format) < - static_cast<std::size_t>(PixelFormat::MaxStencilFormat)) { + if (pixel_format < PixelFormat::MaxStencilFormat) { return SurfaceType::Stencil; } - - if (static_cast<std::size_t>(pixel_format) < - static_cast<std::size_t>(PixelFormat::MaxDepthStencilFormat)) { + if (pixel_format < PixelFormat::MaxDepthStencilFormat) { return SurfaceType::DepthStencil; } diff --git a/src/video_core/texture_cache/formatter.cpp b/src/video_core/texture_cache/formatter.cpp index ee4f2d406..418890126 100644 --- a/src/video_core/texture_cache/formatter.cpp +++ b/src/video_core/texture_cache/formatter.cpp @@ -4,6 +4,7 @@ #include <algorithm> #include <string> +#include "common/polyfill_ranges.h" #include "video_core/texture_cache/formatter.h" #include "video_core/texture_cache/image_base.h" #include "video_core/texture_cache/image_info.h" diff --git a/src/video_core/texture_cache/render_targets.h b/src/video_core/texture_cache/render_targets.h index 1efbd6507..0829d773a 100644 --- a/src/video_core/texture_cache/render_targets.h +++ b/src/video_core/texture_cache/render_targets.h @@ -13,7 +13,7 @@ namespace VideoCommon { /// Framebuffer properties used to lookup a framebuffer struct RenderTargets { - constexpr auto operator<=>(const RenderTargets&) const noexcept = default; + constexpr bool operator==(const RenderTargets&) const noexcept = default; constexpr bool Contains(std::span<const ImageViewId> elements) const noexcept { const auto contains = [elements](ImageViewId item) { diff --git a/src/video_core/texture_cache/slot_vector.h b/src/video_core/texture_cache/slot_vector.h index 46e8a86e6..1e2aad76a 100644 --- a/src/video_core/texture_cache/slot_vector.h +++ b/src/video_core/texture_cache/slot_vector.h @@ -12,6 +12,7 @@ #include "common/assert.h" #include "common/common_types.h" +#include "common/polyfill_ranges.h" namespace VideoCommon { diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h index 9db7195bf..587339a31 100644 --- a/src/video_core/texture_cache/texture_cache_base.h +++ b/src/video_core/texture_cache/texture_cache_base.h @@ -16,6 +16,7 @@ #include "common/hash.h" #include "common/literals.h" #include "common/lru_cache.h" +#include "common/polyfill_ranges.h" #include "video_core/compatible_formats.h" #include "video_core/control/channel_state_cache.h" #include "video_core/delayed_destruction_ring.h" @@ -60,8 +61,6 @@ public: TextureCacheChannelInfo(Tegra::Control::ChannelState& state) noexcept; TextureCacheChannelInfo(const TextureCacheChannelInfo& state) = delete; TextureCacheChannelInfo& operator=(const TextureCacheChannelInfo&) = delete; - TextureCacheChannelInfo(TextureCacheChannelInfo&& other) noexcept = default; - TextureCacheChannelInfo& operator=(TextureCacheChannelInfo&& other) noexcept = default; DescriptorTable<TICEntry> graphics_image_table{gpu_memory}; DescriptorTable<TSCEntry> graphics_sampler_table{gpu_memory}; diff --git a/src/video_core/textures/astc.cpp b/src/video_core/textures/astc.cpp index 69a32819a..e8d7c7863 100644 --- a/src/video_core/textures/astc.cpp +++ b/src/video_core/textures/astc.cpp @@ -15,6 +15,7 @@ #include "common/alignment.h" #include "common/common_types.h" +#include "common/polyfill_ranges.h" #include "common/thread_worker.h" #include "video_core/textures/astc.h" diff --git a/src/video_core/transform_feedback.cpp b/src/video_core/transform_feedback.cpp index 45071185a..155599316 100644 --- a/src/video_core/transform_feedback.cpp +++ b/src/video_core/transform_feedback.cpp @@ -7,6 +7,7 @@ #include "common/alignment.h" #include "common/assert.h" +#include "common/polyfill_ranges.h" #include "shader_recompiler/shader_info.h" #include "video_core/transform_feedback.h" diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index ddecfca13..652329c38 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -12,6 +12,7 @@ #include "common/assert.h" #include "common/literals.h" +#include "common/polyfill_ranges.h" #include "common/settings.h" #include "video_core/vulkan_common/nsight_aftermath_tracker.h" #include "video_core/vulkan_common/vulkan_device.h" @@ -74,23 +75,14 @@ enum class NvidiaArchitecture { }; constexpr std::array REQUIRED_EXTENSIONS{ - VK_KHR_MAINTENANCE1_EXTENSION_NAME, - VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME, - VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, - VK_KHR_16BIT_STORAGE_EXTENSION_NAME, - VK_KHR_8BIT_STORAGE_EXTENSION_NAME, - VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, - VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME, - VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME, - VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME, - VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME, - VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME, VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME, - VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME, - VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME, VK_EXT_ROBUSTNESS_2_EXTENSION_NAME, + + // Core in 1.2, but required due to use of extension methods, + // and well-supported by drivers + VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME, + VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME, VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME, - VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME, #ifdef _WIN32 VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, #endif @@ -99,6 +91,17 @@ constexpr std::array REQUIRED_EXTENSIONS{ #endif }; +constexpr std::array REQUIRED_EXTENSIONS_BEFORE_1_2{ + VK_KHR_8BIT_STORAGE_EXTENSION_NAME, + VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME, + VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME, + VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, +}; + +constexpr std::array REQUIRED_EXTENSIONS_BEFORE_1_3{ + VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME, +}; + template <typename T> void SetNext(void**& next, T& data) { *next = &data; @@ -327,7 +330,8 @@ NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical, Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR surface, const vk::InstanceDispatch& dld_) : instance{instance_}, dld{dld_}, physical{physical_}, properties{physical.GetProperties()}, - supported_extensions{GetSupportedExtensions(physical)}, + instance_version{properties.apiVersion}, supported_extensions{GetSupportedExtensions( + physical)}, format_properties(GetFormatProperties(physical)) { CheckSuitability(surface != nullptr); SetupFamilies(surface); @@ -451,8 +455,8 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR }; SetNext(next, variable_pointers); - VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT demote{ - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT, + VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures demote{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES, .pNext = nullptr, .shaderDemoteToHelperInvocation = true, }; @@ -896,28 +900,51 @@ std::string Device::GetDriverName() const { } } +static std::vector<const char*> ExtensionsRequiredForInstanceVersion(u32 available_version) { + std::vector<const char*> extensions{REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end()}; + + if (available_version < VK_API_VERSION_1_2) { + extensions.insert(extensions.end(), REQUIRED_EXTENSIONS_BEFORE_1_2.begin(), + REQUIRED_EXTENSIONS_BEFORE_1_2.end()); + } + + if (available_version < VK_API_VERSION_1_3) { + extensions.insert(extensions.end(), REQUIRED_EXTENSIONS_BEFORE_1_3.begin(), + REQUIRED_EXTENSIONS_BEFORE_1_3.end()); + } + + return extensions; +} + void Device::CheckSuitability(bool requires_swapchain) const { - std::bitset<REQUIRED_EXTENSIONS.size()> available_extensions; - bool has_swapchain = false; - for (const VkExtensionProperties& property : physical.EnumerateDeviceExtensionProperties()) { - const std::string_view name{property.extensionName}; - for (size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) { - if (available_extensions[i]) { - continue; - } - available_extensions[i] = name == REQUIRED_EXTENSIONS[i]; - } - has_swapchain = has_swapchain || name == VK_KHR_SWAPCHAIN_EXTENSION_NAME; + std::vector<const char*> required_extensions = + ExtensionsRequiredForInstanceVersion(instance_version); + std::vector<const char*> available_extensions; + + if (requires_swapchain) { + required_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); } - for (size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) { - if (available_extensions[i]) { - continue; + + auto extension_properties = physical.EnumerateDeviceExtensionProperties(); + + for (const VkExtensionProperties& property : extension_properties) { + available_extensions.push_back(property.extensionName); + } + + bool has_all_required_extensions = true; + for (const char* requirement_name : required_extensions) { + const bool found = + std::ranges::any_of(available_extensions, [&](const char* extension_name) { + return std::strcmp(requirement_name, extension_name) == 0; + }); + + if (!found) { + LOG_ERROR(Render_Vulkan, "Missing required extension: {}", requirement_name); + has_all_required_extensions = false; } - LOG_ERROR(Render_Vulkan, "Missing required extension: {}", REQUIRED_EXTENSIONS[i]); - throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT); } - if (requires_swapchain && !has_swapchain) { - LOG_ERROR(Render_Vulkan, "Missing required extension: VK_KHR_swapchain"); + + if (!has_all_required_extensions) { throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT); } @@ -940,9 +967,8 @@ void Device::CheckSuitability(bool requires_swapchain) const { throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT); } } - VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT demote{}; - demote.sType = - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT; + VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures demote{}; + demote.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES; demote.pNext = nullptr; VkPhysicalDeviceVariablePointerFeaturesKHR variable_pointers{}; @@ -960,7 +986,7 @@ void Device::CheckSuitability(bool requires_swapchain) const { physical.GetFeatures2KHR(features2); const VkPhysicalDeviceFeatures& features{features2.features}; - const std::array feature_report{ + std::vector feature_report{ std::make_pair(features.robustBufferAccess, "robustBufferAccess"), std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"), std::make_pair(features.imageCubeArray, "imageCubeArray"), @@ -983,27 +1009,30 @@ void Device::CheckSuitability(bool requires_swapchain) const { "shaderStorageImageWriteWithoutFormat"), std::make_pair(features.shaderClipDistance, "shaderClipDistance"), std::make_pair(features.shaderCullDistance, "shaderCullDistance"), - std::make_pair(demote.shaderDemoteToHelperInvocation, "shaderDemoteToHelperInvocation"), std::make_pair(variable_pointers.variablePointers, "variablePointers"), std::make_pair(variable_pointers.variablePointersStorageBuffer, "variablePointersStorageBuffer"), std::make_pair(robustness2.robustBufferAccess2, "robustBufferAccess2"), std::make_pair(robustness2.robustImageAccess2, "robustImageAccess2"), std::make_pair(robustness2.nullDescriptor, "nullDescriptor"), + std::make_pair(demote.shaderDemoteToHelperInvocation, "shaderDemoteToHelperInvocation"), }; + + bool has_all_required_features = true; for (const auto& [is_supported, name] : feature_report) { - if (is_supported) { - continue; + if (!is_supported) { + LOG_ERROR(Render_Vulkan, "Missing required feature: {}", name); + has_all_required_features = false; } - LOG_ERROR(Render_Vulkan, "Missing required feature: {}", name); + } + + if (!has_all_required_features) { throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT); } } std::vector<const char*> Device::LoadExtensions(bool requires_surface) { - std::vector<const char*> extensions; - extensions.reserve(8 + REQUIRED_EXTENSIONS.size()); - extensions.insert(extensions.begin(), REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end()); + std::vector<const char*> extensions = ExtensionsRequiredForInstanceVersion(instance_version); if (requires_surface) { extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); } diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index d7cc6c593..c85fbba77 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -211,11 +211,6 @@ public: return khr_uniform_buffer_standard_layout; } - /// Returns true if the device supports VK_KHR_spirv_1_4. - bool IsKhrSpirv1_4Supported() const { - return khr_spirv_1_4; - } - /// Returns true if the device supports VK_KHR_push_descriptor. bool IsKhrPushDescriptorSupported() const { return khr_push_descriptor; @@ -316,6 +311,17 @@ public: return ext_shader_atomic_int64; } + /// Returns the minimum supported version of SPIR-V. + u32 SupportedSpirvVersion() const { + if (instance_version >= VK_API_VERSION_1_3) { + return 0x00010600U; + } + if (khr_spirv_1_4) { + return 0x00010400U; + } + return 0x00010000U; + } + /// Returns true when a known debugging tool is attached. bool HasDebuggingToolAttached() const { return has_renderdoc || has_nsight_graphics; diff --git a/src/video_core/vulkan_common/vulkan_instance.cpp b/src/video_core/vulkan_common/vulkan_instance.cpp index a082e3059..562039b56 100644 --- a/src/video_core/vulkan_common/vulkan_instance.cpp +++ b/src/video_core/vulkan_common/vulkan_instance.cpp @@ -9,18 +9,21 @@ #include "common/common_types.h" #include "common/dynamic_library.h" #include "common/logging/log.h" +#include "common/polyfill_ranges.h" #include "core/frontend/emu_window.h" #include "video_core/vulkan_common/vulkan_instance.h" #include "video_core/vulkan_common/vulkan_wrapper.h" // Include these late to avoid polluting previous headers -#ifdef _WIN32 +#if defined(_WIN32) #include <windows.h> // ensure include order #include <vulkan/vulkan_win32.h> -#endif - -#if !defined(_WIN32) && !defined(__APPLE__) +#elif defined(__APPLE__) +#include <vulkan/vulkan_macos.h> +#elif defined(__ANDROID__) +#include <vulkan/vulkan_android.h> +#else #include <X11/Xlib.h> #include <vulkan/vulkan_wayland.h> #include <vulkan/vulkan_xlib.h> @@ -39,8 +42,15 @@ namespace { case Core::Frontend::WindowSystemType::Windows: extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); break; -#endif -#if !defined(_WIN32) && !defined(__APPLE__) +#elif defined(__APPLE__) + case Core::Frontend::WindowSystemType::Cocoa: + extensions.push_back(VK_MVK_MACOS_SURFACE_EXTENSION_NAME); + break; +#elif defined(__ANDROID__) + case Core::Frontend::WindowSystemType::Android: + extensions.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME); + break; +#else case Core::Frontend::WindowSystemType::X11: extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); break; @@ -59,6 +69,10 @@ namespace { extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); } extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + +#ifdef __APPLE__ + extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); +#endif return extensions; } @@ -140,7 +154,7 @@ vk::Instance CreateInstance(const Common::DynamicLibrary& library, vk::InstanceD } vk::Instance instance = std::async([&] { - return vk::Instance::Create(required_version, layers, extensions, dld); + return vk::Instance::Create(available_version, layers, extensions, dld); }).get(); if (!vk::Load(*instance, dld)) { LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers"); diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp index 6442898bd..1732866e0 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp @@ -12,6 +12,7 @@ #include "common/assert.h" #include "common/common_types.h" #include "common/logging/log.h" +#include "common/polyfill_ranges.h" #include "video_core/vulkan_common/vulkan_device.h" #include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_wrapper.h" diff --git a/src/video_core/vulkan_common/vulkan_surface.cpp b/src/video_core/vulkan_common/vulkan_surface.cpp index 69f9c494b..fa9bafa20 100644 --- a/src/video_core/vulkan_common/vulkan_surface.cpp +++ b/src/video_core/vulkan_common/vulkan_surface.cpp @@ -11,9 +11,11 @@ #include <windows.h> // ensure include order #include <vulkan/vulkan_win32.h> -#endif - -#if !defined(_WIN32) && !defined(__APPLE__) +#elif defined(__APPLE__) +#include <vulkan/vulkan_macos.h> +#elif defined(__ANDROID__) +#include <vulkan/vulkan_android.h> +#else #include <X11/Xlib.h> #include <vulkan/vulkan_wayland.h> #include <vulkan/vulkan_xlib.h> @@ -40,8 +42,33 @@ vk::SurfaceKHR CreateSurface(const vk::Instance& instance, throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); } } -#endif -#if !defined(_WIN32) && !defined(__APPLE__) +#elif defined(__APPLE__) + if (window_info.type == Core::Frontend::WindowSystemType::Cocoa) { + const VkMacOSSurfaceCreateInfoMVK mvk_ci{VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK, + nullptr, 0, window_info.render_surface}; + const auto vkCreateMacOSSurfaceMVK = reinterpret_cast<PFN_vkCreateMacOSSurfaceMVK>( + dld.vkGetInstanceProcAddr(*instance, "vkCreateMacOSSurfaceMVK")); + if (!vkCreateMacOSSurfaceMVK || + vkCreateMacOSSurfaceMVK(*instance, &mvk_ci, nullptr, &unsafe_surface) != VK_SUCCESS) { + LOG_ERROR(Render_Vulkan, "Failed to initialize Metal surface"); + throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); + } + } +#elif defined(__ANDROID__) + if (window_info.type == Core::Frontend::WindowSystemType::Android) { + const VkAndroidSurfaceCreateInfoKHR android_ci{ + VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR, nullptr, 0, + reinterpret_cast<ANativeWindow*>(window_info.render_surface)}; + const auto vkCreateAndroidSurfaceKHR = reinterpret_cast<PFN_vkCreateAndroidSurfaceKHR>( + dld.vkGetInstanceProcAddr(*instance, "vkCreateAndroidSurfaceKHR")); + if (!vkCreateAndroidSurfaceKHR || + vkCreateAndroidSurfaceKHR(*instance, &android_ci, nullptr, &unsafe_surface) != + VK_SUCCESS) { + LOG_ERROR(Render_Vulkan, "Failed to initialize Android surface"); + throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); + } + } +#else if (window_info.type == Core::Frontend::WindowSystemType::X11) { const VkXlibSurfaceCreateInfoKHR xlib_ci{ VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, nullptr, 0, @@ -70,6 +97,7 @@ vk::SurfaceKHR CreateSurface(const vk::Instance& instance, } } #endif + if (!unsafe_surface) { LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform"); throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); diff --git a/src/web_service/CMakeLists.txt b/src/web_service/CMakeLists.txt index 3f75d97d1..19534b9e4 100644 --- a/src/web_service/CMakeLists.txt +++ b/src/web_service/CMakeLists.txt @@ -4,6 +4,7 @@ add_library(web_service STATIC announce_room_json.cpp announce_room_json.h + precompiled_headers.h telemetry_json.cpp telemetry_json.h verify_login.cpp @@ -17,3 +18,7 @@ add_library(web_service STATIC create_target_directory_groups(web_service) target_link_libraries(web_service PRIVATE common network nlohmann_json::nlohmann_json httplib cpp-jwt) + +if (YUZU_USE_PRECOMPILED_HEADERS) + target_precompile_headers(web_service PRIVATE precompiled_headers.h) +endif() diff --git a/src/web_service/precompiled_headers.h b/src/web_service/precompiled_headers.h new file mode 100644 index 000000000..aabae730b --- /dev/null +++ b/src/web_service/precompiled_headers.h @@ -0,0 +1,6 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_precompiled_headers.h" diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 0aa109dd3..656dd79a9 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -186,6 +186,7 @@ add_executable(yuzu multiplayer/state.cpp multiplayer/state.h multiplayer/validation.h + precompiled_headers.h startup_checks.cpp startup_checks.h uisettings.cpp @@ -387,7 +388,11 @@ if (YUZU_USE_BUNDLED_QT AND QT_VERSION VERSION_LESS 6) endif() if (ENABLE_SDL2) - target_link_libraries(yuzu PRIVATE SDL2) + if (YUZU_USE_EXTERNAL_SDL2) + target_link_libraries(yuzu PRIVATE SDL2-static) + else() + target_link_libraries(yuzu PRIVATE SDL2) + endif() target_compile_definitions(yuzu PRIVATE HAVE_SDL2) endif() @@ -405,3 +410,7 @@ endif() if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) target_link_libraries(yuzu PRIVATE dynarmic) endif() + +if (YUZU_USE_PRECOMPILED_HEADERS) + target_precompile_headers(yuzu PRIVATE precompiled_headers.h) +endif() diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index f140e951f..5b5b6fed8 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -118,7 +118,7 @@ void EmuThread::run() { } } else { std::unique_lock lock{running_mutex}; - running_cv.wait(lock, stop_token, [this] { return IsRunning(); }); + Common::CondvarWait(running_cv, lock, stop_token, [&] { return IsRunning(); }); } } @@ -269,6 +269,10 @@ static Core::Frontend::WindowSystemType GetWindowSystemType() { return Core::Frontend::WindowSystemType::X11; else if (platform_name == QStringLiteral("wayland")) return Core::Frontend::WindowSystemType::Wayland; + else if (platform_name == QStringLiteral("cocoa")) + return Core::Frontend::WindowSystemType::Cocoa; + else if (platform_name == QStringLiteral("android")) + return Core::Frontend::WindowSystemType::Android; LOG_CRITICAL(Frontend, "Unknown Qt platform!"); return Core::Frontend::WindowSystemType::Windows; diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 2e19a879e..f4deae4ee 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -14,6 +14,7 @@ #include <QTouchEvent> #include <QWidget> +#include "common/polyfill_thread.h" #include "common/thread.h" #include "core/frontend/emu_window.h" diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index 4a875f86a..8ca683966 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp @@ -365,7 +365,7 @@ void ConfigureGraphics::RetrieveVulkanDevices() try { vk::InstanceDispatch dld; const Common::DynamicLibrary library = OpenLibrary(); - const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_0); + const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_1); const std::vector<VkPhysicalDevice> physical_devices = instance.EnumeratePhysicalDevices(); vulkan_devices.clear(); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index be13024c6..e06ee7570 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -167,6 +167,7 @@ __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; constexpr int default_mouse_hide_timeout = 2500; constexpr int default_mouse_center_timeout = 10; +constexpr int default_input_update_timeout = 1; /** * "Callouts" are one-time instructional messages shown to the user. In the config settings, there @@ -405,6 +406,10 @@ GMainWindow::GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan mouse_center_timer.setInterval(default_mouse_center_timeout); connect(&mouse_center_timer, &QTimer::timeout, this, &GMainWindow::CenterMouseCursor); + update_input_timer.setInterval(default_input_update_timeout); + connect(&update_input_timer, &QTimer::timeout, this, &GMainWindow::UpdateInputDrivers); + update_input_timer.start(); + MigrateConfigFiles(); if (has_broken_vulkan) { @@ -2827,6 +2832,7 @@ void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_tex } void GMainWindow::OnMenuReportCompatibility() { +#if defined(ARCHITECTURE_x86_64) && !defined(__APPLE__) const auto& caps = Common::GetCPUCaps(); const bool has_fma = caps.fma || caps.fma4; const auto processor_count = std::thread::hardware_concurrency(); @@ -2853,6 +2859,11 @@ void GMainWindow::OnMenuReportCompatibility() { "> " "Web.")); } +#else + QMessageBox::critical(this, tr("Hardware requirements not met"), + tr("Your system does not meet the recommended hardware requirements. " + "Compatibility reporting has been disabled.")); +#endif } void GMainWindow::OpenURL(const QUrl& url) { @@ -3647,6 +3658,13 @@ void GMainWindow::UpdateUISettings() { UISettings::values.first_start = false; } +void GMainWindow::UpdateInputDrivers() { + if (!input_subsystem) { + return; + } + input_subsystem->PumpEvents(); +} + void GMainWindow::HideMouseCursor() { if (emu_thread == nullptr && UISettings::values.hide_mouse) { mouse_hide_timer.stop(); @@ -4047,7 +4065,6 @@ void GMainWindow::UpdateUITheme() { const QString default_theme = QString::fromUtf8(UISettings::themes[static_cast<size_t>(Config::default_theme)].second); QString current_theme = UISettings::values.theme; - QStringList theme_paths(default_theme_paths); if (current_theme.isEmpty()) { current_theme = default_theme; @@ -4060,7 +4077,7 @@ void GMainWindow::UpdateUITheme() { if (current_theme == QStringLiteral("default") || current_theme == QStringLiteral("colorful")) { QIcon::setThemeName(current_theme == QStringLiteral("colorful") ? current_theme : startup_icon_theme); - QIcon::setThemeSearchPaths(theme_paths); + QIcon::setThemeSearchPaths(QStringList(default_theme_paths)); if (CheckDarkMode()) { current_theme = QStringLiteral("default_dark"); } diff --git a/src/yuzu/main.h b/src/yuzu/main.h index af6fcec3c..62d629973 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -355,6 +355,7 @@ private: void UpdateGPUAccuracyButton(); void UpdateStatusButtons(); void UpdateUISettings(); + void UpdateInputDrivers(); void HideMouseCursor(); void ShowMouseCursor(); void CenterMouseCursor(); @@ -406,6 +407,7 @@ private: bool auto_muted = false; QTimer mouse_hide_timer; QTimer mouse_center_timer; + QTimer update_input_timer; QString startup_icon_theme; bool os_dark_mode = false; diff --git a/src/yuzu/multiplayer/chat_room.h b/src/yuzu/multiplayer/chat_room.h index 01c70fad0..dd71ea4cd 100644 --- a/src/yuzu/multiplayer/chat_room.h +++ b/src/yuzu/multiplayer/chat_room.h @@ -4,6 +4,7 @@ #pragma once #include <memory> +#include <unordered_map> #include <unordered_set> #include <QDialog> #include <QSortFilterProxyModel> diff --git a/src/yuzu/precompiled_headers.h b/src/yuzu/precompiled_headers.h new file mode 100644 index 000000000..aabae730b --- /dev/null +++ b/src/yuzu/precompiled_headers.h @@ -0,0 +1,6 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_precompiled_headers.h" diff --git a/src/yuzu/startup_checks.cpp b/src/yuzu/startup_checks.cpp index 6a91212e2..563818362 100644 --- a/src/yuzu/startup_checks.cpp +++ b/src/yuzu/startup_checks.cpp @@ -4,16 +4,19 @@ #include "video_core/vulkan_common/vulkan_wrapper.h" #ifdef _WIN32 -#include <cstring> // for memset, strncpy +#include <cstring> #include <processthreadsapi.h> #include <windows.h> #elif defined(YUZU_UNIX) +#include <cstring> #include <errno.h> +#include <spawn.h> +#include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #endif -#include <cstdio> +#include <fmt/core.h> #include "video_core/vulkan_common/vulkan_instance.h" #include "video_core/vulkan_common/vulkan_library.h" #include "yuzu/startup_checks.h" @@ -24,10 +27,10 @@ void CheckVulkan() { Vulkan::vk::InstanceDispatch dld; const Common::DynamicLibrary library = Vulkan::OpenLibrary(); const Vulkan::vk::Instance instance = - Vulkan::CreateInstance(library, dld, VK_API_VERSION_1_0); + Vulkan::CreateInstance(library, dld, VK_API_VERSION_1_1); } catch (const Vulkan::vk::Exception& exception) { - std::fprintf(stderr, "Failed to initialize Vulkan: %s\n", exception.what()); + fmt::print(stderr, "Failed to initialize Vulkan: {}\n", exception.what()); } } @@ -49,8 +52,15 @@ bool CheckEnvVars(bool* is_child) { *is_child = true; return false; } else if (!SetEnvironmentVariableA(IS_CHILD_ENV_VAR, ENV_VAR_ENABLED_TEXT)) { - std::fprintf(stderr, "SetEnvironmentVariableA failed to set %s with error %lu\n", - IS_CHILD_ENV_VAR, GetLastError()); + fmt::print(stderr, "SetEnvironmentVariableA failed to set {} with error {}\n", + IS_CHILD_ENV_VAR, GetLastError()); + return true; + } +#elif defined(YUZU_UNIX) + const char* startup_check_var = getenv(STARTUP_CHECK_ENV_VAR); + if (startup_check_var != nullptr && + std::strncmp(startup_check_var, ENV_VAR_ENABLED_TEXT, 8) == 0) { + CheckVulkan(); return true; } #endif @@ -62,8 +72,8 @@ bool StartupChecks(const char* arg0, bool* has_broken_vulkan, bool perform_vulka // Set the startup variable for child processes const bool env_var_set = SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, ENV_VAR_ENABLED_TEXT); if (!env_var_set) { - std::fprintf(stderr, "SetEnvironmentVariableA failed to set %s with error %lu\n", - STARTUP_CHECK_ENV_VAR, GetLastError()); + fmt::print(stderr, "SetEnvironmentVariableA failed to set {} with error {}\n", + STARTUP_CHECK_ENV_VAR, GetLastError()); return false; } @@ -81,48 +91,57 @@ bool StartupChecks(const char* arg0, bool* has_broken_vulkan, bool perform_vulka DWORD exit_code = STILL_ACTIVE; const int err = GetExitCodeProcess(process_info.hProcess, &exit_code); if (err == 0) { - std::fprintf(stderr, "GetExitCodeProcess failed with error %lu\n", GetLastError()); + fmt::print(stderr, "GetExitCodeProcess failed with error {}\n", GetLastError()); } // Vulkan is broken if the child crashed (return value is not zero) *has_broken_vulkan = (exit_code != 0); if (CloseHandle(process_info.hProcess) == 0) { - std::fprintf(stderr, "CloseHandle failed with error %lu\n", GetLastError()); + fmt::print(stderr, "CloseHandle failed with error {}\n", GetLastError()); } if (CloseHandle(process_info.hThread) == 0) { - std::fprintf(stderr, "CloseHandle failed with error %lu\n", GetLastError()); + fmt::print(stderr, "CloseHandle failed with error {}\n", GetLastError()); } } if (!SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, nullptr)) { - std::fprintf(stderr, "SetEnvironmentVariableA failed to clear %s with error %lu\n", - STARTUP_CHECK_ENV_VAR, GetLastError()); + fmt::print(stderr, "SetEnvironmentVariableA failed to clear {} with error {}\n", + STARTUP_CHECK_ENV_VAR, GetLastError()); } #elif defined(YUZU_UNIX) + const int env_var_set = setenv(STARTUP_CHECK_ENV_VAR, ENV_VAR_ENABLED_TEXT, 1); + if (env_var_set == -1) { + const int err = errno; + fmt::print(stderr, "setenv failed to set {} with error {}\n", STARTUP_CHECK_ENV_VAR, err); + return false; + } + if (perform_vulkan_check) { - const pid_t pid = fork(); - if (pid == 0) { - CheckVulkan(); - return true; - } else if (pid == -1) { - const int err = errno; - std::fprintf(stderr, "fork failed with error %d\n", err); + const pid_t pid = SpawnChild(arg0); + if (pid == -1) { return false; } // Get exit code from child process int status; - const int r_val = wait(&status); + const int r_val = waitpid(pid, &status, 0); if (r_val == -1) { const int err = errno; - std::fprintf(stderr, "wait failed with error %d\n", err); + fmt::print(stderr, "wait failed with error {}\n", err); return false; } // Vulkan is broken if the child crashed (return value is not zero) *has_broken_vulkan = (status != 0); } + + const int env_var_cleared = unsetenv(STARTUP_CHECK_ENV_VAR); + if (env_var_cleared == -1) { + const int err = errno; + fmt::print(stderr, "unsetenv failed to clear {} with error {}\n", STARTUP_CHECK_ENV_VAR, + err); + } #endif return false; } @@ -150,10 +169,29 @@ bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi, int flags) { pi // lpProcessInformation ); if (!process_created) { - std::fprintf(stderr, "CreateProcessA failed with error %lu\n", GetLastError()); + fmt::print(stderr, "CreateProcessA failed with error {}\n", GetLastError()); return false; } return true; } +#elif defined(YUZU_UNIX) +pid_t SpawnChild(const char* arg0) { + const pid_t pid = fork(); + + if (pid == -1) { + // error + const int err = errno; + fmt::print(stderr, "fork failed with error {}\n", err); + return pid; + } else if (pid == 0) { + // child + execl(arg0, arg0, nullptr); + const int err = errno; + fmt::print(stderr, "execl failed with error {}\n", err); + _exit(0); + } + + return pid; +} #endif diff --git a/src/yuzu/startup_checks.h b/src/yuzu/startup_checks.h index d8e563be6..2f86fb843 100644 --- a/src/yuzu/startup_checks.h +++ b/src/yuzu/startup_checks.h @@ -5,6 +5,8 @@ #ifdef _WIN32 #include <windows.h> +#elif defined(YUZU_UNIX) +#include <sys/types.h> #endif constexpr char IS_CHILD_ENV_VAR[] = "YUZU_IS_CHILD"; @@ -17,4 +19,6 @@ bool StartupChecks(const char* arg0, bool* has_broken_vulkan, bool perform_vulka #ifdef _WIN32 bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi, int flags); +#elif defined(YUZU_UNIX) +pid_t SpawnChild(const char* arg0); #endif diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt index 774d026aa..13b673186 100644 --- a/src/yuzu_cmd/CMakeLists.txt +++ b/src/yuzu_cmd/CMakeLists.txt @@ -26,6 +26,7 @@ add_executable(yuzu-cmd emu_window/emu_window_sdl2_null.h emu_window/emu_window_sdl2_vk.cpp emu_window/emu_window_sdl2_vk.h + precompiled_headers.h yuzu.cpp yuzu.rc ) @@ -57,3 +58,7 @@ if (MSVC) include(CopyYuzuSDLDeps) copy_yuzu_SDL_deps(yuzu-cmd) endif() + +if (YUZU_USE_PRECOMPILED_HEADERS) + target_precompile_headers(yuzu-cmd PRIVATE precompiled_headers.h) +endif() diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index d6bea9aa8..59f9c8e09 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp @@ -90,7 +90,11 @@ static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> template <> void Config::ReadSetting(const std::string& group, Settings::Setting<std::string>& setting) { - setting = sdl2_config->Get(group, setting.GetLabel(), setting.GetDefault()); + std::string setting_value = sdl2_config->Get(group, setting.GetLabel(), setting.GetDefault()); + if (setting_value.empty()) { + setting_value = setting.GetDefault(); + } + setting = std::move(setting_value); } template <> diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp index 25948328c..0d580fe4f 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp @@ -51,11 +51,6 @@ EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsyste window_info.type = Core::Frontend::WindowSystemType::Windows; window_info.render_surface = reinterpret_cast<void*>(wm.info.win.window); break; -#else - case SDL_SYSWM_TYPE::SDL_SYSWM_WINDOWS: - LOG_CRITICAL(Frontend, "Window manager subsystem Windows not compiled"); - std::exit(EXIT_FAILURE); - break; #endif #ifdef SDL_VIDEO_DRIVER_X11 case SDL_SYSWM_TYPE::SDL_SYSWM_X11: @@ -63,11 +58,6 @@ EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsyste window_info.display_connection = wm.info.x11.display; window_info.render_surface = reinterpret_cast<void*>(wm.info.x11.window); break; -#else - case SDL_SYSWM_TYPE::SDL_SYSWM_X11: - LOG_CRITICAL(Frontend, "Window manager subsystem X11 not compiled"); - std::exit(EXIT_FAILURE); - break; #endif #ifdef SDL_VIDEO_DRIVER_WAYLAND case SDL_SYSWM_TYPE::SDL_SYSWM_WAYLAND: @@ -75,14 +65,21 @@ EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsyste window_info.display_connection = wm.info.wl.display; window_info.render_surface = wm.info.wl.surface; break; -#else - case SDL_SYSWM_TYPE::SDL_SYSWM_WAYLAND: - LOG_CRITICAL(Frontend, "Window manager subsystem Wayland not compiled"); - std::exit(EXIT_FAILURE); +#endif +#ifdef SDL_VIDEO_DRIVER_COCOA + case SDL_SYSWM_TYPE::SDL_SYSWM_COCOA: + window_info.type = Core::Frontend::WindowSystemType::Cocoa; + window_info.render_surface = SDL_Metal_CreateView(render_window); + break; +#endif +#ifdef SDL_VIDEO_DRIVER_ANDROID + case SDL_SYSWM_TYPE::SDL_SYSWM_ANDROID: + window_info.type = Core::Frontend::WindowSystemType::Android; + window_info.render_surface = reinterpret_cast<void*>(wm.info.android.window); break; #endif default: - LOG_CRITICAL(Frontend, "Window manager subsystem not implemented"); + LOG_CRITICAL(Frontend, "Window manager subsystem {} not implemented", wm.subsystem); std::exit(EXIT_FAILURE); break; } diff --git a/src/yuzu_cmd/precompiled_headers.h b/src/yuzu_cmd/precompiled_headers.h new file mode 100644 index 000000000..aabae730b --- /dev/null +++ b/src/yuzu_cmd/precompiled_headers.h @@ -0,0 +1,6 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_precompiled_headers.h" |