mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-09-03 22:55:28 +00:00
Compare commits
17 Commits
04e6892f2e
...
9401075498
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9401075498 | ||
![]() |
033a0540f7 | ||
![]() |
64a20c74fc | ||
![]() |
76c114a02b | ||
![]() |
c248f1afa4 | ||
![]() |
63257d1ee9 | ||
![]() |
18f0bd1d4b | ||
![]() |
2ff3a7215b | ||
![]() |
b47a75fa2d | ||
![]() |
25be1cfe97 | ||
![]() |
e0c72cd963 | ||
![]() |
da546bebb8 | ||
![]() |
489fd643d3 | ||
![]() |
bc417bdcee | ||
![]() |
0917ad89e0 | ||
![]() |
81ebf45c9b | ||
![]() |
62c773ac75 |
@ -2,6 +2,8 @@
|
||||
|
||||
[Core]
|
||||
# Values set here will override the main Dolphin settings.
|
||||
Overclock = 1.4
|
||||
OverclockEnable = True
|
||||
|
||||
[OnFrame]
|
||||
# Add memory patches to be applied every frame here.
|
||||
|
@ -1,5 +1,10 @@
|
||||
# MCDE8P - Sonic & Knuckles
|
||||
|
||||
[Core]
|
||||
# Values set here will override the main Dolphin settings.
|
||||
Overclock = 1.2
|
||||
OverclockEnable = True
|
||||
|
||||
[Video_Settings]
|
||||
|
||||
[Video_Hacks]
|
||||
|
@ -6,8 +6,10 @@
|
||||
#include <algorithm>
|
||||
#include <bit>
|
||||
#include <cmath>
|
||||
#include <concepts>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
@ -31,41 +33,24 @@ constexpr auto Lerp(const T& x, const T& y, const F& a) -> decltype(x + (y - x)
|
||||
|
||||
// Casts the specified value to a Dest. The value will be clamped to fit in the destination type.
|
||||
// Warning: The result of SaturatingCast(NaN) is undefined.
|
||||
template <typename Dest, typename T>
|
||||
template <std::integral Dest, typename T>
|
||||
constexpr Dest SaturatingCast(T value)
|
||||
{
|
||||
static_assert(std::is_integral<Dest>());
|
||||
|
||||
[[maybe_unused]] constexpr Dest lo = std::numeric_limits<Dest>::lowest();
|
||||
constexpr Dest lo = std::numeric_limits<Dest>::min();
|
||||
constexpr Dest hi = std::numeric_limits<Dest>::max();
|
||||
|
||||
// T being a signed integer and Dest unsigned is a problematic case because the value will
|
||||
// be converted into an unsigned integer, and u32(...) < 0 is always false.
|
||||
if constexpr (std::is_integral<T>() && std::is_signed<T>() && std::is_unsigned<Dest>())
|
||||
if constexpr (std::is_integral_v<T>)
|
||||
{
|
||||
static_assert(lo == 0);
|
||||
if (value < 0)
|
||||
if (std::cmp_less(value, lo))
|
||||
return lo;
|
||||
// Now that we got rid of negative values, we can safely cast value to an unsigned T
|
||||
// since unsigned T can represent any positive value signed T could represent.
|
||||
// The compiler will then promote the LHS or the RHS if necessary.
|
||||
if (std::make_unsigned_t<T>(value) > hi)
|
||||
return hi;
|
||||
}
|
||||
else if constexpr (std::is_integral<T>() && std::is_unsigned<T>() && std::is_signed<Dest>())
|
||||
{
|
||||
// value and hi will never be negative, and hi is representable as an unsigned Dest.
|
||||
if (value > std::make_unsigned_t<Dest>(hi))
|
||||
if (std::cmp_greater(value, hi))
|
||||
return hi;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do not use std::clamp or a similar function here to avoid overflow.
|
||||
// For example, if Dest = s64 and T = int, we want integer promotion to convert value to a s64
|
||||
// instead of changing lo or hi into an int.
|
||||
if (value < lo)
|
||||
if (value < static_cast<T>(lo))
|
||||
return lo;
|
||||
if (value > hi)
|
||||
if (value >= static_cast<T>(hi))
|
||||
return hi;
|
||||
}
|
||||
return static_cast<Dest>(value);
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include "Common/CommonFuncs.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
@ -194,4 +195,37 @@ void PrecisionTimer::SleepUntil(Clock::time_point target)
|
||||
}
|
||||
}
|
||||
|
||||
// Results are appropriately slewed on Linux, but not on Windows, macOS, or FreeBSD.
|
||||
// Clocks with that functionality seem to not be available there.
|
||||
auto SteadyAwakeClock::now() -> time_point
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
// The count is system time "in units of 100 nanoseconds".
|
||||
using InterruptDuration = std::chrono::duration<ULONGLONG, std::ratio<100, std::nano::den>::type>;
|
||||
|
||||
ULONGLONG interrupt_time{};
|
||||
if (!QueryUnbiasedInterruptTime(&interrupt_time))
|
||||
ERROR_LOG_FMT(COMMON, "QueryUnbiasedInterruptTime");
|
||||
|
||||
return time_point{InterruptDuration{interrupt_time}};
|
||||
#else
|
||||
// Note that Linux's CLOCK_MONOTONIC "does not count time that the system is suspended".
|
||||
// This is in contrast to the behavior on macOS and FreeBSD.
|
||||
static constexpr auto clock_id =
|
||||
#if defined(__linux__)
|
||||
CLOCK_MONOTONIC;
|
||||
#elif defined(__APPLE__)
|
||||
CLOCK_UPTIME_RAW;
|
||||
#else
|
||||
CLOCK_UPTIME;
|
||||
#endif
|
||||
|
||||
timespec ts{};
|
||||
if (clock_gettime(clock_id, &ts) != 0)
|
||||
ERROR_LOG_FMT(COMMON, "clock_gettime: {}", LastStrerrorString());
|
||||
|
||||
return time_point{std::chrono::seconds{ts.tv_sec} + std::chrono::nanoseconds{ts.tv_nsec}};
|
||||
#endif
|
||||
}
|
||||
|
||||
} // Namespace Common
|
||||
|
@ -50,4 +50,19 @@ private:
|
||||
#endif
|
||||
};
|
||||
|
||||
// Similar to std::chrono::steady_clock except this clock
|
||||
// specifically does *not* count time while the system is suspended.
|
||||
class SteadyAwakeClock
|
||||
{
|
||||
public:
|
||||
using rep = s64;
|
||||
using period = std::nano;
|
||||
using duration = std::chrono::duration<rep, period>;
|
||||
using time_point = std::chrono::time_point<SteadyAwakeClock>;
|
||||
|
||||
static constexpr bool is_steady = true;
|
||||
|
||||
static time_point now();
|
||||
};
|
||||
|
||||
} // Namespace Common
|
||||
|
@ -174,6 +174,15 @@ void AddCode(ARCode code)
|
||||
}
|
||||
}
|
||||
|
||||
size_t CountEnabledCodes()
|
||||
{
|
||||
if (!Config::AreCheatsEnabled())
|
||||
return 0;
|
||||
|
||||
std::lock_guard guard(s_lock);
|
||||
return s_active_codes.size();
|
||||
}
|
||||
|
||||
void LoadAndApplyCodes(const Common::IniFile& global_ini, const Common::IniFile& local_ini,
|
||||
const std::string& game_id, u16 revision)
|
||||
{
|
||||
|
@ -50,6 +50,7 @@ void SetSyncedCodesAsActive();
|
||||
void UpdateSyncedCodes(std::span<const ARCode> codes);
|
||||
std::vector<ARCode> ApplyAndReturnCodes(std::span<const ARCode> codes);
|
||||
void AddCode(ARCode new_code);
|
||||
size_t CountEnabledCodes();
|
||||
void LoadAndApplyCodes(const Common::IniFile& global_ini, const Common::IniFile& local_ini,
|
||||
const std::string& game_id, u16 revision);
|
||||
|
||||
|
@ -203,8 +203,8 @@ private:
|
||||
EventType* m_ev_lost = nullptr;
|
||||
|
||||
CPUThreadConfigCallback::ConfigChangedCallbackID m_registered_config_callback_id;
|
||||
float m_config_oc_factor = 0.0f;
|
||||
float m_config_oc_inv_factor = 0.0f;
|
||||
float m_config_oc_factor = 1.0f;
|
||||
float m_config_oc_inv_factor = 1.0f;
|
||||
bool m_config_sync_on_skip_idle = false;
|
||||
|
||||
s64 m_throttle_reference_cycle = 0;
|
||||
|
@ -50,6 +50,15 @@ static std::vector<GeckoCode> s_active_codes;
|
||||
static std::vector<GeckoCode> s_synced_codes;
|
||||
static std::mutex s_active_codes_lock;
|
||||
|
||||
size_t CountEnabledCodes()
|
||||
{
|
||||
if (!Config::AreCheatsEnabled())
|
||||
return 0;
|
||||
|
||||
std::lock_guard guard(s_active_codes_lock);
|
||||
return s_active_codes.size();
|
||||
}
|
||||
|
||||
void SetActiveCodes(std::span<const GeckoCode> gcodes, const std::string& game_id, u16 revision)
|
||||
{
|
||||
std::lock_guard lk(s_active_codes_lock);
|
||||
|
@ -60,6 +60,7 @@ constexpr u32 HLE_TRAMPOLINE_ADDRESS = INSTALLER_END_ADDRESS - 4;
|
||||
// preserve the emulation performance.
|
||||
constexpr u32 MAGIC_GAMEID = 0xD01F1BAD;
|
||||
|
||||
size_t CountEnabledCodes();
|
||||
void SetActiveCodes(std::span<const GeckoCode> gcodes, const std::string& game_id, u16 revision);
|
||||
void SetSyncedCodesAsActive();
|
||||
void UpdateSyncedCodes(std::span<const GeckoCode> gcodes);
|
||||
|
@ -72,8 +72,8 @@ void CPUManager::StartTimePlayedTimer()
|
||||
{
|
||||
Common::SetCurrentThreadName("Play Time Tracker");
|
||||
|
||||
// Steady clock for greater accuracy of timing
|
||||
std::chrono::steady_clock timer;
|
||||
// Use a clock that will appropriately ignore suspended system time.
|
||||
Common::SteadyAwakeClock timer;
|
||||
auto prev_time = timer.now();
|
||||
|
||||
while (true)
|
||||
|
@ -454,7 +454,7 @@ private:
|
||||
u32 m_even_field_last_hl = 0; // index last halfline of the even field
|
||||
u32 m_odd_field_last_hl = 0; // index last halfline of the odd field
|
||||
|
||||
float m_config_vi_oc_factor = 0.0f;
|
||||
float m_config_vi_oc_factor = 1.0f;
|
||||
|
||||
Config::ConfigChangedCallbackID m_config_changed_callback_id;
|
||||
Core::System& m_system;
|
||||
|
@ -28,7 +28,7 @@ constexpr u16 LegalNitroChannelMask = 0b0011'1111'1111'1110u;
|
||||
|
||||
u16 SelectWifiChannel(u16 enabled_channels_mask, u16 current_channel)
|
||||
{
|
||||
const Common::BitSet<u16> enabled_channels{enabled_channels_mask & LegalChannelMask};
|
||||
const Common::BitSet<u16> enabled_channels(enabled_channels_mask & LegalChannelMask);
|
||||
u16 next_channel = current_channel;
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "Core/PowerPC/MMU.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "Core/System.h"
|
||||
#include "VideoCommon/OnScreenDisplay.h"
|
||||
|
||||
namespace PatchEngine
|
||||
{
|
||||
@ -200,6 +201,18 @@ void LoadPatches()
|
||||
ActionReplay::LoadAndApplyCodes(globalIni, localIni, sconfig.GetGameID(),
|
||||
sconfig.GetRevision());
|
||||
}
|
||||
|
||||
const size_t enabled_patch_count =
|
||||
std::ranges::count_if(s_on_frame, [](Patch patch) { return patch.enabled; });
|
||||
if (enabled_patch_count > 0)
|
||||
{
|
||||
OSD::AddMessage(fmt::format("{} game patch(es) enabled", enabled_patch_count),
|
||||
OSD::Duration::NORMAL);
|
||||
}
|
||||
|
||||
const size_t enabled_cheat_count = ActionReplay::CountEnabledCodes() + Gecko::CountEnabledCodes();
|
||||
if (enabled_cheat_count > 0)
|
||||
OSD::AddMessage(fmt::format("{} cheat(s) enabled", enabled_cheat_count), OSD::Duration::NORMAL);
|
||||
}
|
||||
|
||||
static void ApplyPatches(const Core::CPUThreadGuard& guard, const std::vector<Patch>& patches)
|
||||
|
@ -122,12 +122,19 @@ GameList::GameList(QWidget* parent) : QStackedWidget(parent), m_model(this)
|
||||
m_list_proxy->setSortRole(GameListModel::SORT_ROLE);
|
||||
m_list_proxy->setSourceModel(&m_model);
|
||||
m_grid_proxy = new GridProxyModel(this);
|
||||
m_grid_proxy->setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||
m_grid_proxy->setSortRole(GameListModel::SORT_ROLE);
|
||||
m_grid_proxy->setSourceModel(&m_model);
|
||||
|
||||
MakeListView();
|
||||
MakeGridView();
|
||||
MakeEmptyView();
|
||||
|
||||
// Use List View's sorting for Grid View too.
|
||||
m_grid_proxy->sort(m_list_proxy->sortColumn(), m_list_proxy->sortOrder());
|
||||
connect(m_list->horizontalHeader(), &QHeaderView::sortIndicatorChanged, m_grid_proxy,
|
||||
&GridProxyModel::sort);
|
||||
|
||||
if (Settings::GetQSettings().contains(QStringLiteral("gridview/scale")))
|
||||
m_model.SetScale(Settings::GetQSettings().value(QStringLiteral("gridview/scale")).toFloat());
|
||||
|
||||
|
@ -18,8 +18,7 @@ const QSize LARGE_BANNER_SIZE(144, 48);
|
||||
|
||||
GridProxyModel::GridProxyModel(QObject* parent) : QSortFilterProxyModel(parent)
|
||||
{
|
||||
setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||
sort(static_cast<int>(GameListModel::Column::Title));
|
||||
setDynamicSortFilter(true);
|
||||
}
|
||||
|
||||
QVariant GridProxyModel::data(const QModelIndex& i, int role) const
|
||||
@ -76,3 +75,24 @@ bool GridProxyModel::filterAcceptsRow(int source_row, const QModelIndex& source_
|
||||
GameListModel* glm = qobject_cast<GameListModel*>(sourceModel());
|
||||
return glm->ShouldDisplayGameListItem(source_row);
|
||||
}
|
||||
|
||||
bool GridProxyModel::lessThan(const QModelIndex& left, const QModelIndex& right) const
|
||||
{
|
||||
if (left.data(GameListModel::SORT_ROLE) != right.data(GameListModel::SORT_ROLE))
|
||||
return QSortFilterProxyModel::lessThan(left, right);
|
||||
|
||||
// If two items are otherwise equal, compare them by their title
|
||||
const auto right_title = sourceModel()
|
||||
->index(right.row(), static_cast<int>(GameListModel::Column::Title))
|
||||
.data()
|
||||
.toString();
|
||||
const auto left_title = sourceModel()
|
||||
->index(left.row(), static_cast<int>(GameListModel::Column::Title))
|
||||
.data()
|
||||
.toString();
|
||||
|
||||
if (sortOrder() == Qt::AscendingOrder)
|
||||
return left_title < right_title;
|
||||
|
||||
return right_title < left_title;
|
||||
}
|
||||
|
@ -14,5 +14,8 @@ class GridProxyModel final : public QSortFilterProxyModel
|
||||
public:
|
||||
explicit GridProxyModel(QObject* parent = nullptr);
|
||||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
protected:
|
||||
bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override;
|
||||
bool lessThan(const QModelIndex& left, const QModelIndex& right) const override;
|
||||
};
|
||||
|
@ -173,12 +173,8 @@ static void Draw(s32 x, s32 y, s32 xi, s32 yi)
|
||||
{
|
||||
for (int comp = 0; comp < 4; comp++)
|
||||
{
|
||||
u16 color = (u16)ColorSlopes[i][comp].GetValue(x, y);
|
||||
|
||||
// clamp color value to 0
|
||||
u16 mask = ~(color >> 8);
|
||||
|
||||
tev.Color[i][comp] = color & mask;
|
||||
const float color = ColorSlopes[i][comp].GetValue(x, y);
|
||||
tev.Color[i][comp] = (u8)std::clamp<float>(color, 0.0f, 255.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,6 +66,13 @@ TEST(MathUtil, SaturatingCast)
|
||||
// 16777217 = 2^24 + 1 is the first integer that cannot be represented correctly with a f32.
|
||||
EXPECT_EQ(16777216, MathUtil::SaturatingCast<s32>(float(16777216)));
|
||||
EXPECT_EQ(16777216, MathUtil::SaturatingCast<s32>(float(16777217)));
|
||||
|
||||
// Note that values in the range [2147483584, 2147483776] have an equivalent float representation.
|
||||
EXPECT_EQ(std::numeric_limits<s32>::max(), MathUtil::SaturatingCast<s32>(2147483648.f));
|
||||
EXPECT_EQ(std::numeric_limits<s32>::min(), MathUtil::SaturatingCast<s32>(-2147483649.f));
|
||||
|
||||
// Cast from a signed integer type to a smaller signed integer type
|
||||
EXPECT_EQ(-128, (MathUtil::SaturatingCast<s8, int>(-129)));
|
||||
}
|
||||
|
||||
TEST(MathUtil, RectangleEquality)
|
||||
|
Loading…
Reference in New Issue
Block a user