diff --git a/cpmfile.json b/cpmfile.json index c938e67e88..1bb29afae4 100644 --- a/cpmfile.json +++ b/cpmfile.json @@ -87,8 +87,8 @@ "bundled": true }, "llvm-mingw": { - "repo": "misc/llvm-mingw", - "git_host": "git.crueter.xyz", + "repo": "eden-emu/llvm-mingw", + "git_host": "git.eden-emu.dev", "tag": "%VERSION%", "version": "20250828", "artifact": "clang-rt-builtins.tar.zst", diff --git a/externals/cpmfile.json b/externals/cpmfile.json index 8209e431a3..d67348cd68 100644 --- a/externals/cpmfile.json +++ b/externals/cpmfile.json @@ -246,12 +246,13 @@ }, "tzdb": { "package": "nx_tzdb", - "repo": "misc/tzdb_to_nx", - "git_host": "git.crueter.xyz", + "repo": "eden-emu/tzdb_to_nx", + "git_host": "git.eden-emu.dev", "artifact": "%VERSION%.tar.gz", "tag": "%VERSION%", - "hash": "dc37a189a44ce8b5c988ca550582431a6c7eadfd3c6e709bee6277116ee803e714333e85c9e6cbb5c69346a14d6f2cc7ed96e8aa09cc5fb8a89f945059651db6", - "version": "121125" + "hash": "cce65a12bf90f4ead43b24a0b95dfad77ac3d9bfbaaf66c55e6701346e7a1e44ca5d2f23f47ee35ee02271eb1082bf1762af207aad9fb236f1c8476812d008ed", + "version": "121125", + "git_version": "230326" }, "vulkan-headers": { "repo": "KhronosGroup/Vulkan-Headers", diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt index a20858f0a9..6f25856cbf 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt @@ -670,15 +670,6 @@ abstract class SettingsItem( valuesId = R.array.dmaAccuracyValues ) ) - put( - SingleChoiceSetting( - IntSetting.FRAME_PACING_MODE, - titleId = R.string.frame_pacing_mode, - descriptionId = R.string.frame_pacing_mode_description, - choicesId = R.array.framePacingModeNames, - valuesId = R.array.framePacingModeValues - ) - ) put( SwitchSetting( BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS, diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index 853e1e3e4b..060a6fe9ae 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -256,7 +256,6 @@ class SettingsFragmentPresenter( add(IntSetting.RENDERER_ACCURACY.key) add(IntSetting.DMA_ACCURACY.key) - add(IntSetting.FRAME_PACING_MODE.key) add(IntSetting.MAX_ANISOTROPY.key) add(IntSetting.RENDERER_VRAM_USAGE_MODE.key) add(IntSetting.RENDERER_ASTC_DECODE_METHOD.key) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt index 877097dc80..3aa55522e6 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt @@ -29,7 +29,6 @@ import org.yuzu.yuzu_emu.databinding.FragmentDriverManagerBinding import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.features.settings.model.StringSetting import org.yuzu.yuzu_emu.features.settings.ui.SettingsSubscreen -import org.yuzu.yuzu_emu.model.Driver.Companion.toDriver import org.yuzu.yuzu_emu.model.DriverViewModel import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.utils.FileUtil @@ -216,19 +215,23 @@ class DriverManagerFragment : Fragment() { val driverData = GpuDriverHelper.getMetadataFromZip(driverFile) val driverInList = - driverViewModel.driverData.firstOrNull { it.second == driverData } + driverViewModel.driverData.firstOrNull { + it.first == driverPath || it.second == driverData + } if (driverInList != null) { return@newInstance getString(R.string.driver_already_installed) } else { driverViewModel.onDriverAdded(Pair(driverPath, driverData)) withContext(Dispatchers.Main) { if (_binding != null) { + refreshDriverList() val adapter = binding.listDrivers.adapter as DriverAdapter - adapter.addItem(driverData.toDriver()) - adapter.selectItem(adapter.currentList.indices.last) + val selectedPosition = adapter.currentList + .indexOfFirst { it.selected } + .let { if (it == -1) 0 else it } driverViewModel.showClearButton(!StringSetting.DRIVER_PATH.global) binding.listDrivers - .smoothScrollToPosition(adapter.currentList.indices.last) + .smoothScrollToPosition(selectedPosition) } } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt index fc7fbc9bfc..3904f83279 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt @@ -154,15 +154,30 @@ class DriverViewModel : ViewModel() { } fun onDriverRemoved(removedPosition: Int, selectedPosition: Int) { - driversToDelete.add(driverData[removedPosition - 1].first) - driverData.removeAt(removedPosition - 1) - onDriverSelected(selectedPosition) + val driverIndex = removedPosition - 1 + if (driverIndex !in driverData.indices) { + updateDriverList() + return + } + + driversToDelete.add(driverData[driverIndex].first) + driverData.removeAt(driverIndex) + val safeSelectedPosition = selectedPosition.coerceIn(0, driverData.size) + onDriverSelected(safeSelectedPosition) } fun onDriverAdded(driver: Pair) { if (driversToDelete.contains(driver.first)) { driversToDelete.remove(driver.first) } + + val existingDriverIndex = driverData.indexOfFirst { + it.first == driver.first || it.second == driver.second + } + if (existingDriverIndex != -1) { + onDriverSelected(existingDriverIndex + 1) + return + } driverData.add(driver) onDriverSelected(driverData.size) } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt index 02368bfc16..584322df50 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt @@ -86,8 +86,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider { binding = ActivityMainBinding.inflate(layoutInflater) - // Since Android 15, google automatically forces "games" to be 60 hrz - // This ensures the display's max refresh rate is actually used display?.let { val supportedModes = it.supportedModes val maxRefreshRate = supportedModes.maxByOrNull { mode -> mode.refreshRate } diff --git a/src/android/app/src/main/jni/emu_window/emu_window.cpp b/src/android/app/src/main/jni/emu_window/emu_window.cpp index 4e6fd560f4..6886dac172 100644 --- a/src/android/app/src/main/jni/emu_window/emu_window.cpp +++ b/src/android/app/src/main/jni/emu_window/emu_window.cpp @@ -6,8 +6,15 @@ #include +#include +#include +#include +#include +#include + #include "common/android/id_cache.h" #include "common/logging.h" +#include "common/settings.h" #include "input_common/drivers/android.h" #include "input_common/drivers/touch_screen.h" #include "input_common/drivers/virtual_amiibo.h" @@ -22,6 +29,12 @@ void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) { m_window_width = 0; m_window_height = 0; window_info.render_surface = nullptr; + m_last_frame_rate_hint = -1.0f; + m_pending_frame_rate_hint = -1.0f; + m_pending_frame_rate_hint_votes = 0; + m_smoothed_present_rate = 0.0f; + m_last_frame_display_time = {}; + m_pending_frame_rate_since = {}; return; } @@ -32,6 +45,7 @@ void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) { UpdateCurrentFramebufferLayout(m_window_width, m_window_height); window_info.render_surface = reinterpret_cast(surface); + UpdateFrameRateHint(); } void EmuWindow_Android::OnTouchPressed(int id, float x, float y) { @@ -51,6 +65,9 @@ void EmuWindow_Android::OnTouchReleased(int id) { } void EmuWindow_Android::OnFrameDisplayed() { + UpdateObservedFrameRate(); + UpdateFrameRateHint(); + if (!m_first_frame) { Common::Android::RunJNIOnFiber( [&](JNIEnv* env) { EmulationSession::GetInstance().OnEmulationStarted(); }); @@ -58,6 +75,175 @@ void EmuWindow_Android::OnFrameDisplayed() { } } +void EmuWindow_Android::UpdateObservedFrameRate() { + const auto now = Clock::now(); + if (m_last_frame_display_time.time_since_epoch().count() != 0) { + const auto frame_time = std::chrono::duration(now - m_last_frame_display_time); + const float seconds = frame_time.count(); + if (seconds > 0.0f) { + const float instantaneous_rate = 1.0f / seconds; + if (std::isfinite(instantaneous_rate) && instantaneous_rate >= 1.0f && + instantaneous_rate <= 240.0f) { + constexpr float SmoothingFactor = 0.15f; + if (m_smoothed_present_rate <= 0.0f) { + m_smoothed_present_rate = instantaneous_rate; + } else { + m_smoothed_present_rate += + (instantaneous_rate - m_smoothed_present_rate) * SmoothingFactor; + } + } + } + } + m_last_frame_display_time = now; +} + +float EmuWindow_Android::QuantizeFrameRateHint(float frame_rate) { + if (!std::isfinite(frame_rate) || frame_rate <= 0.0f) { + return 0.0f; + } + + frame_rate = std::clamp(frame_rate, 1.0f, 240.0f); + + constexpr float Step = 0.5f; + return std::round(frame_rate / Step) * Step; +} + +float EmuWindow_Android::GetFrameTimeVerifiedHint() const { + if (!EmulationSession::GetInstance().IsRunning()) { + return 0.0f; + } + + const double frame_time_scale = + EmulationSession::GetInstance().System().GetPerfStats().GetLastFrameTimeScale(); + if (!std::isfinite(frame_time_scale) || frame_time_scale <= 0.0) { + return 0.0f; + } + + const float verified_rate = + std::clamp(60.0f / static_cast(frame_time_scale), 0.0f, 240.0f); + return QuantizeFrameRateHint(verified_rate); +} + +float EmuWindow_Android::GetFrameRateHint() const { + const float observed_rate = std::clamp(m_smoothed_present_rate, 0.0f, 240.0f); + const float frame_time_verified_hint = GetFrameTimeVerifiedHint(); + + if (m_last_frame_rate_hint > 0.0f && observed_rate > 0.0f) { + const float tolerance = std::max(m_last_frame_rate_hint * 0.12f, 4.0f); + if (std::fabs(observed_rate - m_last_frame_rate_hint) <= tolerance) { + return m_last_frame_rate_hint; + } + } + + const float observed_hint = QuantizeFrameRateHint(observed_rate); + if (observed_hint > 0.0f) { + if (frame_time_verified_hint > 0.0f) { + const float tolerance = std::max(observed_hint * 0.20f, 3.0f); + if (std::fabs(observed_hint - frame_time_verified_hint) <= tolerance) { + return QuantizeFrameRateHint((observed_hint + frame_time_verified_hint) * 0.5f); + } + } + return observed_hint; + } + + if (frame_time_verified_hint > 0.0f) { + return frame_time_verified_hint; + } + + constexpr float NominalFrameRate = 60.0f; + if (!Settings::values.use_speed_limit.GetValue()) { + return NominalFrameRate; + } + + const u16 speed_limit = Settings::SpeedLimit(); + if (speed_limit == 0) { + return 0.0f; + } + + const float speed_limited_rate = + NominalFrameRate * (static_cast(std::min(speed_limit, 100)) / 100.0f); + return QuantizeFrameRateHint(speed_limited_rate); +} + +void EmuWindow_Android::UpdateFrameRateHint() { + auto* const surface = reinterpret_cast(window_info.render_surface); + if (!surface) { + return; + } + + const auto now = Clock::now(); + const float frame_rate_hint = GetFrameRateHint(); + if (std::fabs(frame_rate_hint - m_last_frame_rate_hint) < 0.01f) { + m_pending_frame_rate_hint = frame_rate_hint; + m_pending_frame_rate_hint_votes = 0; + m_pending_frame_rate_since = {}; + return; + } + + if (frame_rate_hint == 0.0f) { + m_pending_frame_rate_hint = frame_rate_hint; + m_pending_frame_rate_hint_votes = 0; + m_pending_frame_rate_since = now; + } else if (m_last_frame_rate_hint >= 0.0f) { + if (std::fabs(frame_rate_hint - m_pending_frame_rate_hint) >= 0.01f) { + m_pending_frame_rate_hint = frame_rate_hint; + m_pending_frame_rate_hint_votes = 1; + m_pending_frame_rate_since = now; + return; + } + + ++m_pending_frame_rate_hint_votes; + if (m_pending_frame_rate_since.time_since_epoch().count() == 0) { + m_pending_frame_rate_since = now; + } + + const auto stable_for = now - m_pending_frame_rate_since; + const float reference_rate = std::max(frame_rate_hint, 1.0f); + const auto stable_duration = std::chrono::duration_cast( + std::chrono::duration(std::clamp(3.0f / reference_rate, 0.15f, 0.40f))); + constexpr std::uint32_t MinStableVotes = 3; + + if (m_pending_frame_rate_hint_votes < MinStableVotes || stable_for < stable_duration) { + return; + } + } else { + m_pending_frame_rate_since = now; + } + + using SetFrameRateWithChangeStrategyFn = + int32_t (*)(ANativeWindow*, float, int8_t, int8_t); + using SetFrameRateFn = int32_t (*)(ANativeWindow*, float, int8_t); + static const auto set_frame_rate_with_change_strategy = + reinterpret_cast( + dlsym(RTLD_DEFAULT, "ANativeWindow_setFrameRateWithChangeStrategy")); + static const auto set_frame_rate = reinterpret_cast( + dlsym(RTLD_DEFAULT, "ANativeWindow_setFrameRate")); + + constexpr int8_t FrameRateCompatibilityDefault = 0; + constexpr int8_t ChangeFrameRateOnlyIfSeamless = 0; + + int32_t result = -1; + if (set_frame_rate_with_change_strategy) { + result = set_frame_rate_with_change_strategy(surface, frame_rate_hint, + FrameRateCompatibilityDefault, + ChangeFrameRateOnlyIfSeamless); + } else if (set_frame_rate) { + result = set_frame_rate(surface, frame_rate_hint, FrameRateCompatibilityDefault); + } else { + return; + } + + if (result != 0) { + LOG_DEBUG(Frontend, "Failed to update Android surface frame rate hint: {}", result); + return; + } + + m_last_frame_rate_hint = frame_rate_hint; + m_pending_frame_rate_hint = frame_rate_hint; + m_pending_frame_rate_hint_votes = 0; + m_pending_frame_rate_since = {}; +} + EmuWindow_Android::EmuWindow_Android(ANativeWindow* surface, std::shared_ptr driver_library) : m_driver_library{driver_library} { diff --git a/src/android/app/src/main/jni/emu_window/emu_window.h b/src/android/app/src/main/jni/emu_window/emu_window.h index d7b5fc6dac..b73e8b9b4d 100644 --- a/src/android/app/src/main/jni/emu_window/emu_window.h +++ b/src/android/app/src/main/jni/emu_window/emu_window.h @@ -1,8 +1,13 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later #pragma once +#include +#include #include #include @@ -50,10 +55,24 @@ public: }; private: + using Clock = std::chrono::steady_clock; + + void UpdateFrameRateHint(); + void UpdateObservedFrameRate(); + [[nodiscard]] float GetFrameRateHint() const; + [[nodiscard]] float GetFrameTimeVerifiedHint() const; + [[nodiscard]] static float QuantizeFrameRateHint(float frame_rate); + float m_window_width{}; float m_window_height{}; std::shared_ptr m_driver_library; bool m_first_frame = false; + float m_last_frame_rate_hint = -1.0f; + float m_pending_frame_rate_hint = -1.0f; + float m_smoothed_present_rate = 0.0f; + Clock::time_point m_last_frame_display_time{}; + Clock::time_point m_pending_frame_rate_since{}; + std::uint32_t m_pending_frame_rate_hint_votes = 0; }; diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index d8767f9fed..43c569851d 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -712,9 +712,8 @@ public: private: void CheckAvailability(HLERequestContext& ctx) { LOG_DEBUG(Service_ACC, "(STUBBED) called"); - IPC::ResponseBuilder rb{ctx, 3}; + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); - rb.Push(false); // TODO: Check when this is supposed to return true and when not } void GetAccountId(HLERequestContext& ctx) { diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index 710a95a455..a0302a5841 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp @@ -183,8 +183,8 @@ struct NifmWirelessSettingData { static_assert(sizeof(NifmWirelessSettingData) == 0x70, "NifmWirelessSettingData has incorrect size."); -#pragma pack(push, 1) // This is nn::nifm::detail::sf::NetworkProfileData +#pragma pack(push, 1) struct SfNetworkProfileData { IpSettingData ip_setting_data{}; u128 uuid{}; @@ -196,9 +196,11 @@ struct SfNetworkProfileData { SfWirelessSettingData wireless_setting_data{}; INSERT_PADDING_BYTES(1); }; +#pragma pack(pop) static_assert(sizeof(SfNetworkProfileData) == 0x17C, "SfNetworkProfileData has incorrect size."); // This is nn::nifm::NetworkProfileData +#pragma pack(push, 1) struct NifmNetworkProfileData { u128 uuid{}; std::array network_name{}; @@ -210,8 +212,8 @@ struct NifmNetworkProfileData { NifmWirelessSettingData wireless_setting_data{}; IpSettingData ip_setting_data{}; }; -static_assert(sizeof(NifmNetworkProfileData) == 0x18E, - "NifmNetworkProfileData has incorrect size."); +#pragma pack(pop) +static_assert(sizeof(NifmNetworkProfileData) == 0x18E, "NifmNetworkProfileData has incorrect size."); struct PendingProfile { std::array ssid{}; diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp index 68d73f0a59..f9f0ee56eb 100644 --- a/src/core/hle/service/sockets/sfdnsres.cpp +++ b/src/core/hle/service/sockets/sfdnsres.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project @@ -53,12 +53,15 @@ enum class NetDbError : s32 { NoData = 4, }; -static const constexpr std::array blockedDomains = {"srv.nintendo.net", - "battle.net", - "microsoft.com", - "mojang.com", - "xboxlive.com", - "minecraftservices.com"}; +static const constexpr std::array blockedDomains = { + "srv.nintendo.net", //obvious + "phoenix-api.wbagora.com", //hogwarts legacy + "battle.net", + "microsoft.com", //minecraft dungeons + other games + "mojang.com", + "xboxlive.com", + "minecraftservices.com" +}; static bool IsBlockedHost(const std::string& host) { return std::any_of( diff --git a/src/dynarmic/src/dynarmic/CMakeLists.txt b/src/dynarmic/src/dynarmic/CMakeLists.txt index 3d2ea4d42e..50bf5a4604 100644 --- a/src/dynarmic/src/dynarmic/CMakeLists.txt +++ b/src/dynarmic/src/dynarmic/CMakeLists.txt @@ -53,7 +53,6 @@ add_library(dynarmic STATIC common/fp/util.h common/llvm_disassemble.cpp common/llvm_disassemble.h - common/lut_from_list.h common/math_util.cpp common/math_util.h common/safe_ops.h diff --git a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_vector_floating_point.cpp b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_vector_floating_point.cpp index 4d11c62abd..431d51c081 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_vector_floating_point.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_vector_floating_point.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -31,7 +31,6 @@ #include "dynarmic/common/fp/info.h" #include "dynarmic/common/fp/op.h" #include "dynarmic/common/fp/rounding_mode.h" -#include "dynarmic/common/lut_from_list.h" #include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/microinstruction.h" #include "dynarmic/ir/opcodes.h" diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp index 76c103ec6f..abe04b53ff 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp @@ -31,7 +31,6 @@ #include "dynarmic/common/fp/info.h" #include "dynarmic/common/fp/op.h" #include "dynarmic/common/fp/rounding_mode.h" -#include "dynarmic/common/lut_from_list.h" #include "dynarmic/interface/optimization_flags.h" #include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/microinstruction.h" diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp index 2247b18fcd..ee9ec39f46 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp @@ -31,7 +31,6 @@ #include "dynarmic/common/fp/info.h" #include "dynarmic/common/fp/op.h" #include "dynarmic/common/fp/util.h" -#include "dynarmic/common/lut_from_list.h" #include "dynarmic/interface/optimization_flags.h" #include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/microinstruction.h" @@ -2127,28 +2126,42 @@ void EmitFPVectorToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) { } } - using fbits_list = mp::lift_sequence>; - using rounding_list = mp::list< - mp::lift_value, - mp::lift_value, - mp::lift_value, - mp::lift_value, - mp::lift_value>; - - static const auto lut = Common::GenerateLookupTableFromList([](I) { - using FPT = mcl::unsigned_integer_of_size; // WORKAROUND: For issue 678 on MSVC - return std::pair{ - mp::lower_to_tuple_v, - Common::FptrCast([](VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { - constexpr size_t fbits = mp::get<0, I>::value; - constexpr FP::RoundingMode rounding_mode = mp::get<1, I>::value; + using FPT = mcl::unsigned_integer_of_size; // WORKAROUND: For issue 678 on MSVC + auto const func = [rounding]() -> void(*)(VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { + switch (rounding) { + case FP::RoundingMode::ToNearest_TieEven: + return [](VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { for (size_t i = 0; i < output.size(); ++i) - output[i] = FPT(FP::FPToFixed(fsize, input[i], fbits, unsigned_, fpcr, rounding_mode, fpsr)); - }) - }; - }, mp::cartesian_product{}); - - EmitTwoOpFallback<3>(code, ctx, inst, lut.at(std::make_tuple(fbits, rounding))); + output[i] = FPT(FP::FPToFixed(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::ToNearest_TieEven, fpsr)); + }; + case FP::RoundingMode::TowardsPlusInfinity: + return [](VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { + for (size_t i = 0; i < output.size(); ++i) + output[i] = FPT(FP::FPToFixed(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::TowardsPlusInfinity, fpsr)); + }; + case FP::RoundingMode::TowardsMinusInfinity: + return [](VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { + for (size_t i = 0; i < output.size(); ++i) + output[i] = FPT(FP::FPToFixed(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::TowardsMinusInfinity, fpsr)); + }; + case FP::RoundingMode::TowardsZero: + return [](VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { + for (size_t i = 0; i < output.size(); ++i) + output[i] = FPT(FP::FPToFixed(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::TowardsZero, fpsr)); + }; + case FP::RoundingMode::ToNearest_TieAwayFromZero: + return [](VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { + for (size_t i = 0; i < output.size(); ++i) + output[i] = FPT(FP::FPToFixed(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::ToNearest_TieAwayFromZero, fpsr)); + }; + case FP::RoundingMode::ToOdd: + return [](VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { + for (size_t i = 0; i < output.size(); ++i) + output[i] = FPT(FP::FPToFixed(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::ToOdd, fpsr)); + }; + } + }(); + EmitTwoOpFallback<3>(code, ctx, inst, func); } void EmitX64::EmitFPVectorToSignedFixed16(EmitContext& ctx, IR::Inst* inst) { diff --git a/src/dynarmic/src/dynarmic/common/lut_from_list.h b/src/dynarmic/src/dynarmic/common/lut_from_list.h deleted file mode 100644 index 633b62aeda..0000000000 --- a/src/dynarmic/src/dynarmic/common/lut_from_list.h +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -/* This file is part of the dynarmic project. - * Copyright (c) 2018 MerryMage - * SPDX-License-Identifier: 0BSD - */ - -#pragma once - -#include -#include -#include - -#include -#include -#include - -#ifdef _MSC_VER -# include -#endif - -namespace Dynarmic::Common { - -// prevents this function from printing 56,000 character warning messages -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wno-stack-usage" -#endif -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wno-stack-usage" -#endif - -template -inline auto GenerateLookupTableFromList(Function f, mcl::mp::list) { -#ifdef _MSC_VER - using PairT = std::invoke_result_t>>; -#else - using PairT = std::common_type_t...>; -#endif - using MapT = mcl::mp::apply; - static_assert(mcl::is_instance_of_template_v); - const std::initializer_list pair_array{f(Values{})...}; - return MapT(pair_array.begin(), pair_array.end()); -} - -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -} // namespace Dynarmic::Common diff --git a/src/dynarmic/tests/A32/fuzz_arm.cpp b/src/dynarmic/tests/A32/fuzz_arm.cpp index fd17b3bd01..cd2eade884 100644 --- a/src/dynarmic/tests/A32/fuzz_arm.cpp +++ b/src/dynarmic/tests/A32/fuzz_arm.cpp @@ -20,15 +20,14 @@ #include #include "dynarmic/common/common_types.h" -#include "../fuzz_util.h" -#include "../rand_int.h" -#include "../unicorn_emu/a32_unicorn.h" -#include "./testenv.h" -#include "../native/testenv.h" +#include "dynarmic/tests/fuzz_util.h" +#include "dynarmic/tests/rand_int.h" +#include "dynarmic/tests/unicorn_emu/a32_unicorn.h" +#include "dynarmic/tests/A32/testenv.h" +#include "dynarmic/tests/native/testenv.h" #include "dynarmic/common/fp/fpcr.h" #include "dynarmic/common/fp/fpsr.h" #include "dynarmic/common/llvm_disassemble.h" -#include "dynarmic/common/variant_util.h" #include "dynarmic/frontend/A32/ITState.h" #include "dynarmic/frontend/A32/a32_location_descriptor.h" #include "dynarmic/frontend/A32/a32_types.h" diff --git a/src/dynarmic/tests/A32/fuzz_thumb.cpp b/src/dynarmic/tests/A32/fuzz_thumb.cpp index 3a561a18d9..f985e6f93d 100644 --- a/src/dynarmic/tests/A32/fuzz_thumb.cpp +++ b/src/dynarmic/tests/A32/fuzz_thumb.cpp @@ -19,10 +19,10 @@ #include #include "dynarmic/common/common_types.h" -#include "../rand_int.h" -#include "../unicorn_emu/a32_unicorn.h" -#include "./testenv.h" -#include "../native/testenv.h" +#include "dynarmic/tests/rand_int.h" +#include "dynarmic/tests/unicorn_emu/a32_unicorn.h" +#include "dynarmic/tests/A32/testenv.h" +#include "dynarmic/tests/native/testenv.h" #include "dynarmic/frontend/A32/FPSCR.h" #include "dynarmic/frontend/A32/PSR.h" #include "dynarmic/frontend/A32/a32_location_descriptor.h" @@ -107,7 +107,7 @@ static bool DoesBehaviorMatch(const A32Unicorn& uni, const A32::Ji return std::equal(interp_regs.begin(), interp_regs.end(), jit_regs.begin(), jit_regs.end()) && uni.GetCpsr() == jit.Cpsr() && interp_write_records == jit_write_records; } -static void RunInstance(size_t run_number, ThumbTestEnv& test_env, A32Unicorn& uni, A32::Jit& jit, const ThumbTestEnv::RegisterArray& initial_regs, size_t instruction_count, size_t instructions_to_execute_count) { +static void RunInstance(size_t run_number, ThumbTestEnv& test_env, A32::UserConfig const& config, A32Unicorn& uni, A32::Jit& jit, const ThumbTestEnv::RegisterArray& initial_regs, size_t instruction_count, size_t instructions_to_execute_count) { uni.ClearPageCache(); jit.ClearCache(); @@ -145,9 +145,8 @@ static void RunInstance(size_t run_number, ThumbTestEnv& test_env, A32Unicorn uni{test_env}; - A32::Jit jit{GetUserConfig(&test_env)}; + A32::UserConfig config{GetUserConfig(&test_env)}; + A32::Jit jit{config}; constexpr ThumbTestEnv::RegisterArray initial_regs{ 0xe90ecd70, @@ -534,5 +539,5 @@ TEST_CASE("Verify fix for off by one error in MemoryRead32 worked", "[Thumb][Thu 0xE7FE, // b +#0 }; - RunInstance(1, test_env, uni, jit, initial_regs, 5, 5); + RunInstance(1, test_env, config, uni, jit, initial_regs, 5, 5); } diff --git a/src/dynarmic/tests/A32/test_arm_instructions.cpp b/src/dynarmic/tests/A32/test_arm_instructions.cpp index 2e7e7dc5d8..5a27cd499c 100644 --- a/src/dynarmic/tests/A32/test_arm_instructions.cpp +++ b/src/dynarmic/tests/A32/test_arm_instructions.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -8,8 +8,8 @@ #include -#include "./testenv.h" -#include "../native/testenv.h" +#include "dynarmic/tests/A32/testenv.h" +#include "dynarmic/tests/native/testenv.h" #include "dynarmic/frontend/A32/a32_location_descriptor.h" #include "dynarmic/interface/A32/a32.h" diff --git a/src/dynarmic/tests/A32/test_coprocessor.cpp b/src/dynarmic/tests/A32/test_coprocessor.cpp index 3888d2c68b..66ae6ebb09 100644 --- a/src/dynarmic/tests/A32/test_coprocessor.cpp +++ b/src/dynarmic/tests/A32/test_coprocessor.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -10,8 +10,8 @@ #include -#include "./testenv.h" -#include "../native/testenv.h" +#include "dynarmic/tests/A32/testenv.h" +#include "dynarmic/tests/native/testenv.h" #include "dynarmic/frontend/A32/a32_location_descriptor.h" #include "dynarmic/interface/A32/a32.h" #include "dynarmic/interface/A32/coprocessor.h" diff --git a/src/dynarmic/tests/A32/test_svc.cpp b/src/dynarmic/tests/A32/test_svc.cpp index 0be2432c7b..0cfaf23ec5 100644 --- a/src/dynarmic/tests/A32/test_svc.cpp +++ b/src/dynarmic/tests/A32/test_svc.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -10,8 +10,8 @@ #include -#include "./testenv.h" -#include "../native/testenv.h" +#include "dynarmic/tests/A32/testenv.h" +#include "dynarmic/tests/native/testenv.h" using namespace Dynarmic; diff --git a/src/dynarmic/tests/A32/test_thumb_instructions.cpp b/src/dynarmic/tests/A32/test_thumb_instructions.cpp index d509acdd8d..6aa1b7389b 100644 --- a/src/dynarmic/tests/A32/test_thumb_instructions.cpp +++ b/src/dynarmic/tests/A32/test_thumb_instructions.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -9,8 +9,8 @@ #include #include "dynarmic/common/common_types.h" -#include "./testenv.h" -#include "../native/testenv.h" +#include "dynarmic/tests/A32/testenv.h" +#include "dynarmic/tests/native/testenv.h" #include "dynarmic/interface/A32/a32.h" static Dynarmic::A32::UserConfig GetUserConfig(ThumbTestEnv* testenv) { diff --git a/src/dynarmic/tests/A64/a64.cpp b/src/dynarmic/tests/A64/a64.cpp index d331c5e8a1..4d4484e53e 100644 --- a/src/dynarmic/tests/A64/a64.cpp +++ b/src/dynarmic/tests/A64/a64.cpp @@ -9,8 +9,8 @@ #include #include -#include "./testenv.h" -#include "../native/testenv.h" +#include "dynarmic/tests/A64/testenv.h" +#include "dynarmic/tests/native/testenv.h" #include "dynarmic/common/fp/fpsr.h" #include "dynarmic/interface/exclusive_monitor.h" #include "dynarmic/interface/optimization_flags.h" diff --git a/src/dynarmic/tests/A64/fp_min_max.cpp b/src/dynarmic/tests/A64/fp_min_max.cpp index 1669b63071..313b5e5117 100644 --- a/src/dynarmic/tests/A64/fp_min_max.cpp +++ b/src/dynarmic/tests/A64/fp_min_max.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -11,8 +11,8 @@ #include #include "dynarmic/common/common_types.h" -#include "./testenv.h" -#include "../native/testenv.h" +#include "dynarmic/tests/A64/testenv.h" +#include "dynarmic/tests/native/testenv.h" using namespace Dynarmic; diff --git a/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp b/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp index 2cdf288eab..0c7a30a868 100644 --- a/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp +++ b/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp @@ -15,11 +15,11 @@ #include #include "dynarmic/common/common_types.h" -#include "../fuzz_util.h" -#include "../rand_int.h" -#include "../unicorn_emu/a64_unicorn.h" -#include "./testenv.h" -#include "../native/testenv.h" +#include "dynarmic/tests/fuzz_util.h" +#include "dynarmic/tests/rand_int.h" +#include "dynarmic/tests/unicorn_emu/a64_unicorn.h" +#include "dynarmic/tests/A64/testenv.h" +#include "dynarmic/tests/native/testenv.h" #include "dynarmic/common/fp/fpcr.h" #include "dynarmic/common/fp/fpsr.h" #include "dynarmic/common/llvm_disassemble.h" @@ -168,7 +168,7 @@ static Dynarmic::A64::UserConfig GetUserConfig(A64TestEnv& jit_env) { return jit_user_config; } -static void RunTestInstance(Dynarmic::A64::Jit& jit, A64Unicorn& uni, A64TestEnv& jit_env, A64TestEnv& uni_env, const A64Unicorn::RegisterArray& regs, const A64Unicorn::VectorArray& vecs, const size_t instructions_start, const std::vector& instructions, const u32 pstate, const u32 fpcr) { +static void RunTestInstance(Dynarmic::A64::Jit& jit, A64Unicorn& uni, A64TestEnv& jit_env, A64TestEnv& uni_env, Dynarmic::A64::UserConfig& conf, const A64Unicorn::RegisterArray& regs, const A64Unicorn::VectorArray& vecs, const size_t instructions_start, const std::vector& instructions, const u32 pstate, const u32 fpcr) { jit_env.code_mem = instructions; uni_env.code_mem = instructions; jit_env.code_mem.emplace_back(0x14000000); // B . @@ -269,16 +269,13 @@ static void RunTestInstance(Dynarmic::A64::Jit& jit, A64Unicorn& uni, A64TestEnv fmt::print("\n"); const auto get_code = [&jit_env](u64 vaddr) { return jit_env.MemoryReadCode(vaddr); }; - IR::Block ir_block = A64::Translate({instructions_start, FP::FPCR{fpcr}}, get_code, {}); - fmt::print("IR:\n"); - fmt::print("{}\n", IR::DumpBlock(ir_block)); + const A64::LocationDescriptor location{instructions_start, FP::FPCR{fpcr}}; + IR::Block ir_block{location}; + A64::Translate(ir_block, location, get_code, {}); + fmt::print("IR:\n{}\n", IR::DumpBlock(ir_block)); Optimization::Optimize(ir_block, conf, {}); - fmt::print("Optimized IR:\n"); - fmt::print("{}\n", IR::DumpBlock(ir_block)); - - fmt::print("x86_64:\n"); - fmt::print("{}", jit.Disassemble()); - + fmt::print("Optimized IR:\n{}\n", IR::DumpBlock(ir_block)); + fmt::print("x86_64:\n{}", jit.Disassemble()); fmt::print("Interrupts:\n"); for (auto& i : uni_env.interrupts) { puts(i.c_str()); @@ -304,7 +301,8 @@ TEST_CASE("A64: Single random instruction", "[a64][unicorn]") { A64TestEnv jit_env{}; A64TestEnv uni_env{}; - Dynarmic::A64::Jit jit{GetUserConfig(jit_env)}; + Dynarmic::A64::UserConfig conf{GetUserConfig(jit_env)}; + Dynarmic::A64::Jit jit{conf}; A64Unicorn uni{uni_env}; A64Unicorn::RegisterArray regs; @@ -323,7 +321,7 @@ TEST_CASE("A64: Single random instruction", "[a64][unicorn]") { INFO("Instruction: 0x" << std::hex << instructions[0]); - RunTestInstance(jit, uni, jit_env, uni_env, regs, vecs, start_address, instructions, pstate, fpcr); + RunTestInstance(jit, uni, jit_env, uni_env, conf, regs, vecs, start_address, instructions, pstate, fpcr); } } @@ -331,7 +329,8 @@ TEST_CASE("A64: Floating point instructions", "[a64][unicorn]") { A64TestEnv jit_env{}; A64TestEnv uni_env{}; - Dynarmic::A64::Jit jit{GetUserConfig(jit_env)}; + Dynarmic::A64::UserConfig conf{GetUserConfig(jit_env)}; + Dynarmic::A64::Jit jit{conf}; A64Unicorn uni{uni_env}; static constexpr std::array float_numbers{ @@ -448,7 +447,7 @@ TEST_CASE("A64: Floating point instructions", "[a64][unicorn]") { INFO("Instruction: 0x" << std::hex << instructions[0]); - RunTestInstance(jit, uni, jit_env, uni_env, regs, vecs, start_address, instructions, pstate, fpcr); + RunTestInstance(jit, uni, jit_env, uni_env, conf, regs, vecs, start_address, instructions, pstate, fpcr); } } @@ -456,7 +455,8 @@ TEST_CASE("A64: Small random block", "[a64][unicorn]") { A64TestEnv jit_env{}; A64TestEnv uni_env{}; - Dynarmic::A64::Jit jit{GetUserConfig(jit_env)}; + Dynarmic::A64::UserConfig conf{GetUserConfig(jit_env)}; + Dynarmic::A64::Jit jit{conf}; A64Unicorn uni{uni_env}; A64Unicorn::RegisterArray regs; @@ -483,7 +483,7 @@ TEST_CASE("A64: Small random block", "[a64][unicorn]") { INFO("Instruction 4: 0x" << std::hex << instructions[3]); INFO("Instruction 5: 0x" << std::hex << instructions[4]); - RunTestInstance(jit, uni, jit_env, uni_env, regs, vecs, start_address, instructions, pstate, fpcr); + RunTestInstance(jit, uni, jit_env, uni_env, conf, regs, vecs, start_address, instructions, pstate, fpcr); } } @@ -491,7 +491,8 @@ TEST_CASE("A64: Large random block", "[a64][unicorn]") { A64TestEnv jit_env{}; A64TestEnv uni_env{}; - Dynarmic::A64::Jit jit{GetUserConfig(jit_env)}; + Dynarmic::A64::UserConfig conf{GetUserConfig(jit_env)}; + Dynarmic::A64::Jit jit{conf}; A64Unicorn uni{uni_env}; A64Unicorn::RegisterArray regs; @@ -512,6 +513,6 @@ TEST_CASE("A64: Large random block", "[a64][unicorn]") { const u32 pstate = RandInt(0, 0xF) << 28; const u32 fpcr = RandomFpcr(); - RunTestInstance(jit, uni, jit_env, uni_env, regs, vecs, start_address, instructions, pstate, fpcr); + RunTestInstance(jit, uni, jit_env, uni_env, conf, regs, vecs, start_address, instructions, pstate, fpcr); } } diff --git a/src/dynarmic/tests/A64/misaligned_page_table.cpp b/src/dynarmic/tests/A64/misaligned_page_table.cpp index fc0bc77428..99afba519d 100644 --- a/src/dynarmic/tests/A64/misaligned_page_table.cpp +++ b/src/dynarmic/tests/A64/misaligned_page_table.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -8,8 +8,8 @@ #include -#include "./testenv.h" -#include "../native/testenv.h" +#include "dynarmic/tests/A64/testenv.h" +#include "dynarmic/tests/native/testenv.h" #include "dynarmic/interface/A64/a64.h" TEST_CASE("misaligned load/store do not use page_table when detect_misaligned_access_via_page_table is set", "[a64]") { diff --git a/src/dynarmic/tests/A64/real_world.cpp b/src/dynarmic/tests/A64/real_world.cpp index a083f16d61..c15f307c3d 100644 --- a/src/dynarmic/tests/A64/real_world.cpp +++ b/src/dynarmic/tests/A64/real_world.cpp @@ -1,11 +1,11 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later #include #include -#include "./testenv.h" -#include "../native/testenv.h" +#include "dynarmic/tests/A64/testenv.h" +#include "dynarmic/tests/native/testenv.h" #include "dynarmic/interface/A64/a64.h" using namespace Dynarmic; diff --git a/src/dynarmic/tests/A64/test_invalidation.cpp b/src/dynarmic/tests/A64/test_invalidation.cpp index 0c92f5f606..3b2d5fef98 100644 --- a/src/dynarmic/tests/A64/test_invalidation.cpp +++ b/src/dynarmic/tests/A64/test_invalidation.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -8,8 +8,8 @@ #include -#include "./testenv.h" -#include "../native/testenv.h" +#include "dynarmic/tests/A64/testenv.h" +#include "dynarmic/tests/native/testenv.h" #include "dynarmic/interface/A64/a64.h" using namespace Dynarmic; diff --git a/src/dynarmic/tests/A64/verify_unicorn.cpp b/src/dynarmic/tests/A64/verify_unicorn.cpp index 0c0ccc1609..5bdcd0dc3e 100644 --- a/src/dynarmic/tests/A64/verify_unicorn.cpp +++ b/src/dynarmic/tests/A64/verify_unicorn.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2018 MerryMage * SPDX-License-Identifier: 0BSD @@ -7,9 +10,9 @@ #include -#include "../rand_int.h" -#include "../unicorn_emu/a64_unicorn.h" -#include "./testenv.h" +#include "dynarmic/tests/rand_int.h" +#include "dynarmic/tests/unicorn_emu/a64_unicorn.h" +#include "dynarmic/tests/A64/testenv.h" using namespace Dynarmic; diff --git a/src/dynarmic/tests/fp/FPToFixed.cpp b/src/dynarmic/tests/fp/FPToFixed.cpp index 570ebcbbd7..e16e4460ed 100644 --- a/src/dynarmic/tests/fp/FPToFixed.cpp +++ b/src/dynarmic/tests/fp/FPToFixed.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -12,7 +12,7 @@ #include #include "dynarmic/common/common_types.h" -#include "../rand_int.h" +#include "dynarmic/tests/rand_int.h" #include "dynarmic/common/fp/fpcr.h" #include "dynarmic/common/fp/fpsr.h" #include "dynarmic/common/fp/op.h" diff --git a/src/dynarmic/tests/fp/mantissa_util_tests.cpp b/src/dynarmic/tests/fp/mantissa_util_tests.cpp index de29d51865..9d16c3624c 100644 --- a/src/dynarmic/tests/fp/mantissa_util_tests.cpp +++ b/src/dynarmic/tests/fp/mantissa_util_tests.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -12,7 +12,7 @@ #include #include "dynarmic/common/common_types.h" -#include "../rand_int.h" +#include "dynarmic/tests/rand_int.h" #include "dynarmic/common/fp/mantissa_util.h" #include "dynarmic/common/safe_ops.h" diff --git a/src/dynarmic/tests/fp/unpacked_tests.cpp b/src/dynarmic/tests/fp/unpacked_tests.cpp index 919f21bf2f..a4f10d1273 100644 --- a/src/dynarmic/tests/fp/unpacked_tests.cpp +++ b/src/dynarmic/tests/fp/unpacked_tests.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -12,7 +12,7 @@ #include #include "dynarmic/common/common_types.h" -#include "../rand_int.h" +#include "dynarmic/tests/rand_int.h" #include "dynarmic/common/fp/fpcr.h" #include "dynarmic/common/fp/fpsr.h" #include "dynarmic/common/fp/unpacked.h" diff --git a/src/dynarmic/tests/fuzz_util.cpp b/src/dynarmic/tests/fuzz_util.cpp index 351eb1e10f..05f0a9e865 100644 --- a/src/dynarmic/tests/fuzz_util.cpp +++ b/src/dynarmic/tests/fuzz_util.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -6,7 +6,7 @@ * SPDX-License-Identifier: 0BSD */ -#include "./fuzz_util.h" +#include "dynarmic/tests/fuzz_util.h" #include @@ -14,7 +14,7 @@ #include #include "dynarmic/common/assert.h" -#include "./rand_int.h" +#include "dynarmic/tests/rand_int.h" #include "dynarmic/common/fp/fpcr.h" #include "dynarmic/common/fp/rounding_mode.h" diff --git a/src/dynarmic/tests/native/preserve_xmm.cpp b/src/dynarmic/tests/native/preserve_xmm.cpp index 7421252063..6369e1a74d 100644 --- a/src/dynarmic/tests/native/preserve_xmm.cpp +++ b/src/dynarmic/tests/native/preserve_xmm.cpp @@ -1,12 +1,12 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later #include #include #include -#include "../A64/testenv.h" -#include "../native/testenv.h" +#include "dynarmic/tests/A64/testenv.h" +#include "dynarmic/tests/native/testenv.h" #include "dynarmic/common/fp/fpsr.h" #include "dynarmic/interface/exclusive_monitor.h" diff --git a/src/dynarmic/tests/test_generator.cpp b/src/dynarmic/tests/test_generator.cpp index 4435e762ae..33e41099ff 100644 --- a/src/dynarmic/tests/test_generator.cpp +++ b/src/dynarmic/tests/test_generator.cpp @@ -22,8 +22,8 @@ #include "./A32/testenv.h" #include "./A64/testenv.h" -#include "./fuzz_util.h" -#include "./rand_int.h" +#include "dynarmic/tests/fuzz_util.h" +#include "dynarmic/tests/rand_int.h" #include "dynarmic/common/fp/fpcr.h" #include "dynarmic/common/fp/fpsr.h" #include "dynarmic/common/llvm_disassemble.h" diff --git a/src/dynarmic/tests/unicorn_emu/a32_unicorn.cpp b/src/dynarmic/tests/unicorn_emu/a32_unicorn.cpp index 1a4f1845d5..66c1e7fd24 100644 --- a/src/dynarmic/tests/unicorn_emu/a32_unicorn.cpp +++ b/src/dynarmic/tests/unicorn_emu/a32_unicorn.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -6,22 +6,14 @@ * SPDX-License-Identifier: 0BSD */ -#include "./a32_unicorn.h" - #include - -#include "dynarmic/common/assert.h" +#include #include +#include "dynarmic/tests/unicorn_emu/a32_unicorn.h" +#include "dynarmic/common/assert.h" +#include "dynarmic/tests/A32/testenv.h" -#include "../A32/testenv.h" - -#define CHECKED(expr) \ - do { \ - if (auto cerr_ = (expr)) { \ - ASSERT(false && "Call " #expr " failed with error: {} ({})\n", static_cast(cerr_), \ - uc_strerror(cerr_)); \ - } \ - } while (0) +#define CHECKED(expr) do if ((expr)) ASSERT(false && "Call " #expr " failed with error\n"); while (0) constexpr u32 BEGIN_ADDRESS = 0; constexpr u32 END_ADDRESS = ~u32(0); diff --git a/src/dynarmic/tests/unicorn_emu/a32_unicorn.h b/src/dynarmic/tests/unicorn_emu/a32_unicorn.h index 79831b8111..d94724d9f2 100644 --- a/src/dynarmic/tests/unicorn_emu/a32_unicorn.h +++ b/src/dynarmic/tests/unicorn_emu/a32_unicorn.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -21,7 +21,7 @@ #include "dynarmic/common/common_types.h" -#include "../A32/testenv.h" +#include "dynarmic/tests/A32/testenv.h" namespace Unicorn::A32 { static constexpr size_t num_gprs = 16; diff --git a/src/dynarmic/tests/unicorn_emu/a64_unicorn.cpp b/src/dynarmic/tests/unicorn_emu/a64_unicorn.cpp index 3f13377f71..c8aa404199 100644 --- a/src/dynarmic/tests/unicorn_emu/a64_unicorn.cpp +++ b/src/dynarmic/tests/unicorn_emu/a64_unicorn.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -6,17 +6,11 @@ * SPDX-License-Identifier: 0BSD */ -#include "./a64_unicorn.h" - +#include +#include "dynarmic/tests/unicorn_emu/a64_unicorn.h" #include "dynarmic/common/assert.h" -#define CHECKED(expr) \ - do { \ - if (auto cerr_ = (expr)) { \ - ASSERT(false && "Call " #expr " failed with error: {} ({})\n", static_cast(cerr_), \ - uc_strerror(cerr_)); \ - } \ - } while (0) +#define CHECKED(expr) do if ((expr)) ASSERT(false && "Call " #expr " failed with error\n"); while (0) constexpr u64 BEGIN_ADDRESS = 0; constexpr u64 END_ADDRESS = ~u64(0); @@ -172,7 +166,7 @@ void A64Unicorn::DumpMemoryInformation() { void A64Unicorn::InterruptHook(uc_engine* uc, u32 int_number, void* user_data) { auto* this_ = static_cast(user_data); - u32 esr; + u32 esr = 0; //CHECKED(uc_reg_read(uc, UC_ARM64_REG_ESR_EL0, &esr)); auto ec = esr >> 26; diff --git a/src/dynarmic/tests/unicorn_emu/a64_unicorn.h b/src/dynarmic/tests/unicorn_emu/a64_unicorn.h index 54f09c3b28..1bc5b1cb8e 100644 --- a/src/dynarmic/tests/unicorn_emu/a64_unicorn.h +++ b/src/dynarmic/tests/unicorn_emu/a64_unicorn.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -21,7 +21,7 @@ #include "dynarmic/common/common_types.h" -#include "../A64/testenv.h" +#include "dynarmic/tests/A64/testenv.h" class A64Unicorn final { public: diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 3324682639..259e4801d3 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -44,7 +44,6 @@ add_library(video_core STATIC engines/sw_blitter/converter.h engines/const_buffer_info.h engines/draw_manager.cpp - engines/draw_manager.h engines/engine_interface.h engines/engine_upload.cpp engines/engine_upload.h diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 014b4a318e..83c94b2fc3 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -356,7 +356,7 @@ void BufferCache

::BindHostGeometryBuffers(bool is_indexed) { if (is_indexed) { BindHostIndexBuffer(); } else if constexpr (!HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) { - const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); + const auto& draw_state = maxwell3d->draw_manager.draw_state; if (draw_state.topology == Maxwell::PrimitiveTopology::Quads || draw_state.topology == Maxwell::PrimitiveTopology::QuadStrip) { runtime.BindQuadIndexBuffer(draw_state.topology, draw_state.vertex_buffer.first, @@ -740,30 +740,25 @@ void BufferCache

::BindHostIndexBuffer() { TouchBuffer(buffer, channel_state->index_buffer.buffer_id); const u32 offset = buffer.Offset(channel_state->index_buffer.device_addr); const u32 size = channel_state->index_buffer.size; - const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); - if (!draw_state.inline_index_draw_indexes.empty()) [[unlikely]] { + const auto& draw_state = maxwell3d->draw_manager.draw_state; + if (draw_state.inline_index_draw_indexes.empty()) { + SynchronizeBuffer(buffer, channel_state->index_buffer.device_addr, size); + } else { if constexpr (USE_MEMORY_MAPS_FOR_UPLOADS) { auto upload_staging = runtime.UploadStagingBuffer(size); - std::array copies{ - {BufferCopy{.src_offset = upload_staging.offset, .dst_offset = 0, .size = size}}}; - std::memcpy(upload_staging.mapped_span.data(), - draw_state.inline_index_draw_indexes.data(), size); + std::array copies{{BufferCopy{.src_offset = upload_staging.offset, .dst_offset = 0, .size = size}}}; + std::memcpy(upload_staging.mapped_span.data(), draw_state.inline_index_draw_indexes.data(), size); runtime.CopyBuffer(buffer, upload_staging.buffer, copies, true); } else { buffer.ImmediateUpload(0, draw_state.inline_index_draw_indexes); } - } else { - SynchronizeBuffer(buffer, channel_state->index_buffer.device_addr, size); } if constexpr (HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) { - const u32 new_offset = - offset + draw_state.index_buffer.first * draw_state.index_buffer.FormatSizeInBytes(); + const u32 new_offset = offset + draw_state.index_buffer.first * draw_state.index_buffer.FormatSizeInBytes(); runtime.BindIndexBuffer(buffer, new_offset, size); } else { buffer.MarkUsage(offset, size); - runtime.BindIndexBuffer(draw_state.topology, draw_state.index_buffer.format, - draw_state.index_buffer.first, draw_state.index_buffer.count, - buffer, offset, size); + runtime.BindIndexBuffer(draw_state.topology, draw_state.index_buffer.format, draw_state.index_buffer.first, draw_state.index_buffer.count, buffer, offset, size); } } @@ -945,10 +940,9 @@ void BufferCache

::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32 return alignment > 1 && (offset % alignment) != 0; } }(); - const bool use_fast_buffer = needs_alignment_stream || - (has_host_buffer && - size <= channel_state->uniform_buffer_skip_cache_size && - !memory_tracker.IsRegionGpuModified(device_addr, size)); + const bool use_fast_buffer = needs_alignment_stream + || (has_host_buffer && size <= channel_state->uniform_buffer_skip_cache_size + && !memory_tracker.IsRegionGpuModified(device_addr, size)); if (use_fast_buffer) { if constexpr (IS_OPENGL) { if (runtime.HasFastBufferSubData()) { @@ -1226,7 +1220,7 @@ template void BufferCache

::UpdateIndexBuffer() { // We have to check for the dirty flags and index count // The index count is currently changed without updating the dirty flags - const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); + const auto& draw_state = maxwell3d->draw_manager.draw_state; const auto& index_buffer_ref = draw_state.index_buffer; auto& flags = maxwell3d->dirty.flags; if (!flags[Dirty::IndexBuffer]) { diff --git a/src/video_core/buffer_cache/buffer_cache_base.h b/src/video_core/buffer_cache/buffer_cache_base.h index 08524bd854..473cc6842e 100644 --- a/src/video_core/buffer_cache/buffer_cache_base.h +++ b/src/video_core/buffer_cache/buffer_cache_base.h @@ -32,7 +32,7 @@ #include "video_core/control/channel_state_cache.h" #include "video_core/delayed_destruction_ring.h" #include "video_core/dirty_flags.h" -#include "video_core/engines/draw_manager.h" +#include "video_core/engines/maxwell_3d.h" #include "video_core/engines/kepler_compute.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/memory_manager.h" @@ -305,7 +305,7 @@ public: [[nodiscard]] bool IsRegionCpuModified(DAddr addr, size_t size); void SetDrawIndirect( - const Tegra::Engines::DrawManager::IndirectParams* current_draw_indirect_) { + const Tegra::Engines::Maxwell3D::DrawManager::IndirectParams* current_draw_indirect_) { current_draw_indirect = current_draw_indirect_; } @@ -480,7 +480,7 @@ private: #endif DelayedDestructionRing delayed_destruction_ring; - const Tegra::Engines::DrawManager::IndirectParams* current_draw_indirect{}; + const Tegra::Engines::Maxwell3D::DrawManager::IndirectParams* current_draw_indirect{}; u32 last_index_count = 0; diff --git a/src/video_core/engines/draw_manager.cpp b/src/video_core/engines/draw_manager.cpp index 971025cb55..079c7bdc09 100644 --- a/src/video_core/engines/draw_manager.cpp +++ b/src/video_core/engines/draw_manager.cpp @@ -1,23 +1,24 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "common/settings.h" #include "video_core/dirty_flags.h" -#include "video_core/engines/draw_manager.h" +#include "video_core/engines/maxwell_3d.h" #include "video_core/rasterizer_interface.h" namespace Tegra::Engines { -DrawManager::DrawManager(Maxwell3D* maxwell3d_) : maxwell3d(maxwell3d_) {} -void DrawManager::ProcessMethodCall(u32 method, u32 argument) { - const auto& regs{maxwell3d->regs}; +void Maxwell3D::DrawManager::ProcessMethodCall(Maxwell3D& maxwell3d, u32 method, u32 argument) { switch (method) { case MAXWELL3D_REG_INDEX(clear_surface): - return Clear(1); + return Clear(maxwell3d, 1); case MAXWELL3D_REG_INDEX(draw.begin): - return DrawBegin(); + return DrawBegin(maxwell3d); case MAXWELL3D_REG_INDEX(draw.end): - return DrawEnd(); + return DrawEnd(maxwell3d); case MAXWELL3D_REG_INDEX(vertex_buffer.first): case MAXWELL3D_REG_INDEX(vertex_buffer.count): case MAXWELL3D_REG_INDEX(index_buffer.first): @@ -33,33 +34,29 @@ void DrawManager::ProcessMethodCall(u32 method, u32 argument) { case MAXWELL3D_REG_INDEX(index_buffer32_first): case MAXWELL3D_REG_INDEX(index_buffer16_first): case MAXWELL3D_REG_INDEX(index_buffer8_first): - return DrawIndexSmall(argument); + return DrawIndexSmall(maxwell3d, argument); case MAXWELL3D_REG_INDEX(draw_inline_index): - SetInlineIndexBuffer(argument); + SetInlineIndexBuffer(maxwell3d, argument); break; case MAXWELL3D_REG_INDEX(inline_index_2x16.even): - SetInlineIndexBuffer(regs.inline_index_2x16.even); - SetInlineIndexBuffer(regs.inline_index_2x16.odd); + SetInlineIndexBuffer(maxwell3d, maxwell3d.regs.inline_index_2x16.even); + SetInlineIndexBuffer(maxwell3d, maxwell3d.regs.inline_index_2x16.odd); break; case MAXWELL3D_REG_INDEX(inline_index_4x8.index0): - SetInlineIndexBuffer(regs.inline_index_4x8.index0); - SetInlineIndexBuffer(regs.inline_index_4x8.index1); - SetInlineIndexBuffer(regs.inline_index_4x8.index2); - SetInlineIndexBuffer(regs.inline_index_4x8.index3); + SetInlineIndexBuffer(maxwell3d, maxwell3d.regs.inline_index_4x8.index0); + SetInlineIndexBuffer(maxwell3d, maxwell3d.regs.inline_index_4x8.index1); + SetInlineIndexBuffer(maxwell3d, maxwell3d.regs.inline_index_4x8.index2); + SetInlineIndexBuffer(maxwell3d, maxwell3d.regs.inline_index_4x8.index3); break; case MAXWELL3D_REG_INDEX(vertex_array_instance_first): - DrawArrayInstanced(regs.vertex_array_instance_first.topology.Value(), - regs.vertex_array_instance_first.start.Value(), - regs.vertex_array_instance_first.count.Value(), false); + DrawArrayInstanced(maxwell3d, maxwell3d.regs.vertex_array_instance_first.topology.Value(), maxwell3d.regs.vertex_array_instance_first.start.Value(), maxwell3d.regs.vertex_array_instance_first.count.Value(), false); break; case MAXWELL3D_REG_INDEX(vertex_array_instance_subsequent): { - DrawArrayInstanced(regs.vertex_array_instance_subsequent.topology.Value(), - regs.vertex_array_instance_subsequent.start.Value(), - regs.vertex_array_instance_subsequent.count.Value(), true); + DrawArrayInstanced(maxwell3d, maxwell3d.regs.vertex_array_instance_subsequent.topology.Value(), maxwell3d.regs.vertex_array_instance_subsequent.start.Value(), maxwell3d.regs.vertex_array_instance_subsequent.count.Value(), true); break; } case MAXWELL3D_REG_INDEX(draw_texture.src_y0): { - DrawTexture(); + DrawTexture(maxwell3d); break; } default: @@ -67,101 +64,87 @@ void DrawManager::ProcessMethodCall(u32 method, u32 argument) { } } -void DrawManager::Clear(u32 layer_count) { - if (maxwell3d->ShouldExecute()) { - maxwell3d->rasterizer->Clear(layer_count); +void Maxwell3D::DrawManager::Clear(Maxwell3D& maxwell3d, u32 layer_count) { + if (maxwell3d.ShouldExecute()) { + maxwell3d.rasterizer->Clear(layer_count); } } -void DrawManager::DrawDeferred() { +void Maxwell3D::DrawManager::DrawDeferred(Maxwell3D& maxwell3d) { if (draw_state.draw_mode != DrawMode::Instance || draw_state.instance_count == 0) { return; } - DrawEnd(draw_state.instance_count + 1, true); + DrawEnd(maxwell3d, draw_state.instance_count + 1, true); draw_state.instance_count = 0; } -void DrawManager::DrawArray(PrimitiveTopology topology, u32 vertex_first, u32 vertex_count, - u32 base_instance, u32 num_instances) { +void Maxwell3D::DrawManager::DrawArray(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology, u32 vertex_first, u32 vertex_count, u32 base_instance, u32 num_instances) { draw_state.topology = topology; draw_state.vertex_buffer.first = vertex_first; draw_state.vertex_buffer.count = vertex_count; draw_state.base_instance = base_instance; - ProcessDraw(false, num_instances); + ProcessDraw(maxwell3d, false, num_instances); } -void DrawManager::DrawArrayInstanced(PrimitiveTopology topology, u32 vertex_first, u32 vertex_count, - bool subsequent) { +void Maxwell3D::DrawManager::DrawArrayInstanced(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology, u32 vertex_first, u32 vertex_count, bool subsequent) { draw_state.topology = topology; draw_state.vertex_buffer.first = vertex_first; draw_state.vertex_buffer.count = vertex_count; - if (!subsequent) { draw_state.instance_count = 1; } - draw_state.base_instance = draw_state.instance_count - 1; draw_state.draw_mode = DrawMode::Instance; draw_state.instance_count++; - ProcessDraw(false, 1); + ProcessDraw(maxwell3d, false, 1); } -void DrawManager::DrawIndex(PrimitiveTopology topology, u32 index_first, u32 index_count, - u32 base_index, u32 base_instance, u32 num_instances) { - const auto& regs{maxwell3d->regs}; +void Maxwell3D::DrawManager::DrawIndex(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology, u32 index_first, u32 index_count, u32 base_index, u32 base_instance, u32 num_instances) { draw_state.topology = topology; - draw_state.index_buffer = regs.index_buffer; + draw_state.index_buffer = maxwell3d.regs.index_buffer; draw_state.index_buffer.first = index_first; draw_state.index_buffer.count = index_count; draw_state.base_index = base_index; draw_state.base_instance = base_instance; - ProcessDraw(true, num_instances); + ProcessDraw(maxwell3d, true, num_instances); } -void DrawManager::DrawArrayIndirect(PrimitiveTopology topology) { +void Maxwell3D::DrawManager::DrawArrayIndirect(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology) { draw_state.topology = topology; - - ProcessDrawIndirect(); + ProcessDrawIndirect(maxwell3d); } -void DrawManager::DrawIndexedIndirect(PrimitiveTopology topology, u32 index_first, - u32 index_count) { - const auto& regs{maxwell3d->regs}; +void Maxwell3D::DrawManager::DrawIndexedIndirect(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology, u32 index_first, u32 index_count) { draw_state.topology = topology; - draw_state.index_buffer = regs.index_buffer; + draw_state.index_buffer = maxwell3d.regs.index_buffer; draw_state.index_buffer.first = index_first; draw_state.index_buffer.count = index_count; - - ProcessDrawIndirect(); + ProcessDrawIndirect(maxwell3d); } -void DrawManager::SetInlineIndexBuffer(u32 index) { - draw_state.inline_index_draw_indexes.push_back(static_cast(index & 0x000000ff)); - draw_state.inline_index_draw_indexes.push_back(static_cast((index & 0x0000ff00) >> 8)); - draw_state.inline_index_draw_indexes.push_back(static_cast((index & 0x00ff0000) >> 16)); - draw_state.inline_index_draw_indexes.push_back(static_cast((index & 0xff000000) >> 24)); +void Maxwell3D::DrawManager::SetInlineIndexBuffer(Maxwell3D& maxwell3d, u32 index) { + draw_state.inline_index_draw_indexes.push_back(u8(index & 0x000000ff)); + draw_state.inline_index_draw_indexes.push_back(u8((index & 0x0000ff00) >> 8)); + draw_state.inline_index_draw_indexes.push_back(u8((index & 0x00ff0000) >> 16)); + draw_state.inline_index_draw_indexes.push_back(u8((index & 0xff000000) >> 24)); draw_state.draw_mode = DrawMode::InlineIndex; } -void DrawManager::DrawBegin() { - const auto& regs{maxwell3d->regs}; - auto reset_instance_count = regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First; - auto increment_instance_count = - regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent; +void Maxwell3D::DrawManager::DrawBegin(Maxwell3D& maxwell3d) { + auto reset_instance_count = maxwell3d.regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First; + auto increment_instance_count = maxwell3d.regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent; if (reset_instance_count) { - DrawDeferred(); + DrawDeferred(maxwell3d); draw_state.instance_count = 0; draw_state.draw_mode = DrawMode::General; } else if (increment_instance_count) { draw_state.instance_count++; draw_state.draw_mode = DrawMode::Instance; } - - draw_state.topology = regs.draw.topology; + draw_state.topology = maxwell3d.regs.draw.topology; } -void DrawManager::DrawEnd(u32 instance_count, bool force_draw) { - const auto& regs{maxwell3d->regs}; +void Maxwell3D::DrawManager::DrawEnd(Maxwell3D& maxwell3d, u32 instance_count, bool force_draw) { switch (draw_state.draw_mode) { case DrawMode::Instance: if (!force_draw) { @@ -169,119 +152,100 @@ void DrawManager::DrawEnd(u32 instance_count, bool force_draw) { } [[fallthrough]]; case DrawMode::General: - draw_state.base_instance = regs.global_base_instance_index; - draw_state.base_index = regs.global_base_vertex_index; + draw_state.base_instance = maxwell3d.regs.global_base_instance_index; + draw_state.base_index = maxwell3d.regs.global_base_vertex_index; if (draw_state.draw_indexed) { - draw_state.index_buffer = regs.index_buffer; - ProcessDraw(true, instance_count); + draw_state.index_buffer = maxwell3d.regs.index_buffer; + ProcessDraw(maxwell3d, true, instance_count); } else { - draw_state.vertex_buffer = regs.vertex_buffer; - ProcessDraw(false, instance_count); + draw_state.vertex_buffer = maxwell3d.regs.vertex_buffer; + ProcessDraw(maxwell3d, false, instance_count); } draw_state.draw_indexed = false; break; case DrawMode::InlineIndex: - draw_state.base_instance = regs.global_base_instance_index; - draw_state.base_index = regs.global_base_vertex_index; - draw_state.index_buffer = regs.index_buffer; - draw_state.index_buffer.count = - static_cast(draw_state.inline_index_draw_indexes.size() / 4); + draw_state.base_instance = maxwell3d.regs.global_base_instance_index; + draw_state.base_index = maxwell3d.regs.global_base_vertex_index; + draw_state.index_buffer = maxwell3d.regs.index_buffer; + draw_state.index_buffer.count = u32(draw_state.inline_index_draw_indexes.size() / 4); draw_state.index_buffer.format = Maxwell3D::Regs::IndexFormat::UnsignedInt; - maxwell3d->dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; - ProcessDraw(true, instance_count); + maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; + ProcessDraw(maxwell3d, true, instance_count); draw_state.inline_index_draw_indexes.clear(); break; } } -void DrawManager::DrawIndexSmall(u32 argument) { - const auto& regs{maxwell3d->regs}; - IndexBufferSmall index_small_params{argument}; - draw_state.base_instance = regs.global_base_instance_index; - draw_state.base_index = regs.global_base_vertex_index; - draw_state.index_buffer = regs.index_buffer; +void Maxwell3D::DrawManager::DrawIndexSmall(Maxwell3D& maxwell3d, u32 argument) { + Maxwell3D::Regs::IndexBufferSmall index_small_params{argument}; + draw_state.base_instance = maxwell3d.regs.global_base_instance_index; + draw_state.base_index = maxwell3d.regs.global_base_vertex_index; + draw_state.index_buffer = maxwell3d.regs.index_buffer; draw_state.index_buffer.first = index_small_params.first; draw_state.index_buffer.count = index_small_params.count; draw_state.topology = index_small_params.topology; - maxwell3d->dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; - ProcessDraw(true, 1); + maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; + ProcessDraw(maxwell3d, true, 1); } -void DrawManager::DrawTexture() { - const auto& regs{maxwell3d->regs}; - draw_texture_state.dst_x0 = static_cast(regs.draw_texture.dst_x0) / 4096.f; - draw_texture_state.dst_y0 = static_cast(regs.draw_texture.dst_y0) / 4096.f; - const auto dst_width = static_cast(regs.draw_texture.dst_width) / 4096.f; - const auto dst_height = static_cast(regs.draw_texture.dst_height) / 4096.f; - const bool lower_left{regs.window_origin.mode != - Maxwell3D::Regs::WindowOrigin::Mode::UpperLeft}; +void Maxwell3D::DrawManager::DrawTexture(Maxwell3D& maxwell3d) { + draw_texture_state.dst_x0 = f32(maxwell3d.regs.draw_texture.dst_x0) / 4096.f; + draw_texture_state.dst_y0 = f32(maxwell3d.regs.draw_texture.dst_y0) / 4096.f; + const auto dst_width = f32(maxwell3d.regs.draw_texture.dst_width) / 4096.f; + const auto dst_height = f32(maxwell3d.regs.draw_texture.dst_height) / 4096.f; + const bool lower_left{maxwell3d.regs.window_origin.mode != Maxwell3D::Regs::WindowOrigin::Mode::UpperLeft}; if (lower_left) { - draw_texture_state.dst_y0 = - static_cast(regs.surface_clip.height) - draw_texture_state.dst_y0; + draw_texture_state.dst_y0 = f32(maxwell3d.regs.surface_clip.height) - draw_texture_state.dst_y0; } draw_texture_state.dst_x1 = draw_texture_state.dst_x0 + dst_width; draw_texture_state.dst_y1 = draw_texture_state.dst_y0 + dst_height; - draw_texture_state.src_x0 = static_cast(regs.draw_texture.src_x0) / 4096.f; - draw_texture_state.src_y0 = static_cast(regs.draw_texture.src_y0) / 4096.f; - draw_texture_state.src_x1 = - (static_cast(regs.draw_texture.dx_du) / 4294967296.f) * dst_width + - draw_texture_state.src_x0; - draw_texture_state.src_y1 = - (static_cast(regs.draw_texture.dy_dv) / 4294967296.f) * dst_height + - draw_texture_state.src_y0; - draw_texture_state.src_sampler = regs.draw_texture.src_sampler; - draw_texture_state.src_texture = regs.draw_texture.src_texture; - maxwell3d->rasterizer->DrawTexture(); + draw_texture_state.src_x0 = f32(maxwell3d.regs.draw_texture.src_x0) / 4096.f; + draw_texture_state.src_y0 = f32(maxwell3d.regs.draw_texture.src_y0) / 4096.f; + draw_texture_state.src_x1 = (f32(maxwell3d.regs.draw_texture.dx_du) / 4294967296.f) * dst_width + draw_texture_state.src_x0; + draw_texture_state.src_y1 = (f32(maxwell3d.regs.draw_texture.dy_dv) / 4294967296.f) * dst_height + draw_texture_state.src_y0; + draw_texture_state.src_sampler = maxwell3d.regs.draw_texture.src_sampler; + draw_texture_state.src_texture = maxwell3d.regs.draw_texture.src_texture; + maxwell3d.rasterizer->DrawTexture(); } -void DrawManager::UpdateTopology() { - const auto& regs{maxwell3d->regs}; - switch (regs.primitive_topology_control) { - case PrimitiveTopologyControl::UseInBeginMethods: +void Maxwell3D::DrawManager::UpdateTopology(Maxwell3D& maxwell3d) { + switch (maxwell3d.regs.primitive_topology_control) { + case Maxwell3D::Regs::PrimitiveTopologyControl::UseInBeginMethods: break; - case PrimitiveTopologyControl::UseSeparateState: - switch (regs.topology_override) { - case PrimitiveTopologyOverride::None: + case Maxwell3D::Regs::PrimitiveTopologyControl::UseSeparateState: + switch (maxwell3d.regs.topology_override) { + case Maxwell3D::Regs::PrimitiveTopologyOverride::None: break; - case PrimitiveTopologyOverride::Points: - draw_state.topology = PrimitiveTopology::Points; + case Maxwell3D::Regs::PrimitiveTopologyOverride::Points: + draw_state.topology = Maxwell3D::Regs::PrimitiveTopology::Points; break; - case PrimitiveTopologyOverride::Lines: - draw_state.topology = PrimitiveTopology::Lines; + case Maxwell3D::Regs::PrimitiveTopologyOverride::Lines: + draw_state.topology = Maxwell3D::Regs::PrimitiveTopology::Lines; break; - case PrimitiveTopologyOverride::LineStrip: - draw_state.topology = PrimitiveTopology::LineStrip; + case Maxwell3D::Regs::PrimitiveTopologyOverride::LineStrip: + draw_state.topology = Maxwell3D::Regs::PrimitiveTopology::LineStrip; break; default: - draw_state.topology = static_cast(regs.topology_override); + draw_state.topology = Maxwell3D::Regs::PrimitiveTopology(maxwell3d.regs.topology_override); break; } break; } } -void DrawManager::ProcessDraw(bool draw_indexed, u32 instance_count) { - LOG_TRACE(HW_GPU, "called, topology={}, count={}", draw_state.topology, - draw_indexed ? draw_state.index_buffer.count : draw_state.vertex_buffer.count); - - UpdateTopology(); - - if (maxwell3d->ShouldExecute()) { - maxwell3d->rasterizer->Draw(draw_indexed, instance_count); +void Maxwell3D::DrawManager::ProcessDraw(Maxwell3D& maxwell3d, bool draw_indexed, u32 instance_count) { + LOG_TRACE(HW_GPU, "called, topology={}, count={}", draw_state.topology, draw_indexed ? draw_state.index_buffer.count : draw_state.vertex_buffer.count); + UpdateTopology(maxwell3d); + if (maxwell3d.ShouldExecute()) { + maxwell3d.rasterizer->Draw(draw_indexed, instance_count); } } -void DrawManager::ProcessDrawIndirect() { - LOG_TRACE( - HW_GPU, - "called, topology={}, is_indexed={}, includes_count={}, buffer_size={}, max_draw_count={}", - draw_state.topology, indirect_state.is_indexed, indirect_state.include_count, - indirect_state.buffer_size, indirect_state.max_draw_counts); - - UpdateTopology(); - - if (maxwell3d->ShouldExecute()) { - maxwell3d->rasterizer->DrawIndirect(); +void Maxwell3D::DrawManager::ProcessDrawIndirect(Maxwell3D& maxwell3d) { + LOG_TRACE(HW_GPU, "called, topology={}, is_indexed={}, includes_count={}, buffer_size={}, max_draw_count={}", draw_state.topology, indirect_state.is_indexed, indirect_state.include_count, indirect_state.buffer_size, indirect_state.max_draw_counts); + UpdateTopology(maxwell3d); + if (maxwell3d.ShouldExecute()) { + maxwell3d.rasterizer->DrawIndirect(); } } } // namespace Tegra::Engines diff --git a/src/video_core/engines/draw_manager.h b/src/video_core/engines/draw_manager.h deleted file mode 100644 index cfc8127fc6..0000000000 --- a/src/video_core/engines/draw_manager.h +++ /dev/null @@ -1,117 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once -#include "common/common_types.h" -#include "video_core/engines/maxwell_3d.h" - -namespace VideoCore { -class RasterizerInterface; -} - -namespace Tegra::Engines { -using PrimitiveTopologyControl = Maxwell3D::Regs::PrimitiveTopologyControl; -using PrimitiveTopology = Maxwell3D::Regs::PrimitiveTopology; -using PrimitiveTopologyOverride = Maxwell3D::Regs::PrimitiveTopologyOverride; -using IndexBuffer = Maxwell3D::Regs::IndexBuffer; -using VertexBuffer = Maxwell3D::Regs::VertexBuffer; -using IndexBufferSmall = Maxwell3D::Regs::IndexBufferSmall; - -class DrawManager { -public: - enum class DrawMode : u32 { General = 0, Instance, InlineIndex }; - struct State { - PrimitiveTopology topology{}; - DrawMode draw_mode{}; - bool draw_indexed{}; - u32 base_index{}; - VertexBuffer vertex_buffer; - IndexBuffer index_buffer; - u32 base_instance{}; - u32 instance_count{}; - std::vector inline_index_draw_indexes; - }; - - struct DrawTextureState { - f32 dst_x0; - f32 dst_y0; - f32 dst_x1; - f32 dst_y1; - f32 src_x0; - f32 src_y0; - f32 src_x1; - f32 src_y1; - u32 src_sampler; - u32 src_texture; - }; - - struct IndirectParams { - bool is_byte_count; - bool is_indexed; - bool include_count; - GPUVAddr count_start_address; - GPUVAddr indirect_start_address; - size_t buffer_size; - size_t max_draw_counts; - size_t stride; - }; - - explicit DrawManager(Maxwell3D* maxwell_3d); - - void ProcessMethodCall(u32 method, u32 argument); - - void Clear(u32 layer_count); - - void DrawDeferred(); - - void DrawArray(PrimitiveTopology topology, u32 vertex_first, u32 vertex_count, - u32 base_instance, u32 num_instances); - void DrawArrayInstanced(PrimitiveTopology topology, u32 vertex_first, u32 vertex_count, - bool subsequent); - - void DrawIndex(PrimitiveTopology topology, u32 index_first, u32 index_count, u32 base_index, - u32 base_instance, u32 num_instances); - - void DrawArrayIndirect(PrimitiveTopology topology); - - void DrawIndexedIndirect(PrimitiveTopology topology, u32 index_first, u32 index_count); - - const State& GetDrawState() const { - return draw_state; - } - - const DrawTextureState& GetDrawTextureState() const { - return draw_texture_state; - } - - IndirectParams& GetIndirectParams() { - return indirect_state; - } - - const IndirectParams& GetIndirectParams() const { - return indirect_state; - } - -private: - void SetInlineIndexBuffer(u32 index); - - void DrawBegin(); - - void DrawEnd(u32 instance_count = 1, bool force_draw = false); - - void DrawIndexSmall(u32 argument); - - void DrawTexture(); - - void UpdateTopology(); - - void ProcessDraw(bool draw_indexed, u32 instance_count); - - void ProcessDrawIndirect(); - - Maxwell3D* maxwell3d{}; - State draw_state{}; - DrawTextureState draw_texture_state{}; - IndirectParams indirect_state{}; -}; -} // namespace Tegra::Engines diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 6d9ebd6296..9aaa99f7ff 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -13,7 +13,7 @@ #include "core/core.h" #include "core/core_timing.h" #include "video_core/dirty_flags.h" -#include "video_core/engines/draw_manager.h" +#include "video_core/engines/maxwell_3d.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/gpu.h" #include "video_core/memory_manager.h" @@ -26,7 +26,8 @@ namespace Tegra::Engines { constexpr u32 MacroRegistersStart = 0xE00; Maxwell3D::Maxwell3D(Core::System& system_, MemoryManager& memory_manager_) - : draw_manager{std::make_unique(this)}, system{system_} + : draw_manager() + , system{system_} , memory_manager{memory_manager_} #ifdef ARCHITECTURE_x86_64 , macro_engine(bool(Settings::values.disable_macro_jit)) @@ -373,8 +374,7 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume case MAXWELL3D_REG_INDEX(sync_info): return ProcessSyncPoint(); case MAXWELL3D_REG_INDEX(launch_dma): - return upload_state.ProcessExec(regs.launch_dma.memory_layout.Value() == - Regs::LaunchDMA::Layout::Pitch); + return upload_state.ProcessExec(regs.launch_dma.memory_layout.Value() == Regs::LaunchDMA::Layout::Pitch); case MAXWELL3D_REG_INDEX(inline_data): upload_state.ProcessData(argument, is_last_call); return; @@ -386,7 +386,7 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume case MAXWELL3D_REG_INDEX(tiled_cache_barrier): return rasterizer->TiledCacheBarrier(); default: - draw_manager->ProcessMethodCall(method, argument); + draw_manager.ProcessMethodCall(*this, method, argument); break; } } @@ -401,8 +401,7 @@ void Maxwell3D::CallMacroMethod(u32 method, const std::vector& parameters) // Execute the current macro. macro_engine.Execute(*this, macro_positions[entry], parameters); - - draw_manager->DrawDeferred(); + draw_manager.DrawDeferred(*this); } void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) { diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index b73082b7ef..3ac79e0eb8 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -25,6 +25,7 @@ #include "video_core/gpu.h" #include "video_core/macro.h" #include "video_core/textures/texture.h" +#include "video_core/engines/maxwell_3d.h" namespace Core { class System; @@ -40,8 +41,6 @@ class RasterizerInterface; namespace Tegra::Engines { -class DrawManager; - /** * This Engine is known as GF100_3D. Documentation can be found in: * https://github.com/NVIDIA/open-gpu-doc/blob/master/classes/3d/clb197.h @@ -543,7 +542,7 @@ public: } GPUVAddr StorageLimitAddress() const { return (GPUVAddr{storage_limit_address_high} << 32) | - GPUVAddr{storage_limit_address_low}; + GPUVAddr{storage_limit_address_low}; } }; @@ -819,7 +818,7 @@ public: u32 Map(std::size_t index) const { const std::array maps{target0, target1, target2, target3, - target4, target5, target6, target7}; + target4, target5, target6, target7}; ASSERT(index < maps.size()); return maps[index]; } @@ -1831,7 +1830,7 @@ public: bool AnyEnabled() const { return output0_enable || output1_enable || output2_enable || output3_enable || - output4_enable || output5_enable || output6_enable || output7_enable; + output4_enable || output5_enable || output6_enable || output7_enable; } }; @@ -1870,7 +1869,7 @@ public: bool AnyEnabled() const { return plane0 || plane1 || plane2 || plane3 || plane4 || plane5 || plane6 || - plane7; + plane7; } }; @@ -3023,8 +3022,7 @@ public: u32 bindless_texture_const_buffer_slot; ///< 0x2608 u32 trap_handler; ///< 0x260C INSERT_PADDING_BYTES_NOINIT(0x1F0); - std::array, NumTransformFeedbackBuffers> - stream_out_layout; ///< 0x2800 + std::array, NumTransformFeedbackBuffers> stream_out_layout; ///< 0x2800 INSERT_PADDING_BYTES_NOINIT(0x93C); ShaderPerformance shader_performance; ///< 0x333C INSERT_PADDING_BYTES_NOINIT(0x18); @@ -3035,6 +3033,62 @@ public: }; // clang-format on + struct DrawManager { + enum class DrawMode : u32 { General = 0, Instance, InlineIndex }; + struct State { + Maxwell3D::Regs::PrimitiveTopology topology{}; + DrawMode draw_mode{}; + bool draw_indexed{}; + u32 base_index{}; + Maxwell3D::Regs::VertexBuffer vertex_buffer; + Maxwell3D::Regs::IndexBuffer index_buffer; + u32 base_instance{}; + u32 instance_count{}; + std::vector inline_index_draw_indexes; + }; + struct DrawTextureState { + f32 dst_x0; + f32 dst_y0; + f32 dst_x1; + f32 dst_y1; + f32 src_x0; + f32 src_y0; + f32 src_x1; + f32 src_y1; + u32 src_sampler; + u32 src_texture; + }; + struct IndirectParams { + bool is_byte_count; + bool is_indexed; + bool include_count; + GPUVAddr count_start_address; + GPUVAddr indirect_start_address; + size_t buffer_size; + size_t max_draw_counts; + size_t stride; + }; + void ProcessMethodCall(Maxwell3D& maxwell3d, u32 method, u32 argument); + void Clear(Maxwell3D& maxwell3d, u32 layer_count); + void DrawDeferred(Maxwell3D& maxwell3d); + void DrawArray(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology, u32 vertex_first, u32 vertex_count, u32 base_instance, u32 num_instances); + void DrawArrayInstanced(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology, u32 vertex_first, u32 vertex_count, bool subsequent); + void DrawIndex(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology, u32 index_first, u32 index_count, u32 base_index, u32 base_instance, u32 num_instances); + void DrawArrayIndirect(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology); + void DrawIndexedIndirect(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology, u32 index_first, u32 index_count); + void SetInlineIndexBuffer(Maxwell3D& maxwell3d, u32 index); + void DrawBegin(Maxwell3D& maxwell3d); + void DrawEnd(Maxwell3D& maxwell3d, u32 instance_count = 1, bool force_draw = false); + void DrawIndexSmall(Maxwell3D& maxwell3d, u32 argument); + void DrawTexture(Maxwell3D& maxwell3d); + void UpdateTopology(Maxwell3D& maxwell3d); + void ProcessDraw(Maxwell3D& maxwell3d, bool draw_indexed, u32 instance_count); + void ProcessDrawIndirect(Maxwell3D& maxwell3d); + State draw_state{}; + DrawTextureState draw_texture_state{}; + IndirectParams indirect_state{}; + }; + Regs regs{}; /// Store temporary hw register values, used by some calls to restore state after a operation @@ -3102,8 +3156,7 @@ public: Tables tables{}; } dirty; - std::unique_ptr draw_manager; - friend class DrawManager; + DrawManager draw_manager; GPUVAddr GetMacroAddress(size_t index) const { return macro_addresses[index]; diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp index 8d8d857a02..f7cd27b0d3 100644 --- a/src/video_core/gpu_thread.cpp +++ b/src/video_core/gpu_thread.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project @@ -63,9 +63,7 @@ ThreadManager::ThreadManager(Core::System& system_, bool is_async_) ThreadManager::~ThreadManager() = default; -void ThreadManager::StartThread(VideoCore::RendererBase& renderer, - Core::Frontend::GraphicsContext& context, - Tegra::Control::Scheduler& scheduler) { +void ThreadManager::StartThread(VideoCore::RendererBase& renderer, Core::Frontend::GraphicsContext& context, Tegra::Control::Scheduler& scheduler) { rasterizer = renderer.ReadRasterizer(); thread = std::jthread(RunThread, std::ref(system), std::ref(renderer), std::ref(context), std::ref(scheduler), std::ref(state)); diff --git a/src/video_core/macro.cpp b/src/video_core/macro.cpp index 66cea5afbd..cbd21a0743 100644 --- a/src/video_core/macro.cpp +++ b/src/video_core/macro.cpp @@ -31,7 +31,7 @@ #include "common/settings.h" #include "common/container_hash.h" #include "video_core/engines/maxwell_3d.h" -#include "video_core/engines/draw_manager.h" +#include "video_core/engines/maxwell_3d.h" #include "video_core/dirty_flags.h" #include "video_core/rasterizer_interface.h" #include "video_core/macro.h" @@ -83,7 +83,7 @@ void HLE_DrawArraysIndirect::Execute(Engines::Maxwell3D& maxwell3d, std::spanGetIndirectParams(); + auto& params = maxwell3d.draw_manager.indirect_state; params.is_byte_count = false; params.is_indexed = false; params.include_count = false; @@ -98,7 +98,7 @@ void HLE_DrawArraysIndirect::Execute(Engines::Maxwell3D& maxwell3d, std::spanDrawArrayIndirect(topology); + maxwell3d.draw_manager.DrawArrayIndirect(maxwell3d, topology); if (extended) { maxwell3d.engine_state = Maxwell3D::EngineHint::None; @@ -127,7 +127,7 @@ void HLE_DrawArraysIndirect::Fallback(Engines::Maxwell3D& maxwell3d, std::spanDrawArray(topology, vertex_first, vertex_count, base_instance, instance_count); + maxwell3d.draw_manager.DrawArray(maxwell3d, topology, vertex_first, vertex_count, base_instance, instance_count); if (extended) { maxwell3d.regs.global_base_instance_index = 0; maxwell3d.engine_state = Maxwell3D::EngineHint::None; @@ -154,7 +154,7 @@ void HLE_DrawIndexedIndirect::Execute(Engines::Maxwell3D& maxwell3d, std::spanGetIndirectParams(); + auto& params = maxwell3d.draw_manager.indirect_state; params.is_byte_count = false; params.is_indexed = true; params.include_count = false; @@ -164,7 +164,7 @@ void HLE_DrawIndexedIndirect::Execute(Engines::Maxwell3D& maxwell3d, std::spanDrawIndexedIndirect(topology, 0, estimate); + maxwell3d.draw_manager.DrawIndexedIndirect(maxwell3d, topology, 0, estimate); maxwell3d.regs.vertex_id_base = 0x0; maxwell3d.regs.global_base_vertex_index = 0x0; maxwell3d.regs.global_base_instance_index = 0x0; @@ -187,7 +187,7 @@ void HLE_DrawIndexedIndirect::Fallback(Engines::Maxwell3D& maxwell3d, std::span< maxwell3d.SetHLEReplacementAttributeType(0, 0x640, Maxwell3D::HLEReplacementAttributeType::BaseVertex); maxwell3d.SetHLEReplacementAttributeType(0, 0x644, Maxwell3D::HLEReplacementAttributeType::BaseInstance); } - maxwell3d.draw_manager->DrawIndex(Tegra::Maxwell3D::Regs::PrimitiveTopology(parameters[0]), parameters[3], parameters[1], element_base, base_instance, instance_count); + maxwell3d.draw_manager.DrawIndex(maxwell3d, Tegra::Maxwell3D::Regs::PrimitiveTopology(parameters[0]), parameters[3], parameters[1], element_base, base_instance, instance_count); maxwell3d.regs.vertex_id_base = 0x0; maxwell3d.regs.global_base_vertex_index = 0x0; maxwell3d.regs.global_base_instance_index = 0x0; @@ -206,7 +206,7 @@ void HLE_MultiLayerClear::Execute(Engines::Maxwell3D& maxwell3d, std::spanClear(num_layers); + maxwell3d.draw_manager.Clear(maxwell3d, num_layers); } void HLE_MultiDrawIndexedIndirectCount::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { const auto topology = Maxwell3D::Regs::PrimitiveTopology(parameters[2]); @@ -230,7 +230,7 @@ void HLE_MultiDrawIndexedIndirectCount::Execute(Engines::Maxwell3D& maxwell3d, s const std::size_t draw_count = end_indirect - start_indirect; const u32 estimate = static_cast(maxwell3d.EstimateIndexBufferSize()); maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; - auto& params = maxwell3d.draw_manager->GetIndirectParams(); + auto& params = maxwell3d.draw_manager.indirect_state; params.is_byte_count = false; params.is_indexed = true; params.include_count = true; @@ -244,7 +244,7 @@ void HLE_MultiDrawIndexedIndirectCount::Execute(Engines::Maxwell3D& maxwell3d, s maxwell3d.SetHLEReplacementAttributeType(0, 0x640, Maxwell3D::HLEReplacementAttributeType::BaseVertex); maxwell3d.SetHLEReplacementAttributeType(0, 0x644, Maxwell3D::HLEReplacementAttributeType::BaseInstance); maxwell3d.SetHLEReplacementAttributeType(0, 0x648, Maxwell3D::HLEReplacementAttributeType::DrawID); - maxwell3d.draw_manager->DrawIndexedIndirect(topology, 0, estimate); + maxwell3d.draw_manager.DrawIndexedIndirect(maxwell3d, topology, 0, estimate); maxwell3d.engine_state = Maxwell3D::EngineHint::None; maxwell3d.replace_table.clear(); } @@ -280,7 +280,7 @@ void HLE_MultiDrawIndexedIndirectCount::Fallback(Engines::Maxwell3D& maxwell3d, maxwell3d.CallMethod(0x8e3, 0x648, true); maxwell3d.CallMethod(0x8e4, static_cast(index), true); maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; - maxwell3d.draw_manager->DrawIndex(topology, parameters[base + 2], parameters[base], base_vertex, base_instance, parameters[base + 1]); + maxwell3d.draw_manager.DrawIndex(maxwell3d, topology, parameters[base + 2], parameters[base], base_vertex, base_instance, parameters[base + 1]); } } void HLE_DrawIndirectByteCount::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { @@ -290,7 +290,7 @@ void HLE_DrawIndirectByteCount::Execute(Engines::Maxwell3D& maxwell3d, std::span Fallback(maxwell3d, parameters); return; } - auto& params = maxwell3d.draw_manager->GetIndirectParams(); + auto& params = maxwell3d.draw_manager.indirect_state; params.is_byte_count = true; params.is_indexed = false; params.include_count = false; @@ -302,18 +302,14 @@ void HLE_DrawIndirectByteCount::Execute(Engines::Maxwell3D& maxwell3d, std::span maxwell3d.regs.draw.begin = parameters[0]; maxwell3d.regs.draw_auto_stride = parameters[1]; maxwell3d.regs.draw_auto_byte_count = parameters[2]; - maxwell3d.draw_manager->DrawArrayIndirect(topology); + maxwell3d.draw_manager.DrawArrayIndirect(maxwell3d, topology); } void HLE_DrawIndirectByteCount::Fallback(Engines::Maxwell3D& maxwell3d, std::span parameters) { maxwell3d.RefreshParameters(); - maxwell3d.regs.draw.begin = parameters[0]; maxwell3d.regs.draw_auto_stride = parameters[1]; maxwell3d.regs.draw_auto_byte_count = parameters[2]; - - maxwell3d.draw_manager->DrawArray( - maxwell3d.regs.draw.topology, 0, - maxwell3d.regs.draw_auto_byte_count / maxwell3d.regs.draw_auto_stride, 0, 1); + maxwell3d.draw_manager.DrawArray(maxwell3d, maxwell3d.regs.draw.topology, 0, maxwell3d.regs.draw_auto_byte_count / maxwell3d.regs.draw_auto_stride, 0, 1); } void HLE_C713C83D8F63CCF3::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { maxwell3d.RefreshParameters(); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index e268c4d2c6..3ce367e0d3 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -245,7 +245,7 @@ void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) { SyncState(); - const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); + const auto& draw_state = maxwell3d->draw_manager.draw_state; const GLenum primitive_mode = MaxwellToGL::PrimitiveTopology(draw_state.topology); BeginTransformFeedback(pipeline, primitive_mode); @@ -260,12 +260,12 @@ void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) { void RasterizerOpenGL::Draw(bool is_indexed, u32 instance_count) { PrepareDraw(is_indexed, [this, is_indexed, instance_count](GLenum primitive_mode) { - const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); - const GLuint base_instance = static_cast(draw_state.base_instance); - const GLsizei num_instances = static_cast(instance_count); + const auto& draw_state = maxwell3d->draw_manager.draw_state; + const GLuint base_instance = GLuint(draw_state.base_instance); + const GLsizei num_instances = GLsizei(instance_count); if (is_indexed) { - const GLint base_vertex = static_cast(draw_state.base_index); - const GLsizei num_vertices = static_cast(draw_state.index_buffer.count); + const GLint base_vertex = GLint(draw_state.base_index); + const GLsizei num_vertices = GLsizei(draw_state.index_buffer.count); const GLvoid* const offset = buffer_cache_runtime.IndexOffset(); const GLenum format = MaxwellToGL::IndexFormat(draw_state.index_buffer.format); if (num_instances == 1 && base_instance == 0 && base_vertex == 0) { @@ -302,7 +302,7 @@ void RasterizerOpenGL::Draw(bool is_indexed, u32 instance_count) { } void RasterizerOpenGL::DrawIndirect() { - const auto& params = maxwell3d->draw_manager->GetIndirectParams(); + const auto& params = maxwell3d->draw_manager.indirect_state; buffer_cache.SetDrawIndirect(¶ms); PrepareDraw(params.is_indexed, [this, ¶ms](GLenum primitive_mode) { if (params.is_byte_count) { @@ -358,12 +358,12 @@ void RasterizerOpenGL::DrawTexture() { SyncState(); - const auto& draw_texture_state = maxwell3d->draw_manager->GetDrawTextureState(); + const auto& draw_texture_state = maxwell3d->draw_manager.draw_texture_state; const auto& sampler = texture_cache.GetGraphicsSampler(draw_texture_state.src_sampler); const auto& texture = texture_cache.GetImageView(draw_texture_state.src_texture); const auto Scale = [&](auto dim) -> s32 { - return Settings::values.resolution_info.ScaleUp(static_cast(dim)); + return Settings::values.resolution_info.ScaleUp(s32(dim)); }; Region2D dst_region = { diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index aac7732005..18df857bc2 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -25,7 +25,7 @@ #include "shader_recompiler/frontend/maxwell/control_flow.h" #include "shader_recompiler/frontend/maxwell/translate_program.h" #include "shader_recompiler/profile.h" -#include "video_core/engines/draw_manager.h" +#include "video_core/engines/maxwell_3d.h" #include "video_core/engines/kepler_compute.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/memory_manager.h" @@ -362,7 +362,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(maxwell3d->draw_manager->GetDrawState().topology); + graphics_key.gs_input_topology.Assign(maxwell3d->draw_manager.draw_state.topology); 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( @@ -402,7 +402,7 @@ GraphicsPipeline* ShaderCache::BuiltPipeline(GraphicsPipeline* pipeline) const n // If games are using a small index count, we can assume these are full screen quads. // Usually these shaders are only used once for building textures so we can assume they // can't be built async - const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); + const auto& draw_state = maxwell3d->draw_manager.draw_state; if (draw_state.index_buffer.count <= 6 || draw_state.vertex_buffer.count <= 6) { return pipeline; } diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp index 06cbd9e6da..8e95b7ad53 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project @@ -12,7 +12,7 @@ #include "common/cityhash.h" #include "common/common_types.h" #include "common/settings.h" -#include "video_core/engines/draw_manager.h" +#include "video_core/engines/maxwell_3d.h" #include "video_core/renderer_vulkan/fixed_pipeline_state.h" #include "video_core/renderer_vulkan/vk_state_tracker.h" @@ -54,7 +54,7 @@ void RefreshXfbState(VideoCommon::TransformFeedbackState& state, const Maxwell& void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFeatures& features) { const Maxwell& regs = maxwell3d.regs; - const auto topology_ = maxwell3d.draw_manager->GetDrawState().topology; + const auto topology_ = maxwell3d.draw_manager.draw_state.topology; raw1 = 0; extended_dynamic_state.Assign(features.has_extended_dynamic_state ? 1 : 0); diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 77a4e8616a..c73ccf8436 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -675,7 +675,7 @@ GraphicsPipeline* PipelineCache::BuiltPipeline(GraphicsPipeline* pipeline) const // If games are using a small index count, we can assume these are full screen quads. // Usually these shaders are only used once for building textures so we can assume they // can't be built async - const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); + const auto& draw_state = maxwell3d->draw_manager.draw_state; if (draw_state.index_buffer.count <= 6 || draw_state.vertex_buffer.count <= 6) { return pipeline; } diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp index 8518d89eee..94cec29ca7 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp @@ -16,7 +16,7 @@ #include "video_core/renderer_vulkan/vk_texture_cache.h" #include "common/bit_util.h" #include "common/common_types.h" -#include "video_core/engines/draw_manager.h" +#include "video_core/engines/maxwell_3d.h" #include "video_core/host1x/gpu_device_memory_manager.h" #include "video_core/query_cache/query_cache.h" #include "video_core/rasterizer_interface.h" @@ -902,7 +902,7 @@ private: streams_mask = 0; // reset previously recorded streams runtime.View3DRegs([this](Maxwell3D& maxwell3d) { buffers_count = 0; - out_topology = maxwell3d.draw_manager->GetDrawState().topology; + out_topology = maxwell3d.draw_manager.draw_state.topology; for (size_t i = 0; i < Maxwell3D::Regs::NumTransformFeedbackBuffers; i++) { const auto& tf = maxwell3d.regs.transform_feedback; if (tf.buffers[i].enable == 0) { diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index f867980a6f..efe6691c92 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -20,7 +20,7 @@ #include "video_core/buffer_cache/buffer_cache.h" #include "video_core/gpu_logging/gpu_logging.h" #include "video_core/control/channel_state.h" -#include "video_core/engines/draw_manager.h" +#include "video_core/engines/maxwell_3d.h" #include "video_core/engines/kepler_compute.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/host1x/gpu_device_memory_manager.h" @@ -46,7 +46,6 @@ namespace Vulkan { using Maxwell = Tegra::Engines::Maxwell3D::Regs; -using MaxwellDrawState = Tegra::Engines::DrawManager::State; using VideoCommon::ImageViewId; using VideoCommon::ImageViewType; @@ -151,7 +150,7 @@ VkRect2D GetScissorState(const Maxwell& regs, size_t index, u32 up_scale = 1, u3 return scissor; } -DrawParams MakeDrawParams(const MaxwellDrawState& draw_state, u32 num_instances, bool is_indexed) { +DrawParams MakeDrawParams(const Tegra::Engines::Maxwell3D::DrawManager::State& draw_state, u32 num_instances, bool is_indexed) { DrawParams params{ .base_instance = draw_state.base_instance, .num_instances = num_instances, @@ -231,15 +230,13 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) { UpdateDynamicStates(); HandleTransformFeedback(); - query_cache.CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, - maxwell3d->regs.zpass_pixel_count_enable); - + query_cache.CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, maxwell3d->regs.zpass_pixel_count_enable); draw_func(); } void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) { PrepareDraw(is_indexed, [this, is_indexed, instance_count] { - const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); + const auto& draw_state = maxwell3d->draw_manager.draw_state; const u32 num_instances{instance_count}; const DrawParams draw_params{MakeDrawParams(draw_state, num_instances, is_indexed)}; @@ -298,7 +295,7 @@ void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) { } void RasterizerVulkan::DrawIndirect() { - const auto& params = maxwell3d->draw_manager->GetIndirectParams(); + const auto& params = maxwell3d->draw_manager.indirect_state; buffer_cache.SetDrawIndirect(¶ms); PrepareDraw(params.is_indexed, [this, ¶ms] { const auto indirect_buffer = buffer_cache.GetDrawIndirectBuffer(); @@ -368,9 +365,8 @@ void RasterizerVulkan::DrawTexture() { UpdateDynamicStates(); - query_cache.CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, - maxwell3d->regs.zpass_pixel_count_enable); - const auto& draw_texture_state = maxwell3d->draw_manager->GetDrawTextureState(); + query_cache.CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, maxwell3d->regs.zpass_pixel_count_enable); + const auto& draw_texture_state = maxwell3d->draw_manager.draw_texture_state; const auto& sampler = texture_cache.GetGraphicsSampler(draw_texture_state.src_sampler); const auto& texture = texture_cache.GetImageView(draw_texture_state.src_texture); const auto* framebuffer = texture_cache.GetFramebuffer(); @@ -1530,10 +1526,9 @@ void RasterizerVulkan::UpdateDepthBiasEnable(Tegra::Engines::Maxwell3D::Regs& re regs.polygon_offset_line_enable, regs.polygon_offset_fill_enable, }; - const u32 topology_index = static_cast(maxwell3d->draw_manager->GetDrawState().topology); + const u32 topology_index = u32(maxwell3d->draw_manager.draw_state.topology); const u32 enable = enabled_lut[POLYGON_OFFSET_ENABLE_LUT[topology_index]]; - scheduler.Record( - [enable](vk::CommandBuffer cmdbuf) { cmdbuf.SetDepthBiasEnableEXT(enable != 0); }); + scheduler.Record([enable](vk::CommandBuffer cmdbuf) { cmdbuf.SetDepthBiasEnableEXT(enable != 0); }); } void RasterizerVulkan::UpdateLogicOpEnable(Tegra::Engines::Maxwell3D::Regs& regs) { diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index 5d55cf551b..0e4c274d94 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp @@ -9,6 +9,10 @@ #include #include +#ifdef __ANDROID__ +#include +#endif + #include "common/logging.h" #include "common/settings.h" #include "common/settings_enums.h" @@ -170,6 +174,7 @@ bool Swapchain::AcquireNextImage() { break; } + const auto wait_with_frame_pacing = [this] { switch (Settings::values.frame_pacing_mode.GetValue()) { case Settings::FramePacingMode::Target_Auto: scheduler.Wait(resource_ticks[image_index]); @@ -187,6 +192,17 @@ bool Swapchain::AcquireNextImage() { scheduler.Wait(resource_ticks[image_index], 120.0); break; } + }; + +#ifdef __ANDROID__ + if (android_get_device_api_level() >= 30) { + scheduler.Wait(resource_ticks[image_index]); + } else { + wait_with_frame_pacing(); + } +#else + wait_with_frame_pacing(); +#endif resource_ticks[image_index] = scheduler.CurrentTick();