Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0e6b0d9a5 | ||
|
|
580218d495 | ||
|
|
519f280fa5 | ||
|
|
a33ee13bb4 | ||
|
|
0c70cc7e5a | ||
|
|
2cba346ff5 | ||
|
|
db2509edb3 | ||
|
|
e3063d6cd6 | ||
|
|
8d30e8cee8 | ||
|
|
ff2f1998ad | ||
|
|
7942ee438a | ||
|
|
f322dfb1d4 | ||
|
|
a7f5ddfe0d | ||
|
|
0cdfb75fd0 |
@@ -208,7 +208,7 @@
|
||||
</action>
|
||||
<action name="actionAnalyse">
|
||||
<property name="icon">
|
||||
<iconset theme="magnifier-line"/>
|
||||
<iconset theme="search-line"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Analyze</string>
|
||||
|
||||
@@ -144,12 +144,12 @@ void DockMenuBar::onLockStateChanged(bool layout_locked)
|
||||
if (layout_locked)
|
||||
{
|
||||
m_layout_locked_toggle->setText(tr("Layout Locked"));
|
||||
m_layout_locked_toggle->setIcon(QIcon::fromTheme(QString::fromUtf8("padlock-lock")));
|
||||
m_layout_locked_toggle->setIcon(QIcon::fromTheme(QString::fromUtf8("lock-fill")));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_layout_locked_toggle->setText(tr("Layout Unlocked"));
|
||||
m_layout_locked_toggle->setIcon(QIcon::fromTheme(QString::fromUtf8("padlock-unlock")));
|
||||
m_layout_locked_toggle->setIcon(QIcon::fromTheme(QString::fromUtf8("lock-unlock-fill")));
|
||||
}
|
||||
|
||||
m_ignore_lock_state_changed = false;
|
||||
|
||||
@@ -256,8 +256,6 @@ void GameListWidget::initialize()
|
||||
|
||||
m_table_view = new QTableView(m_ui.stack);
|
||||
m_table_view->setModel(m_sort_model);
|
||||
m_table_view->setSortingEnabled(true);
|
||||
m_table_view->horizontalHeader()->setSectionsMovable(true);
|
||||
m_table_view->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
m_table_view->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
m_table_view->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
@@ -265,8 +263,9 @@ void GameListWidget::initialize()
|
||||
m_table_view->setMouseTracking(true);
|
||||
m_table_view->setShowGrid(false);
|
||||
m_table_view->setCurrentIndex(QModelIndex());
|
||||
m_table_view->horizontalHeader()->setHighlightSections(false);
|
||||
m_table_view->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
m_table_view->horizontalHeader()->setHighlightSections(false);
|
||||
m_table_view->horizontalHeader()->setSectionsMovable(true);
|
||||
m_table_view->verticalHeader()->hide();
|
||||
m_table_view->setVerticalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel);
|
||||
|
||||
@@ -738,8 +737,8 @@ void GameListWidget::resizeTableViewColumnsToFit()
|
||||
QtUtils::ResizeColumnsForTableView(m_table_view, {
|
||||
DEFAULT_COLUMN_WIDTHS[GameListModel::Column_Type],
|
||||
DEFAULT_COLUMN_WIDTHS[GameListModel::Column_Serial],
|
||||
DEFAULT_COLUMN_WIDTHS[GameListModel::Column_Title],
|
||||
DEFAULT_COLUMN_WIDTHS[GameListModel::Column_FileTitle],
|
||||
DEFAULT_COLUMN_WIDTHS[GameListModel::Column_Type],
|
||||
DEFAULT_COLUMN_WIDTHS[GameListModel::Column_CRC],
|
||||
DEFAULT_COLUMN_WIDTHS[GameListModel::Column_TimePlayed],
|
||||
DEFAULT_COLUMN_WIDTHS[GameListModel::Column_LastPlayed],
|
||||
|
||||
@@ -855,7 +855,7 @@
|
||||
</action>
|
||||
<action name="actionDebugger">
|
||||
<property name="icon">
|
||||
<iconset theme="heart-circle-line"/>
|
||||
<iconset theme="bug-line"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Open Debugger</string>
|
||||
|
||||
@@ -318,7 +318,9 @@ void EmuThread::loadState(const QString& filename)
|
||||
if (!VMManager::HasValidVM())
|
||||
return;
|
||||
|
||||
VMManager::LoadState(filename.toUtf8().constData());
|
||||
Error error;
|
||||
if (!VMManager::LoadState(filename.toUtf8().constData(), &error))
|
||||
Host::ReportErrorAsync(TRANSLATE_SV("QtHost", "Failed to Load State"), error.GetDescription());
|
||||
}
|
||||
|
||||
void EmuThread::loadStateFromSlot(qint32 slot, bool load_backup)
|
||||
@@ -332,7 +334,9 @@ void EmuThread::loadStateFromSlot(qint32 slot, bool load_backup)
|
||||
if (!VMManager::HasValidVM())
|
||||
return;
|
||||
|
||||
VMManager::LoadStateFromSlot(slot, load_backup);
|
||||
Error error;
|
||||
if (!VMManager::LoadStateFromSlot(slot, load_backup, &error))
|
||||
Host::ReportErrorAsync(TRANSLATE_SV("QtHost", "Failed to Load State"), error.GetDescription());
|
||||
}
|
||||
|
||||
void EmuThread::saveState(const QString& filename)
|
||||
|
||||
@@ -204,7 +204,7 @@ void SettingsWindow::setupUi(const GameList::Entry* game)
|
||||
tr("<strong>Advanced Settings</strong><hr>These are advanced options to determine the configuration of the simulated "
|
||||
"console.<br><br>Mouse over an option for additional information, and Shift+Wheel to scroll this panel."));
|
||||
addWidget(m_debug_settings = new DebugSettingsWidget(this, m_ui.settingsContainer), tr("Debug"),
|
||||
QStringLiteral("debugger-line"),
|
||||
QStringLiteral("bug-line"),
|
||||
tr("<strong>Debug Settings</strong><hr>These are options which can be used to log internal information about the application. "
|
||||
"<strong>Do not modify unless you know what you are doing</strong>, it will cause significant slowdown, and can waste large "
|
||||
"amounts of disk space."));
|
||||
|
||||
1
pcsx2-qt/resources/icons/black/svg/bug-line.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 24 24"><path d="M13 19.9C15.2822 19.4367 17 17.419 17 15V12C17 11.299 16.8564 10.6219 16.5846 10H7.41538C7.14358 10.6219 7 11.299 7 12V15C7 17.419 8.71776 19.4367 11 19.9V14H13V19.9ZM5.5358 17.6907C5.19061 16.8623 5 15.9534 5 15H2V13H5V12C5 11.3573 5.08661 10.7348 5.2488 10.1436L3.0359 8.86602L4.0359 7.13397L6.05636 8.30049C6.11995 8.19854 6.18609 8.09835 6.25469 8H17.7453C17.8139 8.09835 17.88 8.19854 17.9436 8.30049L19.9641 7.13397L20.9641 8.86602L18.7512 10.1436C18.9134 10.7348 19 11.3573 19 12V13H22V15H19C19 15.9534 18.8094 16.8623 18.4642 17.6907L20.9641 19.134L19.9641 20.866L17.4383 19.4077C16.1549 20.9893 14.1955 22 12 22C9.80453 22 7.84512 20.9893 6.56171 19.4077L4.0359 20.866L3.0359 19.134L5.5358 17.6907ZM8 6C8 3.79086 9.79086 2 12 2C14.2091 2 16 3.79086 16 6H8Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 815 B |
@@ -1,28 +0,0 @@
|
||||
<svg viewBox="0 0 150 150">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
stroke: #000;
|
||||
stroke-miterlimit: 10;
|
||||
stroke-width: 2px;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<g id="Camada_3">
|
||||
<g id="By_Maxihplay">
|
||||
<g id="baixo">
|
||||
<path class="cls-1" d="m20.57,127.29v-7.95h12.21v-30.79l-10.63,5.87-2.93-7.29,15.21-8.03h7.51v40.25h10.52v7.95h-31.89Z"/>
|
||||
<path class="cls-1" d="m95.6,103.13c0,3.94-.43,7.45-1.28,10.56-.86,3.1-2.11,5.73-3.76,7.86-1.65,2.14-3.66,3.77-6.03,4.89-2.37,1.12-5.08,1.69-8.14,1.69-2.64,0-5.07-.47-7.3-1.39-2.22-.93-4.14-2.39-5.76-4.38-1.61-1.99-2.87-4.54-3.78-7.64-.9-3.1-1.36-6.82-1.36-11.14,0-3.93.43-7.45,1.3-10.56.87-3.1,2.12-5.72,3.76-7.86,1.64-2.14,3.65-3.77,6.05-4.89,2.4-1.12,5.11-1.69,8.14-1.69,2.64,0,5.07.47,7.3,1.39,2.22.93,4.14,2.38,5.74,4.36,1.6,1.98,2.85,4.52,3.76,7.62.9,3.1,1.36,6.83,1.36,11.18Zm-28.37.15v1.37c0,.43.02.86.07,1.3l17.96-12.98c-.86-2.42-1.98-4.21-3.39-5.37s-3.06-1.74-4.97-1.74c-1.37,0-2.64.35-3.81,1.05s-2.19,1.77-3.06,3.21c-.87,1.44-1.55,3.25-2.05,5.43-.5,2.18-.75,4.75-.75,7.74Zm19.36.15c0-.42-.01-.84-.04-1.26-.02-.43-.04-.84-.04-1.23l-17.85,12.9c.78,2.37,1.88,4.13,3.3,5.28,1.42,1.15,3.07,1.72,4.95,1.72,1.37,0,2.64-.35,3.83-1.06s2.21-1.78,3.08-3.21c.87-1.43,1.55-3.24,2.03-5.43.49-2.19.73-4.76.73-7.72Z"/>
|
||||
<path class="cls-1" d="m103.12,127.29v-7.95h12.21v-30.79l-10.63,5.87-2.93-7.29,15.21-8.03h7.51v40.25h10.52v7.95h-31.89Z"/>
|
||||
</g>
|
||||
<g id="cima">
|
||||
<path class="cls-1" d="m52.38,46.43c0,3.94-.43,7.45-1.28,10.56-.86,3.1-2.11,5.73-3.76,7.86-1.65,2.14-3.66,3.77-6.03,4.89-2.37,1.12-5.08,1.69-8.14,1.69-2.64,0-5.07-.47-7.3-1.39-2.22-.93-4.14-2.39-5.76-4.38-1.61-1.99-2.87-4.54-3.78-7.64-.9-3.1-1.36-6.82-1.36-11.14,0-3.93.43-7.45,1.3-10.56.87-3.1,2.12-5.72,3.76-7.86,1.64-2.14,3.65-3.77,6.05-4.89,2.4-1.12,5.11-1.69,8.14-1.69,2.64,0,5.07.47,7.3,1.39,2.22.93,4.14,2.38,5.74,4.36,1.6,1.98,2.85,4.52,3.76,7.62.9,3.1,1.36,6.83,1.36,11.18Zm-28.37.15v1.37c0,.43.02.86.07,1.3l17.96-12.98c-.86-2.42-1.98-4.21-3.39-5.37s-3.06-1.74-4.97-1.74c-1.37,0-2.64.35-3.81,1.05s-2.19,1.77-3.06,3.21c-.87,1.44-1.55,3.25-2.05,5.43-.5,2.18-.75,4.75-.75,7.74Zm19.36.15c0-.42-.01-.84-.04-1.26-.02-.43-.04-.84-.04-1.23l-17.85,12.9c.78,2.37,1.88,4.13,3.3,5.28,1.42,1.15,3.07,1.72,4.95,1.72,1.37,0,2.64-.35,3.83-1.06s2.21-1.78,3.08-3.21c.87-1.43,1.55-3.24,2.03-5.43.49-2.19.73-4.76.73-7.72Z"/>
|
||||
<path class="cls-1" d="m59.89,70.58v-7.95h12.21v-30.79l-10.63,5.87-2.93-7.29,15.21-8.03h7.51v40.25h10.52v7.95h-31.89Z"/>
|
||||
<path class="cls-1" d="m134.93,46.43c0,3.94-.43,7.45-1.28,10.56-.86,3.1-2.11,5.73-3.76,7.86-1.65,2.14-3.66,3.77-6.03,4.89-2.37,1.12-5.08,1.69-8.14,1.69-2.64,0-5.07-.47-7.3-1.39-2.22-.93-4.14-2.39-5.76-4.38-1.61-1.99-2.87-4.54-3.78-7.64-.9-3.1-1.36-6.82-1.36-11.14,0-3.93.43-7.45,1.3-10.56.87-3.1,2.12-5.72,3.76-7.86,1.64-2.14,3.65-3.77,6.05-4.89,2.4-1.12,5.11-1.69,8.14-1.69,2.64,0,5.07.47,7.3,1.39,2.22.93,4.14,2.38,5.74,4.36,1.6,1.98,2.85,4.52,3.76,7.62.9,3.1,1.36,6.83,1.36,11.18Zm-28.37.15v1.37c0,.43.02.86.07,1.3l17.96-12.98c-.86-2.42-1.98-4.21-3.39-5.37-1.41-1.16-3.06-1.74-4.97-1.74-1.37,0-2.64.35-3.81,1.05s-2.19,1.77-3.06,3.21c-.87,1.44-1.55,3.25-2.05,5.43-.5,2.18-.75,4.75-.75,7.74Zm19.36.15c0-.42-.01-.84-.04-1.26-.02-.43-.04-.84-.04-1.23l-17.85,12.9c.78,2.37,1.88,4.13,3.3,5.28,1.42,1.15,3.07,1.72,4.95,1.72,1.37,0,2.64-.35,3.83-1.06s2.21-1.78,3.08-3.21c.87-1.43,1.55-3.24,2.03-5.43.49-2.19.73-4.76.73-7.72Z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Camada_2">
|
||||
<path class="cls-2" d="m-3.8-.03h154.06v152.06H-3.8V-.03Z" fill="none"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.5 KiB |
@@ -1,10 +0,0 @@
|
||||
<svg viewBox="0 0 512 512">
|
||||
<circle
|
||||
style="fill:none;stroke:#000000;stroke-width:39.1094;stroke-linecap:round;stroke-dasharray:none"
|
||||
cx="255.99998"
|
||||
cy="255.99998"
|
||||
r="236.44533"/>
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:round"
|
||||
d="M 14.169739,256 H 138.21901 L 210.20476,131.31702 277.76735,383.464 358.15788,244.22352 h 139.38547"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 396 B |
1
pcsx2-qt/resources/icons/black/svg/lock-fill.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 24 24"><path d="M19 10H20C20.5523 10 21 10.4477 21 11V21C21 21.5523 20.5523 22 20 22H4C3.44772 22 3 21.5523 3 21V11C3 10.4477 3.44772 10 4 10H5V9C5 5.13401 8.13401 2 12 2C15.866 2 19 5.13401 19 9V10ZM17 10V9C17 6.23858 14.7614 4 12 4C9.23858 4 7 6.23858 7 9V10H17ZM11 14V18H13V14H11Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 317 B |
1
pcsx2-qt/resources/icons/black/svg/lock-unlock-fill.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 24 24"><path d="M7 10H20C20.5523 10 21 10.4477 21 11V21C21 21.5523 20.5523 22 20 22H4C3.44772 22 3 21.5523 3 21V11C3 10.4477 3.44772 10 4 10H5V9C5 5.13401 8.13401 2 12 2C14.7405 2 17.1131 3.5748 18.2624 5.86882L16.4731 6.76344C15.6522 5.12486 13.9575 4 12 4C9.23858 4 7 6.23858 7 9V10ZM10 15V17H14V15H10Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 338 B |
@@ -1 +0,0 @@
|
||||
<svg viewBox="0 0 512 512"><path d="M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z"/></svg>
|
||||
|
Before Width: | Height: | Size: 391 B |
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="800px" height="800px" fill="none" version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m8.1816 10.703s4e-5 -2.5676 0-4.1081c-4e-5 -1.8489 1.527-3.5946 3.8182-3.5946 2.2912 0 3.8181 1.7457 3.8181 3.5946v4.1081" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
<path d="m4.5 11.393c-4e-5 1.7387-1e-4 5.3708 2e-5 7.8056 1.3e-4 2.6923 4.1637 3.3012 7.5 3.3012 3.3363 0 7.4999-0.6089 7.4999-3.3012v-7.8056c0-0.5523-0.4477-0.9975-1-0.9975h-13c-0.55227 0-0.99998 0.4452-0.99999 0.9975zm6 4.6096c0 0.476 0.2069 0.9037 0.5357 1.198v1.5521c0 0.5522 0.4477 1 1 1h0.1429c0.5523 0 1-0.4478 1-1v-1.5521c0.3288-0.2943 0.5357-0.722 0.5357-1.198 0-0.8876-0.7195-1.6071-1.6071-1.6071-0.8877 0-1.6072 0.7195-1.6072 1.6071z" clip-rule="evenodd" fill="#000" fill-rule="evenodd"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 876 B |
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="800px" height="800px" fill="none" version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m4.5 11.393c-4e-5 1.7387-1e-4 5.3708 2e-5 7.8056 1.3e-4 2.6923 4.1637 3.3012 7.5 3.3012 3.3363 0 7.4999-0.6089 7.4999-3.3012v-7.8056c0-0.5523-0.4477-0.9975-1-0.9975h-13c-0.55227 0-0.99998 0.4452-0.99999 0.9975zm6 4.6096c0 0.476 0.2069 0.9037 0.5357 1.198v1.5521c0 0.5522 0.4477 1 1 1h0.1429c0.5523 0 1-0.4478 1-1v-1.5521c0.3288-0.2943 0.5357-0.722 0.5357-1.198 0-0.8876-0.7195-1.6071-1.6071-1.6071-0.8877 0-1.6072 0.7195-1.6072 1.6071z" clip-rule="evenodd" fill="#000" fill-rule="evenodd"/>
|
||||
<path d="m8.1816 10.703s4e-5 -2.5676 0-4.1081c-4e-5 -1.8489 1.527-3.5946 3.8182-3.5946 2.2912 0 3.8181 1.7457 3.8181 3.5946" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 869 B |
1
pcsx2-qt/resources/icons/black/svg/search-line.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 24 24"><path d="M18.031 16.6168L22.3137 20.8995L20.8995 22.3137L16.6168 18.031C15.0769 19.263 13.124 20 11 20C6.032 20 2 15.968 2 11C2 6.032 6.032 2 11 2C15.968 2 20 6.032 20 11C20 13.124 19.263 15.0769 18.031 16.6168ZM16.0247 15.8748C17.2475 14.6146 18 12.8956 18 11C18 7.1325 14.8675 4 11 4C7.1325 4 4 7.1325 4 11C4 14.8675 7.1325 18 11 18C12.8956 18 14.6146 17.2475 15.8748 16.0247L16.0247 15.8748Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 435 B |
1
pcsx2-qt/resources/icons/white/svg/bug-line.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 24 24" fill="#fff"><path d="M13 19.9C15.2822 19.4367 17 17.419 17 15V12C17 11.299 16.8564 10.6219 16.5846 10H7.41538C7.14358 10.6219 7 11.299 7 12V15C7 17.419 8.71776 19.4367 11 19.9V14H13V19.9ZM5.5358 17.6907C5.19061 16.8623 5 15.9534 5 15H2V13H5V12C5 11.3573 5.08661 10.7348 5.2488 10.1436L3.0359 8.86602L4.0359 7.13397L6.05636 8.30049C6.11995 8.19854 6.18609 8.09835 6.25469 8H17.7453C17.8139 8.09835 17.88 8.19854 17.9436 8.30049L19.9641 7.13397L20.9641 8.86602L18.7512 10.1436C18.9134 10.7348 19 11.3573 19 12V13H22V15H19C19 15.9534 18.8094 16.8623 18.4642 17.6907L20.9641 19.134L19.9641 20.866L17.4383 19.4077C16.1549 20.9893 14.1955 22 12 22C9.80453 22 7.84512 20.9893 6.56171 19.4077L4.0359 20.866L3.0359 19.134L5.5358 17.6907ZM8 6C8 3.79086 9.79086 2 12 2C14.2091 2 16 3.79086 16 6H8Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 827 B |
@@ -1,31 +0,0 @@
|
||||
<svg viewBox="0 0 150 150">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: #fff;
|
||||
stroke: #fff;
|
||||
stroke-miterlimit: 10;
|
||||
stroke-width: 2px;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<g id="Camada_3">
|
||||
<g id="codigos">
|
||||
<g id="By_Maxihplay">
|
||||
<g id="baixo">
|
||||
<path class="cls-1" d="m20.57,127.29v-7.95h12.21v-30.79l-10.63,5.87-2.93-7.29,15.21-8.03h7.51v40.25h10.52v7.95h-31.89Z"/>
|
||||
<path class="cls-1" d="m95.6,103.13c0,3.94-.43,7.45-1.28,10.56-.86,3.1-2.11,5.73-3.76,7.86-1.65,2.14-3.66,3.77-6.03,4.89-2.37,1.12-5.08,1.69-8.14,1.69-2.64,0-5.07-.47-7.3-1.39-2.22-.93-4.14-2.39-5.76-4.38-1.61-1.99-2.87-4.54-3.78-7.64-.9-3.1-1.36-6.82-1.36-11.14,0-3.93.43-7.45,1.3-10.56.87-3.1,2.12-5.72,3.76-7.86,1.64-2.14,3.65-3.77,6.05-4.89,2.4-1.12,5.11-1.69,8.14-1.69,2.64,0,5.07.47,7.3,1.39,2.22.93,4.14,2.38,5.74,4.36,1.6,1.98,2.85,4.52,3.76,7.62.9,3.1,1.36,6.83,1.36,11.18Zm-28.37.15v1.37c0,.43.02.86.07,1.3l17.96-12.98c-.86-2.42-1.98-4.21-3.39-5.37s-3.06-1.74-4.97-1.74c-1.37,0-2.64.35-3.81,1.05s-2.19,1.77-3.06,3.21c-.87,1.44-1.55,3.25-2.05,5.43-.5,2.18-.75,4.75-.75,7.74Zm19.36.15c0-.42-.01-.84-.04-1.26-.02-.43-.04-.84-.04-1.23l-17.85,12.9c.78,2.37,1.88,4.13,3.3,5.28,1.42,1.15,3.07,1.72,4.95,1.72,1.37,0,2.64-.35,3.83-1.06s2.21-1.78,3.08-3.21c.87-1.43,1.55-3.24,2.03-5.43.49-2.19.73-4.76.73-7.72Z"/>
|
||||
<path class="cls-1" d="m103.12,127.29v-7.95h12.21v-30.79l-10.63,5.87-2.93-7.29,15.21-8.03h7.51v40.25h10.52v7.95h-31.89Z"/>
|
||||
</g>
|
||||
<g id="cima">
|
||||
<path class="cls-1" d="m52.38,46.43c0,3.94-.43,7.45-1.28,10.56-.86,3.1-2.11,5.73-3.76,7.86-1.65,2.14-3.66,3.77-6.03,4.89-2.37,1.12-5.08,1.69-8.14,1.69-2.64,0-5.07-.47-7.3-1.39-2.22-.93-4.14-2.39-5.76-4.38-1.61-1.99-2.87-4.54-3.78-7.64-.9-3.1-1.36-6.82-1.36-11.14,0-3.93.43-7.45,1.3-10.56.87-3.1,2.12-5.72,3.76-7.86,1.64-2.14,3.65-3.77,6.05-4.89,2.4-1.12,5.11-1.69,8.14-1.69,2.64,0,5.07.47,7.3,1.39,2.22.93,4.14,2.38,5.74,4.36,1.6,1.98,2.85,4.52,3.76,7.62.9,3.1,1.36,6.83,1.36,11.18Zm-28.37.15v1.37c0,.43.02.86.07,1.3l17.96-12.98c-.86-2.42-1.98-4.21-3.39-5.37s-3.06-1.74-4.97-1.74c-1.37,0-2.64.35-3.81,1.05s-2.19,1.77-3.06,3.21c-.87,1.44-1.55,3.25-2.05,5.43-.5,2.18-.75,4.75-.75,7.74Zm19.36.15c0-.42-.01-.84-.04-1.26-.02-.43-.04-.84-.04-1.23l-17.85,12.9c.78,2.37,1.88,4.13,3.3,5.28,1.42,1.15,3.07,1.72,4.95,1.72,1.37,0,2.64-.35,3.83-1.06s2.21-1.78,3.08-3.21c.87-1.43,1.55-3.24,2.03-5.43.49-2.19.73-4.76.73-7.72Z"/>
|
||||
<path class="cls-1" d="m59.89,70.58v-7.95h12.21v-30.79l-10.63,5.87-2.93-7.29,15.21-8.03h7.51v40.25h10.52v7.95h-31.89Z"/>
|
||||
<path class="cls-1" d="m134.93,46.43c0,3.94-.43,7.45-1.28,10.56-.86,3.1-2.11,5.73-3.76,7.86-1.65,2.14-3.66,3.77-6.03,4.89-2.37,1.12-5.08,1.69-8.14,1.69-2.64,0-5.07-.47-7.3-1.39-2.22-.93-4.14-2.39-5.76-4.38-1.61-1.99-2.87-4.54-3.78-7.64-.9-3.1-1.36-6.82-1.36-11.14,0-3.93.43-7.45,1.3-10.56.87-3.1,2.12-5.72,3.76-7.86,1.64-2.14,3.65-3.77,6.05-4.89,2.4-1.12,5.11-1.69,8.14-1.69,2.64,0,5.07.47,7.3,1.39,2.22.93,4.14,2.38,5.74,4.36,1.6,1.98,2.85,4.52,3.76,7.62.9,3.1,1.36,6.83,1.36,11.18Zm-28.37.15v1.37c0,.43.02.86.07,1.3l17.96-12.98c-.86-2.42-1.98-4.21-3.39-5.37-1.41-1.16-3.06-1.74-4.97-1.74-1.37,0-2.64.35-3.81,1.05s-2.19,1.77-3.06,3.21c-.87,1.44-1.55,3.25-2.05,5.43-.5,2.18-.75,4.75-.75,7.74Zm19.36.15c0-.42-.01-.84-.04-1.26-.02-.43-.04-.84-.04-1.23l-17.85,12.9c.78,2.37,1.88,4.13,3.3,5.28,1.42,1.15,3.07,1.72,4.95,1.72,1.37,0,2.64-.35,3.83-1.06,1.19-.71,2.21-1.78,3.08-3.21.87-1.43,1.55-3.24,2.03-5.43.49-2.19.73-4.76.73-7.72Z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Camada_2">
|
||||
<path class="cls-2" d="m-3.8-.03h154.06v152.06H-3.8V-.03Z" fill="none"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.6 KiB |
@@ -1,10 +0,0 @@
|
||||
<svg viewBox="0 0 512 512">
|
||||
<circle
|
||||
style="fill:none;stroke:#ffffff;stroke-width:39.1094;stroke-linecap:round;stroke-dasharray:none"
|
||||
cx="255.99998"
|
||||
cy="255.99998"
|
||||
r="236.44533" />
|
||||
<path
|
||||
style="fill:none;stroke:#ffffff;stroke-width:30;stroke-linecap:round"
|
||||
d="M 14.169739,256 H 138.21901 L 210.20476,131.31702 277.76735,383.464 358.15788,244.22352 h 139.38547"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 397 B |
1
pcsx2-qt/resources/icons/white/svg/lock-fill.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 24 24" fill="#fff"><path d="M19 10H20C20.5523 10 21 10.4477 21 11V21C21 21.5523 20.5523 22 20 22H4C3.44772 22 3 21.5523 3 21V11C3 10.4477 3.44772 10 4 10H5V9C5 5.13401 8.13401 2 12 2C15.866 2 19 5.13401 19 9V10ZM17 10V9C17 6.23858 14.7614 4 12 4C9.23858 4 7 6.23858 7 9V10H17ZM11 14V18H13V14H11Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 329 B |
1
pcsx2-qt/resources/icons/white/svg/lock-unlock-fill.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 24 24" fill="#fff"><path d="M7 10H20C20.5523 10 21 10.4477 21 11V21C21 21.5523 20.5523 22 20 22H4C3.44772 22 3 21.5523 3 21V11C3 10.4477 3.44772 10 4 10H5V9C5 5.13401 8.13401 2 12 2C14.7405 2 17.1131 3.5748 18.2624 5.86882L16.4731 6.76344C15.6522 5.12486 13.9575 4 12 4C9.23858 4 7 6.23858 7 9V10ZM10 15V17H14V15H10Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 350 B |
1
pcsx2-qt/resources/icons/white/svg/search-line.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 24 24" fill="#fff"><path d="M18.031 16.6168L22.3137 20.8995L20.8995 22.3137L16.6168 18.031C15.0769 19.263 13.124 20 11 20C6.032 20 2 15.968 2 11C2 6.032 6.032 2 11 2C15.968 2 20 6.032 20 11C20 13.124 19.263 15.0769 18.031 16.6168ZM16.0247 15.8748C17.2475 14.6146 18 12.8956 18 11C18 7.1325 14.8675 4 11 4C7.1325 4 4 7.1325 4 11C4 14.8675 7.1325 18 11 18C12.8956 18 14.6146 17.2475 15.8748 16.0247L16.0247 15.8748Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 447 B |
@@ -9,6 +9,7 @@
|
||||
<file>icons/black/svg/booklet.svg</file>
|
||||
<file>icons/black/svg/book.svg</file>
|
||||
<file>icons/black/svg/brush-line.svg</file>
|
||||
<file>icons/black/svg/bug-line.svg</file>
|
||||
<file>icons/black/svg/buzz-controller-line.svg</file>
|
||||
<file>icons/black/svg/camera-video.svg</file>
|
||||
<file>icons/black/svg/cheats-line.svg</file>
|
||||
@@ -17,7 +18,6 @@
|
||||
<file>icons/black/svg/close-line.svg</file>
|
||||
<file>icons/black/svg/controller-line.svg</file>
|
||||
<file>icons/black/svg/controller-strike-line.svg</file>
|
||||
<file>icons/black/svg/debugger-line.svg</file>
|
||||
<file>icons/black/svg/debug-step-into-line.svg</file>
|
||||
<file>icons/black/svg/debug-step-out-line.svg</file>
|
||||
<file>icons/black/svg/debug-step-over-line.svg</file>
|
||||
@@ -54,7 +54,6 @@
|
||||
<file>icons/black/svg/guitar-line.svg</file>
|
||||
<file>icons/black/svg/guncon2-line.svg</file>
|
||||
<file>icons/black/svg/headset-line.svg</file>
|
||||
<file>icons/black/svg/heart-circle-line.svg</file>
|
||||
<file>icons/black/svg/image-fill.svg</file>
|
||||
<file>icons/black/svg/interface-line.svg</file>
|
||||
<file>icons/black/svg/jogcon-line.svg</file>
|
||||
@@ -63,16 +62,15 @@
|
||||
<file>icons/black/svg/keyboardmania-line.svg</file>
|
||||
<file>icons/black/svg/lightbulb-line.svg</file>
|
||||
<file>icons/black/svg/list-check.svg</file>
|
||||
<file>icons/black/svg/lock-fill.svg</file>
|
||||
<file>icons/black/svg/lock-unlock-fill.svg</file>
|
||||
<file>icons/black/svg/login-box-line.svg</file>
|
||||
<file>icons/black/svg/magnifier-line.svg</file>
|
||||
<file>icons/black/svg/memcard-line.svg</file>
|
||||
<file>icons/black/svg/mic-line.svg</file>
|
||||
<file>icons/black/svg/minus-line.svg</file>
|
||||
<file>icons/black/svg/mouse-line.svg</file>
|
||||
<file>icons/black/svg/msd-line.svg</file>
|
||||
<file>icons/black/svg/negcon-line.svg</file>
|
||||
<file>icons/black/svg/padlock-lock.svg</file>
|
||||
<file>icons/black/svg/padlock-unlock.svg</file>
|
||||
<file>icons/black/svg/pause-line.svg</file>
|
||||
<file>icons/black/svg/pencil-line.svg</file>
|
||||
<file>icons/black/svg/pin-filled.svg</file>
|
||||
@@ -87,6 +85,7 @@
|
||||
<file>icons/black/svg/save-3-line.svg</file>
|
||||
<file>icons/black/svg/screenshot-2-line.svg</file>
|
||||
<file>icons/black/svg/seamic-line.svg</file>
|
||||
<file>icons/black/svg/search-line.svg</file>
|
||||
<file>icons/black/svg/settings-3-line.svg</file>
|
||||
<file>icons/black/svg/shut-down-line.svg</file>
|
||||
<file>icons/black/svg/singstar-line.svg</file>
|
||||
@@ -114,6 +113,7 @@
|
||||
<file>icons/white/svg/booklet.svg</file>
|
||||
<file>icons/white/svg/book.svg</file>
|
||||
<file>icons/white/svg/brush-line.svg</file>
|
||||
<file>icons/white/svg/bug-line.svg</file>
|
||||
<file>icons/white/svg/buzz-controller-line.svg</file>
|
||||
<file>icons/white/svg/camera-video.svg</file>
|
||||
<file>icons/white/svg/cheats-line.svg</file>
|
||||
@@ -122,7 +122,6 @@
|
||||
<file>icons/white/svg/close-line.svg</file>
|
||||
<file>icons/white/svg/controller-line.svg</file>
|
||||
<file>icons/white/svg/controller-strike-line.svg</file>
|
||||
<file>icons/white/svg/debugger-line.svg</file>
|
||||
<file>icons/white/svg/debug-step-into-line.svg</file>
|
||||
<file>icons/white/svg/debug-step-out-line.svg</file>
|
||||
<file>icons/white/svg/debug-step-over-line.svg</file>
|
||||
@@ -159,7 +158,6 @@
|
||||
<file>icons/white/svg/guitar-line.svg</file>
|
||||
<file>icons/white/svg/guncon2-line.svg</file>
|
||||
<file>icons/white/svg/headset-line.svg</file>
|
||||
<file>icons/white/svg/heart-circle-line.svg</file>
|
||||
<file>icons/white/svg/image-fill.svg</file>
|
||||
<file>icons/white/svg/interface-line.svg</file>
|
||||
<file>icons/white/svg/jogcon-line.svg</file>
|
||||
@@ -168,6 +166,8 @@
|
||||
<file>icons/white/svg/keyboardmania-line.svg</file>
|
||||
<file>icons/white/svg/lightbulb-line.svg</file>
|
||||
<file>icons/white/svg/list-check.svg</file>
|
||||
<file>icons/white/svg/lock-fill.svg</file>
|
||||
<file>icons/white/svg/lock-unlock-fill.svg</file>
|
||||
<file>icons/white/svg/login-box-line.svg</file>
|
||||
<file>icons/white/svg/magnifier-line.svg</file>
|
||||
<file>icons/white/svg/memcard-line.svg</file>
|
||||
@@ -192,6 +192,7 @@
|
||||
<file>icons/white/svg/save-3-line.svg</file>
|
||||
<file>icons/white/svg/screenshot-2-line.svg</file>
|
||||
<file>icons/white/svg/seamic-line.svg</file>
|
||||
<file>icons/white/svg/search-line.svg</file>
|
||||
<file>icons/white/svg/settings-3-line.svg</file>
|
||||
<file>icons/white/svg/shut-down-line.svg</file>
|
||||
<file>icons/white/svg/singstar-line.svg</file>
|
||||
|
||||
@@ -1077,7 +1077,7 @@ __forceinline void GSState::ApplyPRIM(u32 prim)
|
||||
else
|
||||
m_env.PRIM.PRIM = prim & 0x7;
|
||||
|
||||
if (m_prev_env.PRIM.U32[0] ^ m_env.PRIM.U32[0])
|
||||
if ((m_prev_env.PRIM.U32[0] ^ m_env.PRIM.U32[0]) & PRIM_REG_MASK)
|
||||
m_dirty_gs_regs |= (1 << DIRTY_REG_PRIM);
|
||||
else
|
||||
m_dirty_gs_regs &= ~(1<< DIRTY_REG_PRIM);
|
||||
@@ -1335,7 +1335,7 @@ void GSState::GIFRegHandlerTEX0(const GIFReg* RESTRICT r)
|
||||
|
||||
if (i == m_prev_env.PRIM.CTXT)
|
||||
{
|
||||
if (m_prev_env.CTXT[i].MIPTBP1.U64 ^ mip_tbp1.U64)
|
||||
if ((m_prev_env.CTXT[i].MIPTBP1.U64 ^ mip_tbp1.U64) & MIPTBP_REG_MASK)
|
||||
m_dirty_gs_regs |= (1 << DIRTY_REG_MIPTBP1);
|
||||
else
|
||||
m_dirty_gs_regs &= ~(1 << DIRTY_REG_MIPTBP1);
|
||||
@@ -1354,7 +1354,7 @@ void GSState::GIFRegHandlerCLAMP(const GIFReg* RESTRICT r)
|
||||
|
||||
if (i == m_prev_env.PRIM.CTXT)
|
||||
{
|
||||
if (m_prev_env.CTXT[i].CLAMP.U64 ^ m_env.CTXT[i].CLAMP.U64)
|
||||
if ((m_prev_env.CTXT[i].CLAMP.U64 ^ m_env.CTXT[i].CLAMP.U64) & CLAMP_REG_MASK)
|
||||
m_dirty_gs_regs |= (1 << DIRTY_REG_CLAMP);
|
||||
else
|
||||
m_dirty_gs_regs &= ~(1 << DIRTY_REG_CLAMP);
|
||||
@@ -1379,7 +1379,7 @@ void GSState::GIFRegHandlerTEX1(const GIFReg* RESTRICT r)
|
||||
|
||||
if (i == m_prev_env.PRIM.CTXT)
|
||||
{
|
||||
if (m_prev_env.CTXT[i].TEX1.U64 ^ m_env.CTXT[i].TEX1.U64)
|
||||
if ((m_prev_env.CTXT[i].TEX1.U64 ^ m_env.CTXT[i].TEX1.U64) & TEX1_REG_MASK)
|
||||
m_dirty_gs_regs |= (1 << DIRTY_REG_TEX1);
|
||||
else
|
||||
m_dirty_gs_regs &= ~(1 << DIRTY_REG_TEX1);
|
||||
@@ -1411,11 +1411,11 @@ void GSState::GIFRegHandlerXYOFFSET(const GIFReg* RESTRICT r)
|
||||
{
|
||||
GL_REG("XYOFFSET_%d = 0x%x_%x", i, r->U32[1], r->U32[0]);
|
||||
|
||||
const u64 r_masked = r->U64 & 0x0000FFFF0000FFFFu;
|
||||
const u64 r_masked = r->U64 & XYOFFSET_REG_MASK;
|
||||
|
||||
if (i == m_prev_env.PRIM.CTXT)
|
||||
{
|
||||
if (m_prev_env.CTXT[i].XYOFFSET.U64 != r_masked)
|
||||
if ((m_prev_env.CTXT[i].XYOFFSET.U64 ^ r_masked) & XYOFFSET_REG_MASK)
|
||||
m_dirty_gs_regs |= (1 << DIRTY_REG_XYOFFSET);
|
||||
else
|
||||
m_dirty_gs_regs &= ~(1 << DIRTY_REG_XYOFFSET);
|
||||
@@ -1450,7 +1450,7 @@ void GSState::GIFRegHandlerPRMODE(const GIFReg* RESTRICT r)
|
||||
m_env.PRIM = r->PRMODE;
|
||||
m_env.PRIM.PRIM = _PRIM;
|
||||
|
||||
if (m_prev_env.PRIM.U32[0] ^ m_env.PRIM.U32[0])
|
||||
if ((m_prev_env.PRIM.U32[0] ^ m_env.PRIM.U32[0]) & PRIM_REG_MASK)
|
||||
m_dirty_gs_regs |= (1 << DIRTY_REG_PRIM);
|
||||
else
|
||||
m_dirty_gs_regs &= ~(1 << DIRTY_REG_PRIM);
|
||||
@@ -1487,7 +1487,7 @@ void GSState::GIFRegHandlerMIPTBP1(const GIFReg* RESTRICT r)
|
||||
|
||||
if (i == m_prev_env.PRIM.CTXT)
|
||||
{
|
||||
if (m_prev_env.CTXT[i].MIPTBP1.U64 != m_env.CTXT[i].MIPTBP1.U64)
|
||||
if ((m_prev_env.CTXT[i].MIPTBP1.U64 ^ m_env.CTXT[i].MIPTBP1.U64) & MIPTBP_REG_MASK)
|
||||
m_dirty_gs_regs |= (1 << DIRTY_REG_MIPTBP1);
|
||||
else
|
||||
m_dirty_gs_regs &= ~(1 << DIRTY_REG_MIPTBP1);
|
||||
@@ -1503,7 +1503,7 @@ void GSState::GIFRegHandlerMIPTBP2(const GIFReg* RESTRICT r)
|
||||
|
||||
if (i == m_prev_env.PRIM.CTXT)
|
||||
{
|
||||
if (m_prev_env.CTXT[i].MIPTBP2.U64 != m_env.CTXT[i].MIPTBP2.U64)
|
||||
if ((m_prev_env.CTXT[i].MIPTBP2.U64 ^ m_env.CTXT[i].MIPTBP2.U64) & MIPTBP_REG_MASK)
|
||||
m_dirty_gs_regs |= (1 << DIRTY_REG_MIPTBP2);
|
||||
else
|
||||
m_dirty_gs_regs &= ~(1 << DIRTY_REG_MIPTBP2);
|
||||
@@ -1516,7 +1516,7 @@ void GSState::GIFRegHandlerTEXA(const GIFReg* RESTRICT r)
|
||||
|
||||
m_env.TEXA = r->TEXA;
|
||||
|
||||
if (m_prev_env.TEXA != m_env.TEXA)
|
||||
if ((m_prev_env.TEXA.U64 ^ m_env.TEXA.U64) & TEXA_REG_MASK)
|
||||
m_dirty_gs_regs |= (1 << DIRTY_REG_TEXA);
|
||||
else
|
||||
m_dirty_gs_regs &= ~(1 << DIRTY_REG_TEXA);
|
||||
@@ -1528,7 +1528,7 @@ void GSState::GIFRegHandlerFOGCOL(const GIFReg* RESTRICT r)
|
||||
|
||||
m_env.FOGCOL = r->FOGCOL;
|
||||
|
||||
if (m_prev_env.FOGCOL != m_env.FOGCOL)
|
||||
if ((m_prev_env.FOGCOL.U32[0] ^ m_env.FOGCOL.U32[0]) & FOGCOL_REG_MASK)
|
||||
m_dirty_gs_regs |= (1 << DIRTY_REG_FOGCOL);
|
||||
else
|
||||
m_dirty_gs_regs &= ~(1 << DIRTY_REG_FOGCOL);
|
||||
@@ -1548,7 +1548,7 @@ void GSState::GIFRegHandlerSCISSOR(const GIFReg* RESTRICT r)
|
||||
{
|
||||
if (i == m_prev_env.PRIM.CTXT)
|
||||
{
|
||||
if (m_prev_env.CTXT[i].SCISSOR.U64 != r->SCISSOR.U64)
|
||||
if ((m_prev_env.CTXT[i].SCISSOR.U64 ^ r->SCISSOR.U64) & SCISSOR_REG_MASK)
|
||||
m_dirty_gs_regs |= (1 << DIRTY_REG_SCISSOR);
|
||||
else
|
||||
m_dirty_gs_regs &= ~(1 << DIRTY_REG_SCISSOR);
|
||||
@@ -1579,7 +1579,7 @@ void GSState::GIFRegHandlerALPHA(const GIFReg* RESTRICT r)
|
||||
|
||||
if (i == m_prev_env.PRIM.CTXT)
|
||||
{
|
||||
if (m_prev_env.CTXT[i].ALPHA.U64 != m_env.CTXT[i].ALPHA.U64)
|
||||
if ((m_prev_env.CTXT[i].ALPHA.U64 ^ m_env.CTXT[i].ALPHA.U64) & ALPHA_REG_MASK)
|
||||
m_dirty_gs_regs |= (1 << DIRTY_REG_ALPHA);
|
||||
else
|
||||
m_dirty_gs_regs &= ~(1 << DIRTY_REG_ALPHA);
|
||||
@@ -1590,7 +1590,7 @@ void GSState::GIFRegHandlerDIMX(const GIFReg* RESTRICT r)
|
||||
{
|
||||
m_env.DIMX = r->DIMX;
|
||||
|
||||
if (m_prev_env.DIMX != m_env.DIMX)
|
||||
if ((m_prev_env.DIMX.U64 ^ m_env.DIMX.U64) & DIMX_REG_MASK)
|
||||
m_dirty_gs_regs |= (1 << DIRTY_REG_DIMX);
|
||||
else
|
||||
m_dirty_gs_regs &= ~(1 << DIRTY_REG_DIMX);
|
||||
@@ -1600,7 +1600,7 @@ void GSState::GIFRegHandlerDTHE(const GIFReg* RESTRICT r)
|
||||
{
|
||||
m_env.DTHE = r->DTHE;
|
||||
|
||||
if (m_prev_env.DTHE != m_env.DTHE)
|
||||
if (m_prev_env.DTHE.DTHE != m_env.DTHE.DTHE)
|
||||
m_dirty_gs_regs |= (1 << DIRTY_REG_DTHE);
|
||||
else
|
||||
m_dirty_gs_regs &= ~(1 << DIRTY_REG_DTHE);
|
||||
@@ -1610,7 +1610,7 @@ void GSState::GIFRegHandlerCOLCLAMP(const GIFReg* RESTRICT r)
|
||||
{
|
||||
m_env.COLCLAMP = r->COLCLAMP;
|
||||
|
||||
if (m_prev_env.COLCLAMP != m_env.COLCLAMP)
|
||||
if (m_prev_env.COLCLAMP.CLAMP != m_env.COLCLAMP.CLAMP)
|
||||
m_dirty_gs_regs |= (1 << DIRTY_REG_COLCLAMP);
|
||||
else
|
||||
m_dirty_gs_regs &= ~(1 << DIRTY_REG_COLCLAMP);
|
||||
@@ -1623,7 +1623,7 @@ void GSState::GIFRegHandlerTEST(const GIFReg* RESTRICT r)
|
||||
|
||||
if (i == m_prev_env.PRIM.CTXT)
|
||||
{
|
||||
if (m_prev_env.CTXT[i].TEST != m_env.CTXT[i].TEST)
|
||||
if ((m_prev_env.CTXT[i].TEST.U32[0] ^ m_env.CTXT[i].TEST.U32[0]) & TEST_REG_MASK)
|
||||
m_dirty_gs_regs |= (1 << DIRTY_REG_TEST);
|
||||
else
|
||||
m_dirty_gs_regs &= ~(1 << DIRTY_REG_TEST);
|
||||
@@ -1634,7 +1634,7 @@ void GSState::GIFRegHandlerPABE(const GIFReg* RESTRICT r)
|
||||
{
|
||||
m_env.PABE = r->PABE;
|
||||
|
||||
if (m_prev_env.PABE != m_env.PABE)
|
||||
if (m_prev_env.PABE.PABE != m_env.PABE.PABE)
|
||||
m_dirty_gs_regs |= (1 << DIRTY_REG_PABE);
|
||||
else
|
||||
m_dirty_gs_regs &= ~(1 << DIRTY_REG_PABE);
|
||||
@@ -1647,7 +1647,7 @@ void GSState::GIFRegHandlerFBA(const GIFReg* RESTRICT r)
|
||||
|
||||
if (i == m_prev_env.PRIM.CTXT)
|
||||
{
|
||||
if (m_prev_env.CTXT[i].FBA != m_env.CTXT[i].FBA)
|
||||
if (m_prev_env.CTXT[i].FBA.FBA != m_env.CTXT[i].FBA.FBA)
|
||||
m_dirty_gs_regs |= (1 << DIRTY_REG_FBA);
|
||||
else
|
||||
m_dirty_gs_regs &= ~(1 << DIRTY_REG_FBA);
|
||||
@@ -1701,7 +1701,7 @@ void GSState::GIFRegHandlerFRAME(const GIFReg* RESTRICT r)
|
||||
|
||||
if (i == m_prev_env.PRIM.CTXT)
|
||||
{
|
||||
if (m_prev_env.CTXT[i].FRAME != m_env.CTXT[i].FRAME)
|
||||
if ((m_prev_env.CTXT[i].FRAME.U64 ^ m_env.CTXT[i].FRAME.U64) & FRAME_REG_MASK)
|
||||
m_dirty_gs_regs |= (1 << DIRTY_REG_FRAME);
|
||||
else
|
||||
m_dirty_gs_regs &= ~(1 << DIRTY_REG_FRAME);
|
||||
@@ -1736,7 +1736,7 @@ void GSState::GIFRegHandlerZBUF(const GIFReg* RESTRICT r)
|
||||
|
||||
if (i == m_prev_env.PRIM.CTXT)
|
||||
{
|
||||
if (m_prev_env.CTXT[i].ZBUF != m_env.CTXT[i].ZBUF)
|
||||
if ((m_prev_env.CTXT[i].ZBUF.U64 ^ m_env.CTXT[i].ZBUF.U64) & ZBUF_REG_MASK)
|
||||
m_dirty_gs_regs |= (1 << DIRTY_REG_ZBUF);
|
||||
else
|
||||
m_dirty_gs_regs &= ~(1 << DIRTY_REG_ZBUF);
|
||||
@@ -1919,7 +1919,7 @@ inline bool GSState::TestDrawChanged()
|
||||
// Check if PRIM has changed we need to check if it's just a different triangle or the context is changing.
|
||||
if (m_dirty_gs_regs & (1 << DIRTY_REG_PRIM))
|
||||
{
|
||||
u32 prim_mask = 0x7ff;
|
||||
u32 prim_mask = PRIM_REG_MASK;
|
||||
|
||||
if (GSUtil::GetPrimClass(m_prev_env.PRIM.PRIM) == GSUtil::GetPrimClass(m_env.PRIM.PRIM))
|
||||
prim_mask &= ~0x7;
|
||||
@@ -3994,7 +3994,188 @@ void GSState::CalculatePrimitiveCoversWithoutGaps()
|
||||
m_primitive_covers_without_gaps = SpriteDrawWithoutGaps() ? (m_primitive_covers_without_gaps == GapsFound ? SpriteNoGaps : m_primitive_covers_without_gaps) : GapsFound;
|
||||
}
|
||||
|
||||
__forceinline bool GSState::IsAutoFlushDraw(u32 prim)
|
||||
__forceinline bool GSState::EarlyDetectShuffle(u32 prim)
|
||||
{
|
||||
// We only handle sprites here and need one sprite in the queue.
|
||||
// Texture mapping must be enabled for a shuffle.
|
||||
if (m_index.tail < 2 || prim != GS_SPRITE || !PRIM->TME)
|
||||
return false;
|
||||
|
||||
const GSVertex* RESTRICT vertex = &m_vertex.buff[0];
|
||||
const u16* RESTRICT index = &m_index.buff[0];
|
||||
const GSVector4i& o = m_xyof;
|
||||
|
||||
if (GSLocalMemory::m_psm[m_context->FRAME.PSM].bpp == 16 && GSLocalMemory::m_psm[m_context->TEX0.PSM].bpp == 16)
|
||||
{
|
||||
// Handle shuffles where the source and destination are both 16 bits.
|
||||
|
||||
const int x0 = static_cast<int>(vertex[index[0]].XYZ.X) - static_cast<int>(m_context->XYOFFSET.OFX);
|
||||
const int x1 = static_cast<int>(vertex[index[0]].XYZ.X) - static_cast<int>(m_context->XYOFFSET.OFX);
|
||||
const int xn = static_cast<int>(m_v.XYZ.X) - static_cast<int>(static_cast<int>(m_context->XYOFFSET.OFX));
|
||||
|
||||
int u0, un;
|
||||
if (PRIM->FST)
|
||||
{
|
||||
u0 = static_cast<int>(vertex[index[0]].U);
|
||||
un = static_cast<int>(m_v.U);
|
||||
}
|
||||
else
|
||||
{
|
||||
const float q0 = vertex[index[0]].RGBAQ.Q == 0.0f ? FLT_MIN : vertex[index[0]].RGBAQ.Q;
|
||||
u0 = static_cast<int>((1 << m_context->TEX0.TW) * (vertex[index[0]].ST.S / q0) * 16.0f);
|
||||
const float qn = m_v.RGBAQ.Q == 0.0f ? FLT_MIN : m_v.RGBAQ.Q;
|
||||
un = static_cast<int>((1 << m_context->TEX0.TW) * (m_v.ST.S / qn) * 16.0f);
|
||||
}
|
||||
|
||||
// Check that the X-U offsets are the same for the first and current vertex and
|
||||
// that the width of the first sprite is at most 16 pixels.
|
||||
return std::abs(u0 - x0) == std::abs(un - xn) && std::abs(x1 - x0) <= 0x100;
|
||||
}
|
||||
|
||||
if (GSLocalMemory::m_psm[m_context->FRAME.PSM].bpp == 16 && GSLocalMemory::m_psm[m_context->TEX0.PSM].bpp == 32)
|
||||
{
|
||||
// Handle shuffles where the source is 32/24 bits and destination is 16 bits.
|
||||
// Example: The Godfather.
|
||||
|
||||
// These shuffles usually mask R and G (lower 10 bits in 16 bit format) so that they
|
||||
// write only to B and A (top 6 bits in 16 bit format).
|
||||
if (GSUtil::GetChannelMask(m_context->FRAME.PSM, m_context->FRAME.FBMSK) != 0xC)
|
||||
return false;
|
||||
|
||||
const int x0 = static_cast<int>(vertex[index[0]].XYZ.X) - static_cast<int>(m_context->XYOFFSET.OFX);
|
||||
const int y0 = static_cast<int>(vertex[index[0]].XYZ.Y) - static_cast<int>(m_context->XYOFFSET.OFY);
|
||||
const int x1 = static_cast<int>(vertex[index[1]].XYZ.X) - static_cast<int>(m_context->XYOFFSET.OFX);
|
||||
const int y1 = static_cast<int>(vertex[index[1]].XYZ.Y) - static_cast<int>(m_context->XYOFFSET.OFY);
|
||||
|
||||
int u0, v0, u1, v1;
|
||||
|
||||
if (PRIM->FST)
|
||||
{
|
||||
u0 = static_cast<int>(vertex[index[0]].U);
|
||||
v0 = static_cast<int>(vertex[index[0]].V);
|
||||
u1 = static_cast<int>(vertex[index[1]].U);
|
||||
v1 = static_cast<int>(vertex[index[1]].V);
|
||||
}
|
||||
else
|
||||
{
|
||||
const float q0 = vertex[index[0]].RGBAQ.Q == 0.0f ? FLT_MIN : vertex[index[0]].RGBAQ.Q;
|
||||
u0 = static_cast<int>((1 << m_context->TEX0.TW) * (vertex[index[0]].ST.S / q0) * 16.0f);
|
||||
v0 = static_cast<int>((1 << m_context->TEX0.TH) * (vertex[index[0]].ST.T / q0) * 16.0f);
|
||||
const float q1 = vertex[index[1]].RGBAQ.Q == 0.0f ? FLT_MIN : vertex[index[1]].RGBAQ.Q;
|
||||
u1 = static_cast<int>((1 << m_context->TEX0.TW) * (vertex[index[1]].ST.S / q0) * 16.0f);
|
||||
v1 = static_cast<int>((1 << m_context->TEX0.TH) * (vertex[index[1]].ST.T / q0) * 16.0f);
|
||||
}
|
||||
|
||||
// Check that the source and destination sprite are exactly 8 pixel squares.
|
||||
// We do not use the current vertex in this check because it doesn't have a
|
||||
// clean correspondence with the first shuffle for 32->16 bit shuffles
|
||||
// (the coordinates manually swizzle between 32 and 16 bits).
|
||||
const bool const_spacing =
|
||||
(std::abs(x1 - x0) == 0x80) && (std::abs(y1 - y0) == 0x80) &&
|
||||
(std::abs(u1 - u0) == 0x80) && (std::abs(v1 - v0) == 0x80);
|
||||
|
||||
// The purpose of these shuffles is to write the alpha channel,
|
||||
// so the coordinates should write to upper 16 bits regions only.
|
||||
const bool write_ba = (std::min(x0, x1) & 0x80) != 0;
|
||||
|
||||
return const_spacing && write_ba;
|
||||
}
|
||||
|
||||
if (GSLocalMemory::m_psm[m_context->FRAME.PSM].bpp == 32 && GSLocalMemory::m_psm[m_context->TEX0.PSM].bpp == 16)
|
||||
{
|
||||
// Handle shuffles where the source is 16 bits and destination is 32/16 bits.
|
||||
// Example: DT Racer.
|
||||
|
||||
// These shuffles usually mask RGB (lower 24 bits in 32 bit format) so that they
|
||||
// write only to A.
|
||||
if (GSUtil::GetChannelMask(m_context->FRAME.PSM, m_context->FRAME.FBMSK) != 8)
|
||||
return false;
|
||||
|
||||
const int x0 = static_cast<int>(vertex[index[0]].XYZ.X) - static_cast<int>(m_context->XYOFFSET.OFX);
|
||||
const int y0 = static_cast<int>(vertex[index[0]].XYZ.Y) - static_cast<int>(m_context->XYOFFSET.OFY);
|
||||
const int x1 = static_cast<int>(vertex[index[1]].XYZ.X) - static_cast<int>(m_context->XYOFFSET.OFX);
|
||||
const int y1 = static_cast<int>(vertex[index[1]].XYZ.Y) - static_cast<int>(m_context->XYOFFSET.OFY);
|
||||
|
||||
int u0, v0, u1, v1;
|
||||
|
||||
if (PRIM->FST)
|
||||
{
|
||||
u0 = static_cast<int>(vertex[index[0]].U);
|
||||
v0 = static_cast<int>(vertex[index[0]].V);
|
||||
u1 = static_cast<int>(vertex[index[1]].U);
|
||||
v1 = static_cast<int>(vertex[index[1]].V);
|
||||
}
|
||||
else
|
||||
{
|
||||
const float q0 = vertex[index[0]].RGBAQ.Q == 0.0f ? FLT_MIN : vertex[index[0]].RGBAQ.Q;
|
||||
u0 = static_cast<int>((1 << m_context->TEX0.TW) * (vertex[index[0]].ST.S / q0) * 16.0f);
|
||||
v0 = static_cast<int>((1 << m_context->TEX0.TH) * (vertex[index[0]].ST.T / q0) * 16.0f);
|
||||
const float q1 = vertex[index[1]].RGBAQ.Q == 0.0f ? FLT_MIN : vertex[index[1]].RGBAQ.Q;
|
||||
u1 = static_cast<int>((1 << m_context->TEX0.TW) * (vertex[index[1]].ST.S / q0) * 16.0f);
|
||||
v1 = static_cast<int>((1 << m_context->TEX0.TH) * (vertex[index[1]].ST.T / q0) * 16.0f);
|
||||
}
|
||||
|
||||
// Check that the source and destination sprite are exactly 8 pixel squares.
|
||||
// We do not use the current vertex in this check because it doesn't have a
|
||||
// clean correspondence with the first shuffle for 32->16 bit shuffles
|
||||
// (the coordinates manually swizzle between 32 and 16 bits).
|
||||
const bool const_spacing =
|
||||
(std::abs(x1 - x0) == 0x80) && (std::abs(y1 - y0) == 0x80) &&
|
||||
(std::abs(u1 - u0) == 0x80) && (std::abs(v1 - v0) == 0x80);
|
||||
|
||||
// The purpose of these shuffles is to read the green channel,
|
||||
// so the coordinates should read the lower 16 bits only.
|
||||
const bool read_rg = (std::min(u0, u1) & 0x80) == 0;
|
||||
|
||||
return const_spacing && read_rg;
|
||||
}
|
||||
|
||||
if (m_context->TEX0.PSM == PSMT8)
|
||||
{
|
||||
// Handle channel shuffles.
|
||||
|
||||
// Heuristics to detect channel shuffle based on first sprite and clamp mode.
|
||||
const auto CheckWidthOrClampMode = [this]() -> bool {
|
||||
const GSVertex* v = &m_vertex.buff[0];
|
||||
|
||||
const int draw_width = std::abs(v[1].XYZ.X - v[0].XYZ.X) >> 4;
|
||||
const int draw_height = std::abs(v[1].XYZ.Y - v[0].XYZ.Y) >> 4;
|
||||
|
||||
// Checks if using region clamp or region repeat for U or V.
|
||||
// Might used used when the sprites are 16 pixels wide.
|
||||
const bool clamp_region = ((m_context->CLAMP.WMS | m_context->CLAMP.WMT) & 0x2) != 0;
|
||||
|
||||
// Channel shuffles usually draw 8 x 2 sprites.
|
||||
const bool draw_match = (draw_height == 2) || (draw_width == 8);
|
||||
|
||||
return draw_match || clamp_region;
|
||||
};
|
||||
|
||||
const bool single_page_x = temp_draw_rect.width() <= 64;
|
||||
const bool single_page_y = temp_draw_rect.height() <= 64;
|
||||
if (single_page_x && single_page_y)
|
||||
{
|
||||
return CheckWidthOrClampMode();
|
||||
}
|
||||
else if (!single_page_x)
|
||||
{
|
||||
// Not a single page in width.
|
||||
return false;
|
||||
}
|
||||
|
||||
// WRC 4 does channel shuffles in vertical strips. So check for page alignment.
|
||||
// Texture TBW should also be twice the framebuffer FBW, because the page is twice as wide.
|
||||
if (m_context->TEX0.TBW == (m_context->FRAME.FBW * 2) &&
|
||||
GSLocalMemory::IsPageAligned(m_context->FRAME.PSM, temp_draw_rect))
|
||||
{
|
||||
return CheckWidthOrClampMode();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
__forceinline bool GSState::IsAutoFlushDraw(u32 prim, int& tex_layer)
|
||||
{
|
||||
if (!PRIM->TME || (GSConfig.UserHacks_AutoFlush == GSHWAutoFlushLevel::SpritesOnly && prim != GS_SPRITE))
|
||||
return false;
|
||||
@@ -4004,24 +4185,56 @@ __forceinline bool GSState::IsAutoFlushDraw(u32 prim)
|
||||
return false;
|
||||
|
||||
// Try to detect shuffles, because these will not autoflush, they by design clash.
|
||||
if (GSLocalMemory::m_psm[m_context->FRAME.PSM].bpp == 16 && GSLocalMemory::m_psm[m_context->TEX0.PSM].bpp == 16)
|
||||
{
|
||||
// Pretty confident here...
|
||||
GSVertex* buffer = &m_vertex.buff[0];
|
||||
const bool const_spacing = std::abs(buffer[m_index.buff[0]].U - buffer[m_index.buff[0]].XYZ.X) == std::abs(m_v.U - m_v.XYZ.X) && std::abs(buffer[m_index.buff[1]].XYZ.X - buffer[m_index.buff[0]].XYZ.X) <= 256; // Lequal to 16 pixels apart.
|
||||
if (EarlyDetectShuffle(prim))
|
||||
return false;
|
||||
|
||||
if (const_spacing)
|
||||
return false;
|
||||
// Check if one of the texture being used is the same as the FRAME or ZBUF.
|
||||
// In the case of possible mip-mapping, we need to check all possible layers.
|
||||
bool frame_addr_hit = false;
|
||||
bool zbuf_addr_hit = false;
|
||||
const bool possible_mip_map = m_context->TEX1.MXL > 0 && m_context->TEX1.MMIN >= 2 && m_context->TEX1.MMIN <= 5;
|
||||
int min_possible_layer = 0;
|
||||
int max_possible_layer = 0;
|
||||
if (possible_mip_map)
|
||||
{
|
||||
if (m_context->TEX1.LCM)
|
||||
{
|
||||
// Fixed LOD.
|
||||
min_possible_layer = std::clamp(m_context->TEX1.K >> 4, 0, static_cast<int>(m_context->TEX1.MXL));
|
||||
max_possible_layer = std::clamp((m_context->TEX1.K + 0xF) >> 4, 0, static_cast<int>(m_context->TEX1.MXL));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Variable LOD based on vertex Q.
|
||||
max_possible_layer = static_cast<int>(m_context->TEX1.MXL);
|
||||
}
|
||||
}
|
||||
|
||||
GIFRegTEX0 TEX0_hit;
|
||||
for (tex_layer = min_possible_layer; tex_layer <= max_possible_layer; tex_layer++)
|
||||
{
|
||||
TEX0_hit = GetTex0Layer(tex_layer);
|
||||
if (TEX0_hit.TBP0 == m_context->FRAME.Block())
|
||||
{
|
||||
frame_addr_hit = true;
|
||||
break;
|
||||
}
|
||||
if (TEX0_hit.TBP0 == m_context->ZBUF.Block())
|
||||
{
|
||||
zbuf_addr_hit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const u32 frame_mask = GSLocalMemory::m_psm[m_context->FRAME.PSM].fmsk;
|
||||
const bool frame_hit = m_context->FRAME.Block() == m_context->TEX0.TBP0 && !(m_context->TEST.ATE && m_context->TEST.ATST == 0 && m_context->TEST.AFAIL == 2) && ((m_context->FRAME.FBMSK & frame_mask) != frame_mask);
|
||||
const bool frame_hit = frame_addr_hit && !(m_context->TEST.ATE && m_context->TEST.ATST == 0 && m_context->TEST.AFAIL == 2) && ((m_context->FRAME.FBMSK & frame_mask) != frame_mask);
|
||||
// There's a strange behaviour we need to test on a PS2 here, if the FRAME is a Z format, like Powerdrome something swaps over, and it seems Alpha Fail of "FB Only" writes to the Z.. it's odd.
|
||||
const bool z_needed = !(m_context->TEST.ATE && m_context->TEST.ATST == 0 && m_context->TEST.AFAIL != 2) && !m_context->ZBUF.ZMSK;
|
||||
const bool zbuf_hit = (m_context->ZBUF.Block() == m_context->TEX0.TBP0) && z_needed;
|
||||
const bool zbuf_hit = zbuf_addr_hit && z_needed;
|
||||
const u32 frame_z_psm = frame_hit ? m_context->FRAME.PSM : m_context->ZBUF.PSM;
|
||||
const u32 frame_z_bp = frame_hit ? m_context->FRAME.Block() : m_context->ZBUF.Block();
|
||||
|
||||
if ((frame_hit || zbuf_hit) && GSUtil::HasSharedBits(frame_z_bp, frame_z_psm, m_context->TEX0.TBP0, m_context->TEX0.PSM))
|
||||
if ((frame_hit || zbuf_hit) && GSUtil::HasSharedBits(frame_z_bp, frame_z_psm, TEX0_hit.TBP0, TEX0_hit.PSM))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@@ -4109,7 +4322,8 @@ __forceinline void GSState::HandleAutoFlush()
|
||||
// To briefly explain what's going on here, what we are checking for is draws over a texture when the source and destination are themselves.
|
||||
// Because one page of the texture gets buffered in the Texture Cache (the PS2's one) if any of those pixels are overwritten, you still read the old data.
|
||||
// So we need to calculate if a page boundary is being crossed for the format it is in and if the same part of the texture being written and read inside the draw.
|
||||
if (IsAutoFlushDraw(prim))
|
||||
int tex_layer = 0;
|
||||
if (IsAutoFlushDraw(prim, tex_layer))
|
||||
{
|
||||
int n = 1;
|
||||
u32 buff[3];
|
||||
@@ -4144,23 +4358,37 @@ __forceinline void GSState::HandleAutoFlush()
|
||||
break;
|
||||
}
|
||||
|
||||
const bool possible_mipmap = m_context->TEX1.MXL > 0 && m_context->TEX1.MMIN >= 2 && m_context->TEX1.MMIN <= 5;
|
||||
const float K = static_cast<float>(m_context->TEX1.K) / 16;
|
||||
const float powL = static_cast<float>(1 << m_context->TEX1.L);
|
||||
|
||||
GSVector4i xy_coord;
|
||||
GSVector4i tex_coord;
|
||||
float vert_lod = K;
|
||||
|
||||
// Prepare the currently processed vertex.
|
||||
xy_coord.x = (static_cast<int>(m_v.XYZ.X) - static_cast<int>(m_context->XYOFFSET.OFX)) >> 4;
|
||||
xy_coord.y = (static_cast<int>(m_v.XYZ.Y) - static_cast<int>(m_context->XYOFFSET.OFY)) >> 4;
|
||||
if (PRIM->FST)
|
||||
{
|
||||
tex_coord.x = m_v.U >> 4;
|
||||
tex_coord.y = m_v.V >> 4;
|
||||
tex_coord.x = (m_v.U >> 4) >> tex_layer;
|
||||
tex_coord.y = (m_v.V >> 4) >> tex_layer;
|
||||
}
|
||||
else
|
||||
{
|
||||
const float s = std::min((m_v.ST.S / m_v.RGBAQ.Q), 1.0f);
|
||||
const float t = std::min((m_v.ST.T / m_v.RGBAQ.Q), 1.0f);
|
||||
|
||||
tex_coord.x = static_cast<int>((1 << m_context->TEX0.TW) * s);
|
||||
tex_coord.y = static_cast<int>((1 << m_context->TEX0.TH) * t);
|
||||
tex_coord.x = static_cast<int>((1 << m_context->TEX0.TW) * s) >> tex_layer;
|
||||
tex_coord.y = static_cast<int>((1 << m_context->TEX0.TH) * t) >> tex_layer;
|
||||
|
||||
if (possible_mipmap && !m_context->TEX1.LCM)
|
||||
vert_lod = -std::log2(std::abs(m_v.RGBAQ.Q)) * powL + K;
|
||||
}
|
||||
|
||||
GSVector4i xy_rect = xy_coord.xyxy();
|
||||
GSVector4i tex_rect = tex_coord.xyxy();
|
||||
GSVector2i lod_range = GSVector2i(static_cast<int>(std::floor(vert_lod)), static_cast<int>(std::ceil(vert_lod)));
|
||||
|
||||
const GSLocalMemory::psm_t tex_psm = GSLocalMemory::m_psm[m_context->TEX0.PSM];
|
||||
const GSLocalMemory::psm_t frame_psm = GSLocalMemory::m_psm[m_context->FRAME.PSM];
|
||||
@@ -4169,53 +4397,76 @@ __forceinline void GSState::HandleAutoFlush()
|
||||
{
|
||||
const GSVertex* v = &m_vertex.buff[buff[i]];
|
||||
|
||||
xy_coord.x = (static_cast<int>(v->XYZ.X) - static_cast<int>(m_context->XYOFFSET.OFX)) >> 4;
|
||||
xy_coord.y = (static_cast<int>(v->XYZ.Y) - static_cast<int>(m_context->XYOFFSET.OFY)) >> 4;
|
||||
if (PRIM->FST)
|
||||
{
|
||||
tex_coord.x = v->U >> 4;
|
||||
tex_coord.y = v->V >> 4;
|
||||
tex_coord.x = (v->U >> 4) >> tex_layer;
|
||||
tex_coord.y = (v->V >> 4) >> tex_layer;
|
||||
}
|
||||
else
|
||||
{
|
||||
const float s = std::min((v->ST.S / v->RGBAQ.Q), 1.0f);
|
||||
const float t = std::min((v->ST.T / v->RGBAQ.Q), 1.0f);
|
||||
|
||||
tex_coord.x = static_cast<int>(std::round((1 << m_context->TEX0.TW) * s));
|
||||
tex_coord.y = static_cast<int>(std::round((1 << m_context->TEX0.TH) * t));
|
||||
tex_coord.x = static_cast<int>(std::round((1 << m_context->TEX0.TW) * s)) >> tex_layer;
|
||||
tex_coord.y = static_cast<int>(std::round((1 << m_context->TEX0.TH) * t)) >> tex_layer;
|
||||
|
||||
if (possible_mipmap && !m_context->TEX1.LCM)
|
||||
vert_lod = -std::log2(std::abs(v->RGBAQ.Q)) * powL + K;
|
||||
}
|
||||
|
||||
xy_rect.x = std::min(xy_rect.x, xy_coord.x);
|
||||
xy_rect.z = std::max(xy_rect.z, xy_coord.x);
|
||||
xy_rect.y = std::min(xy_rect.y, xy_coord.y);
|
||||
xy_rect.w = std::max(xy_rect.w, xy_coord.y);
|
||||
tex_rect.x = std::min(tex_rect.x, tex_coord.x);
|
||||
tex_rect.z = std::max(tex_rect.z, tex_coord.x);
|
||||
tex_rect.y = std::min(tex_rect.y, tex_coord.y);
|
||||
tex_rect.w = std::max(tex_rect.w, tex_coord.y);
|
||||
lod_range.x = std::min(lod_range.x, static_cast<int>(std::floor(vert_lod)));
|
||||
lod_range.y = std::max(lod_range.y, static_cast<int>(std::ceil(vert_lod)));
|
||||
}
|
||||
|
||||
// If the current prim does not use the correct mipmap layer then we don't need to flush.
|
||||
if (possible_mipmap && !(lod_range.x <= tex_layer && tex_layer <= lod_range.y))
|
||||
return;
|
||||
|
||||
// If the draw was 1 line thick, make it larger as rects are exclusive of ends.
|
||||
if (xy_rect.x == xy_rect.z)
|
||||
xy_rect += GSVector4i::cxpr(0, 0, 1, 0);
|
||||
if (xy_rect.y == xy_rect.w)
|
||||
xy_rect += GSVector4i::cxpr(0, 0, 0, 1);
|
||||
if (tex_rect.x == tex_rect.z)
|
||||
tex_rect += GSVector4i::cxpr(0, 0, 1, 0);
|
||||
if (tex_rect.y == tex_rect.w)
|
||||
tex_rect += GSVector4i::cxpr(0, 0, 0, 1);
|
||||
|
||||
// If the current prim fails the scissor test then we don't need to flush.
|
||||
if (xy_rect.rintersect(m_context->scissor.in).rempty())
|
||||
return;
|
||||
|
||||
// Get the last texture position from the last draw.
|
||||
const GSVertex* v = &m_vertex.buff[m_index.buff[m_index.tail - 1]];
|
||||
|
||||
if (PRIM->FST)
|
||||
{
|
||||
tex_coord.x = v->U >> 4;
|
||||
tex_coord.y = v->V >> 4;
|
||||
tex_coord.x = (v->U >> 4) >> tex_layer;
|
||||
tex_coord.y = (v->V >> 4) >> tex_layer;
|
||||
}
|
||||
else
|
||||
{
|
||||
const float s = std::min((v->ST.S / v->RGBAQ.Q), 1.0f);
|
||||
const float t = std::min((v->ST.T / v->RGBAQ.Q), 1.0f);
|
||||
|
||||
tex_coord.x = static_cast<int>(std::round((1 << m_context->TEX0.TW) * s));
|
||||
tex_coord.y = static_cast<int>(std::round((1 << m_context->TEX0.TH) * t));
|
||||
tex_coord.x = static_cast<int>(std::round((1 << m_context->TEX0.TW) * s)) >> tex_layer;
|
||||
tex_coord.y = static_cast<int>(std::round((1 << m_context->TEX0.TH) * t)) >> tex_layer;
|
||||
}
|
||||
|
||||
const int clamp_minu = m_context->CLAMP.MINU;
|
||||
const int clamp_maxu = m_context->CLAMP.MAXU;
|
||||
const int clamp_minv = m_context->CLAMP.MINV;
|
||||
const int clamp_maxv = m_context->CLAMP.MAXV;
|
||||
const int clamp_minu = m_context->CLAMP.MINU >> tex_layer;
|
||||
const int clamp_maxu = m_context->CLAMP.MAXU >> tex_layer;
|
||||
const int clamp_minv = m_context->CLAMP.MINV >> tex_layer;
|
||||
const int clamp_maxv = m_context->CLAMP.MAXV >> tex_layer;
|
||||
|
||||
switch (m_context->CLAMP.WMS)
|
||||
{
|
||||
@@ -4351,7 +4602,7 @@ __forceinline void GSState::HandleAutoFlush()
|
||||
const int tex_width = (m_context->TEX0.TBW * 64) / tex_psm.pgs.x;
|
||||
if ((frame_width == tex_width) || ((tex_rect.w / tex_psm.pgs.y) <= 1 && frame_width >= tex_width))
|
||||
{
|
||||
tex_rect += GSVector4i(0, 0, tex_page_mask.z, tex_page_mask.w); // round up to the next page as we will be comparing by page.
|
||||
tex_rect += GSVector4i(0, 0, tex_psm.pgs.x - 1, tex_psm.pgs.y - 1); // round up to the next page as we will be comparing by page.
|
||||
//We know we've changed page, so let's set the dimension to cover the page they're in (for different pixel orders)
|
||||
tex_rect &= tex_page_mask;
|
||||
tex_rect = GSVector4i(tex_rect.x / tex_psm.pgs.x, tex_rect.y / tex_psm.pgs.y, tex_rect.z / tex_psm.pgs.x, tex_rect.w / tex_psm.pgs.y);
|
||||
@@ -4360,7 +4611,7 @@ __forceinline void GSState::HandleAutoFlush()
|
||||
const int frame_page_mask_y = ~(frame_psm.pgs.y - 1);
|
||||
const GSVector4i frame_page_mask = { frame_page_mask_x, frame_page_mask_y, frame_page_mask_x, frame_page_mask_y };
|
||||
GSVector4i area_out = temp_draw_rect;
|
||||
area_out += GSVector4i(0, 0, frame_page_mask.z, frame_page_mask.w); // round up to the next page as we will be comparing by page.
|
||||
area_out += GSVector4i(0, 0, frame_psm.pgs.x - 1, frame_psm.pgs.y - 1); // round up to the next page as we will be comparing by page.
|
||||
area_out &= frame_page_mask;
|
||||
area_out = GSVector4i(area_out.x / frame_psm.pgs.x, area_out.y / frame_psm.pgs.y, area_out.z / frame_psm.pgs.x, area_out.w / frame_psm.pgs.y);
|
||||
|
||||
|
||||
@@ -171,8 +171,9 @@ protected:
|
||||
void UpdateVertexKick();
|
||||
|
||||
void GrowVertexBuffer();
|
||||
bool IsAutoFlushDraw(u32 prim);
|
||||
bool IsAutoFlushDraw(u32 prim, int& tex_layer);
|
||||
template<u32 prim> void HandleAutoFlush();
|
||||
bool EarlyDetectShuffle(u32 prim);
|
||||
void CheckCLUTValidity(u32 prim);
|
||||
|
||||
template <u32 prim, bool auto_flush> void VertexKick(u32 skip);
|
||||
@@ -270,6 +271,20 @@ public:
|
||||
|
||||
static constexpr u32 STATE_VERSION = 9;
|
||||
|
||||
#define PRIM_REG_MASK 0x7FF
|
||||
#define MIPTBP_REG_MASK ((1ULL << 60) - 1ULL)
|
||||
#define CLAMP_REG_MASK ((1ULL << 44) - 1ULL)
|
||||
#define TEX1_REG_MASK 0xFFF001803FDULL
|
||||
#define XYOFFSET_REG_MASK 0x0000FFFF0000FFFFULL
|
||||
#define TEXA_REG_MASK 0xFF000080FFULL
|
||||
#define FOGCOL_REG_MASK 0xFFFFFF
|
||||
#define SCISSOR_REG_MASK 0x7FF07FF07FF07FFULL
|
||||
#define ALPHA_REG_MASK 0xFF000000FFULL
|
||||
#define DIMX_REG_MASK 0x7777777777777777ULL
|
||||
#define FRAME_REG_MASK 0xFFFFFFFF3F3F01FFULL
|
||||
#define ZBUF_REG_MASK 0x10F0001FFULL
|
||||
#define TEST_REG_MASK 0x7FFFF
|
||||
|
||||
enum REG_DIRTY
|
||||
{
|
||||
DIRTY_REG_ALPHA,
|
||||
|
||||
@@ -7663,21 +7663,6 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
||||
if ((!IsOpaque() || m_context->ALPHA.IsBlack()) && rt && ((m_conf.colormask.wrgba & 0x7) || (m_texture_shuffle && !m_copy_16bit_to_target_shuffle && !m_same_group_texture_shuffle)))
|
||||
{
|
||||
EmulateBlending(blend_alpha_min, blend_alpha_max, DATE, DATE_PRIMID, DATE_BARRIER, rt, can_scale_rt_alpha, new_scale_rt_alpha);
|
||||
|
||||
// Similar to IsRTWritten(), check if the rt will change.
|
||||
const bool no_rt = (!DATE && !m_conf.colormask.wrgba && !m_channel_shuffle);
|
||||
const bool no_ds = !m_conf.ds ||
|
||||
// Depth will be written through the RT.
|
||||
(!no_rt && m_cached_ctx.FRAME.FBP == m_cached_ctx.ZBUF.ZBP && !PRIM->TME && m_cached_ctx.ZBUF.ZMSK == 0 &&
|
||||
(m_cached_ctx.FRAME.FBMSK & GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].fmsk) == 0 && m_cached_ctx.TEST.ZTE) ||
|
||||
// No color or Z being written.
|
||||
(no_rt && m_cached_ctx.ZBUF.ZMSK != 0);
|
||||
|
||||
if (no_rt && no_ds)
|
||||
{
|
||||
GL_INS("HW: Late draw cancel EmulateBlending().");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -7695,6 +7680,21 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
||||
}
|
||||
}
|
||||
|
||||
// Similar to IsRTWritten(), check if the rt will change.
|
||||
const bool no_rt = !rt || !(DATE || m_conf.colormask.wrgba || m_channel_shuffle);
|
||||
const bool no_ds = !ds ||
|
||||
// Depth will be written through the RT.
|
||||
(!no_rt && m_cached_ctx.FRAME.FBP == m_cached_ctx.ZBUF.ZBP && !PRIM->TME && m_cached_ctx.ZBUF.ZMSK == 0 &&
|
||||
(m_cached_ctx.FRAME.FBMSK & GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].fmsk) == 0 && m_cached_ctx.TEST.ZTE) ||
|
||||
// No color or Z being written.
|
||||
(no_rt && m_cached_ctx.ZBUF.ZMSK != 0);
|
||||
|
||||
if (no_rt && no_ds)
|
||||
{
|
||||
GL_INS("HW: Late draw cancel DrawPrims().");
|
||||
return;
|
||||
}
|
||||
|
||||
// Always swap DATE with DATE_BARRIER if we have barriers on when alpha write is masked.
|
||||
// This is always enabled on vk/gl but not on dx11/12 as copies are slow so we can selectively enable it like now.
|
||||
if (DATE && !m_conf.colormask.wa && (m_conf.require_one_barrier || m_conf.require_full_barrier))
|
||||
|
||||
@@ -323,10 +323,11 @@ void GSDrawScanline::CSetupPrim(const GSVertexSW* vertex, const u16* index, cons
|
||||
{
|
||||
if (sel.iip)
|
||||
{
|
||||
constexpr VectorI mask16 = VectorI::cxpr(0xFFFF);
|
||||
#if _M_SSE >= 0x501
|
||||
GSVector4i::storel(&local.d8.c, GSVector4i(dscan.c * step_shift).xzyw().ps32());
|
||||
GSVector4i::storel(&local.d8.c, (GSVector4i(dscan.c * step_shift) & GSVector4i::cast(mask16)).xzyw().pu32());
|
||||
#else
|
||||
local.d4.c = GSVector4i(dscan.c * step_shift).xzyw().ps32();
|
||||
local.d4.c = (GSVector4i(dscan.c * step_shift) & mask16).xzyw().pu32();
|
||||
#endif
|
||||
VectorF dc(dscan.c);
|
||||
|
||||
@@ -335,8 +336,8 @@ void GSDrawScanline::CSetupPrim(const GSVertexSW* vertex, const u16* index, cons
|
||||
|
||||
for (int i = 0; i < vlen; i++)
|
||||
{
|
||||
VectorI r = VectorI(dr * shift[1 + i]).ps32();
|
||||
VectorI b = VectorI(db * shift[1 + i]).ps32();
|
||||
VectorI r = (VectorI(dr * shift[1 + i]) & mask16).pu32();
|
||||
VectorI b = (VectorI(db * shift[1 + i]) & mask16).pu32();
|
||||
|
||||
local.d[i].rb = r.upl16(b);
|
||||
}
|
||||
@@ -346,8 +347,8 @@ void GSDrawScanline::CSetupPrim(const GSVertexSW* vertex, const u16* index, cons
|
||||
|
||||
for (int i = 0; i < vlen; i++)
|
||||
{
|
||||
VectorI g = VectorI(dg * shift[1 + i]).ps32();
|
||||
VectorI a = VectorI(da * shift[1 + i]).ps32();
|
||||
VectorI g = (VectorI(dg * shift[1 + i]) & mask16).pu32();
|
||||
VectorI a = (VectorI(da * shift[1 + i]) & mask16).pu32();
|
||||
|
||||
local.d[i].ga = g.upl16(a);
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ void GSSetupPrimCodeGenerator::Generate()
|
||||
many_regs = isYmm && !m_sel.notest && needs_shift;
|
||||
|
||||
#ifdef _WIN64
|
||||
int needs_saving = many_regs ? 6 : m_sel.notest ? 0 : 2;
|
||||
int needs_saving = many_regs ? 7 : m_sel.notest ? 1 : 3;
|
||||
if (needs_saving)
|
||||
{
|
||||
sub(rsp, 8 + 16 * needs_saving);
|
||||
@@ -398,12 +398,17 @@ void GSSetupPrimCodeGenerator::Color()
|
||||
|
||||
broadcastf128(xym0, ptr[_dscan + offsetof(GSVertexSW, c)]);
|
||||
|
||||
// m_local.d4.c = GSVector4i(c * 4.0f).xzyw().ps32();
|
||||
// constexpr VectorI mask16 = VectorI::cxpr(0xFFFF);
|
||||
XYm mask16 = XYm(many_regs ? 12 : m_sel.notest ? 6 : 8);
|
||||
pcmpeqd(mask16, mask16);
|
||||
psrld(mask16, 16);
|
||||
|
||||
// local.d4.c = (GSVector4i(dscan.c * step_shift) & mask16).xzyw().pu32();
|
||||
THREEARG(mulps, xmm1, xmm0, xmm3);
|
||||
cvttps2dq(xmm1, xmm1);
|
||||
pshufd(xmm1, xmm1, _MM_SHUFFLE(3, 1, 2, 0));
|
||||
packssdw(xmm1, xmm1);
|
||||
pand(xym1, mask16);
|
||||
packusdw(xmm1, xmm1);
|
||||
if (isXmm)
|
||||
movdqa(_rip_local_d(c), xmm1);
|
||||
else
|
||||
@@ -419,23 +424,25 @@ void GSSetupPrimCodeGenerator::Color()
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : dsize); i++)
|
||||
{
|
||||
// GSVector4i r = GSVector4i(dr * m_shift[i]).ps32();
|
||||
// VectorI r = (VectorI(dr * shift[1 + i]) & mask16).pu32();
|
||||
|
||||
if (i < 4 || many_regs)
|
||||
THREEARG(mulps, xym0, XYm(4 + i), xym2);
|
||||
else
|
||||
vmulps(ymm0, ymm2, ptr[g_const.m_shift_256b[i + 1]]);
|
||||
cvttps2dq(xym0, xym0);
|
||||
packssdw(xym0, xym0);
|
||||
pand(xym0, mask16);
|
||||
packusdw(xym0, xym0);
|
||||
|
||||
// GSVector4i b = GSVector4i(db * m_shift[i]).ps32();
|
||||
// VectorI b = (VectorI(db * shift[1 + i]) & mask16).pu32();
|
||||
|
||||
if (i < 4 || many_regs)
|
||||
THREEARG(mulps, xym1, XYm(4 + i), xym3);
|
||||
else
|
||||
vmulps(ymm1, ymm3, ptr[g_const.m_shift_256b[i + 1]]);
|
||||
cvttps2dq(xym1, xym1);
|
||||
packssdw(xym1, xym1);
|
||||
pand(xym1, mask16);
|
||||
packusdw(xym1, xym1);
|
||||
|
||||
// m_local.d[i].rb = r.upl16(b);
|
||||
|
||||
@@ -455,23 +462,25 @@ void GSSetupPrimCodeGenerator::Color()
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : dsize); i++)
|
||||
{
|
||||
// GSVector4i g = GSVector4i(dg * m_shift[i]).ps32();
|
||||
// VectorI g = (VectorI(dg * shift[1 + i]) & mask16).pu32();
|
||||
|
||||
if (i < 4 || many_regs)
|
||||
THREEARG(mulps, xym0, XYm(4 + i), xym2);
|
||||
else
|
||||
vmulps(ymm0, ymm2, ptr[g_const.m_shift_256b[i + 1]]);
|
||||
cvttps2dq(xym0, xym0);
|
||||
packssdw(xym0, xym0);
|
||||
pand(xym0, mask16);
|
||||
packusdw(xym0, xym1);
|
||||
|
||||
// GSVector4i a = GSVector4i(da * m_shift[i]).ps32();
|
||||
// VectorI a = (VectorI(da * shift[1 + i]) & mask16).pu32();
|
||||
|
||||
if (i < 4 || many_regs)
|
||||
THREEARG(mulps, xym1, XYm(4 + i), xym3);
|
||||
else
|
||||
vmulps(ymm1, ymm3, ptr[g_const.m_shift_256b[i + 1]]);
|
||||
cvttps2dq(xym1, xym1);
|
||||
packssdw(xym1, xym1);
|
||||
pand(xym1, mask16);
|
||||
packusdw(xym1, xym1);
|
||||
|
||||
// m_local.d[i].ga = g.upl16(a);
|
||||
|
||||
|
||||
@@ -225,14 +225,13 @@ void GSSetupPrimCodeGenerator::Color()
|
||||
// GSVector4 c = dscan.c;
|
||||
armAsm->Ldr(v16, MemOperand(_dscan, offsetof(GSVertexSW, c)));
|
||||
|
||||
// m_local.d4.c = GSVector4i(c * 4.0f).xzyw().ps32();
|
||||
|
||||
// GSVector4i tmp = GSVector4i(dscan.c * step_shift).xzyw();
|
||||
// local.d4.c = tmp.uzp1_16(tmp); // Not currently in GSVector since that's mainly targeting x86 for now
|
||||
armAsm->Fmul(v2.V4S(), v16.V4S(), v3.V4S());
|
||||
armAsm->Fcvtzs(v2.V4S(), v2.V4S());
|
||||
armAsm->Rev64(_vscratch.V4S(), v2.V4S());
|
||||
armAsm->Uzp1(v2.V4S(), v2.V4S(), _vscratch.V4S());
|
||||
armAsm->Sqxtn(v2.V4H(), v2.V4S());
|
||||
armAsm->Dup(v2.V2D(), v2.V2D(), 0);
|
||||
armAsm->Uzp1(v2.V8H(), v2.V8H(), v2.V8H());
|
||||
armAsm->Str(v2, MemOperand(_locals, offsetof(GSScanlineLocalData, d4.c)));
|
||||
|
||||
// GSVector4 dr = c.xxxx();
|
||||
@@ -243,23 +242,18 @@ void GSSetupPrimCodeGenerator::Color()
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 4); i++)
|
||||
{
|
||||
// GSVector4i r = GSVector4i(dr * m_shift[i]).ps32();
|
||||
// VectorI r = VectorI(dr * shift[1 + i]);
|
||||
|
||||
armAsm->Fmul(v2.V4S(), v0.V4S(), VRegister(4 + i, kFormat4S));
|
||||
armAsm->Fcvtzs(v2.V4S(), v2.V4S());
|
||||
armAsm->Sqxtn(v2.V4H(), v2.V4S());
|
||||
armAsm->Dup(v2.V2D(), v2.V2D(), 0);
|
||||
|
||||
// GSVector4i b = GSVector4i(db * m_shift[i]).ps32();
|
||||
// VectorI b = VectorI(db * shift[1 + i]);
|
||||
|
||||
armAsm->Fmul(v3.V4S(), v1.V4S(), VRegister(4 + i, kFormat4S));
|
||||
armAsm->Fcvtzs(v3.V4S(), v3.V4S());
|
||||
armAsm->Sqxtn(v3.V4H(), v3.V4S());
|
||||
armAsm->Dup(v3.V2D(), v3.V2D(), 0);
|
||||
|
||||
// m_local.d[i].rb = r.upl16(b);
|
||||
|
||||
armAsm->Zip1(v2.V8H(), v2.V8H(), v3.V8H());
|
||||
// m_local.d[i].rb = r.trn1_16(b); // Not currently in GSVector since that's mainly targeting x86 for now
|
||||
armAsm->Trn1(v2.V8H(), v2.V8H(), v3.V8H());
|
||||
armAsm->Str(v2, _local(d[i].rb));
|
||||
}
|
||||
|
||||
@@ -273,23 +267,19 @@ void GSSetupPrimCodeGenerator::Color()
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 4); i++)
|
||||
{
|
||||
// GSVector4i g = GSVector4i(dg * m_shift[i]).ps32();
|
||||
// VectorI g = VectorI(dg * shift[1 + i]);
|
||||
|
||||
armAsm->Fmul(v2.V4S(), v0.V4S(), VRegister(4 + i, kFormat4S));
|
||||
armAsm->Fcvtzs(v2.V4S(), v2.V4S());
|
||||
armAsm->Sqxtn(v2.V4H(), v2.V4S());
|
||||
armAsm->Dup(v2.V2D(), v2.V2D(), 0);
|
||||
|
||||
// GSVector4i a = GSVector4i(da * m_shift[i]).ps32();
|
||||
// VectorI a = VectorI(da * shift[1 + i]);
|
||||
|
||||
armAsm->Fmul(v3.V4S(), v1.V4S(), VRegister(4 + i, kFormat4S));
|
||||
armAsm->Fcvtzs(v3.V4S(), v3.V4S());
|
||||
armAsm->Sqxtn(v3.V4H(), v3.V4S());
|
||||
armAsm->Dup(v3.V2D(), v3.V2D(), 0);
|
||||
|
||||
// m_local.d[i].ga = g.upl16(a);
|
||||
// m_local.d[i].ga = g.trn1_16(a); // Not currently in GSVector since that's mainly targeting x86 for now
|
||||
|
||||
armAsm->Zip1(v2.V8H(), v2.V8H(), v3.V8H());
|
||||
armAsm->Trn1(v2.V8H(), v2.V8H(), v3.V8H());
|
||||
armAsm->Str(v2, _local(d[i].ga));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "SIO/Memcard/MemoryCardFile.h"
|
||||
|
||||
#include "common/Assertions.h"
|
||||
#include "common/Error.h"
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/Path.h"
|
||||
#include "common/Timer.h"
|
||||
@@ -103,7 +104,10 @@ static void HotkeyLoadStateSlot(s32 slot)
|
||||
return;
|
||||
}
|
||||
|
||||
VMManager::LoadStateFromSlot(slot);
|
||||
Error error;
|
||||
if (!VMManager::LoadStateFromSlot(slot, false, &error))
|
||||
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_TRIANGLE_EXCLAMATION,
|
||||
error.GetDescription(), Host::OSD_INFO_DURATION);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -7602,65 +7602,17 @@ void FullscreenUI::DrawResumeStateSelector()
|
||||
|
||||
void FullscreenUI::DoLoadState(std::string path)
|
||||
{
|
||||
// Check for hardcore mode before loading state
|
||||
if (Achievements::IsHardcoreModeActive())
|
||||
{
|
||||
Achievements::ConfirmHardcoreModeDisableAsync(TRANSLATE("VMManager", "Loading state"),
|
||||
[path = std::move(path)](bool approved) {
|
||||
if (approved)
|
||||
DoLoadState(std::move(path));
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string filename = std::string(Path::GetFileName(path));
|
||||
s32 slot = -1;
|
||||
bool is_backup = false;
|
||||
|
||||
std::string base_filename = filename;
|
||||
if (filename.length() > 7 && filename.substr(filename.length() - 7) == ".backup")
|
||||
{
|
||||
is_backup = true;
|
||||
base_filename = filename.substr(0, filename.length() - 7);
|
||||
}
|
||||
|
||||
// Get slot number from filename (format: serial.crc.slot.p2s)
|
||||
const size_t last_dot = base_filename.rfind('.');
|
||||
const size_t second_last_dot = base_filename.rfind('.', last_dot - 1);
|
||||
if (last_dot != std::string::npos && second_last_dot != std::string::npos)
|
||||
{
|
||||
const std::string slot_str = base_filename.substr(second_last_dot + 1, last_dot - second_last_dot - 1);
|
||||
if (!slot_str.empty())
|
||||
slot = std::atoi(slot_str.c_str());
|
||||
}
|
||||
|
||||
const std::string message = (slot >= 0) ?
|
||||
fmt::format(TRANSLATE_FS("VMManager", "Loading {} from slot {}..."), is_backup ? TRANSLATE("VMManager", "backup state") : TRANSLATE("VMManager", "state"), slot) :
|
||||
TRANSLATE_STR("VMManager", "Loading save state...");
|
||||
|
||||
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_FOLDER_OPEN, message, Host::OSD_QUICK_DURATION);
|
||||
|
||||
Host::RunOnCPUThread([path = std::move(path)]()
|
||||
{
|
||||
const std::string boot_path = s_save_state_selector_game_path;
|
||||
Host::RunOnCPUThread([boot_path = s_save_state_selector_game_path, path = std::move(path)]() {
|
||||
if (VMManager::HasValidVM())
|
||||
{
|
||||
Error error;
|
||||
if (!SaveState_UnzipFromDisk(path, &error))
|
||||
if (!VMManager::LoadState(path.c_str(), &error))
|
||||
{
|
||||
if (error.GetDescription().find("outdated") != std::string::npos)
|
||||
{
|
||||
Host::RunOnCPUThread([error_desc = error.GetDescription()]()
|
||||
{
|
||||
ImGuiFullscreen::OpenInfoMessageDialog(
|
||||
FSUI_ICONSTR(ICON_FA_TRIANGLE_EXCLAMATION, "Incompatible Save State"),
|
||||
error_desc);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Host::ReportErrorAsync(TRANSLATE_SV("VMManager", "Failed to load save state"), error.GetDescription());
|
||||
}
|
||||
MTGS::RunOnGSThread([error = std::move(error)]() {
|
||||
ImGuiFullscreen::OpenInfoMessageDialog(
|
||||
FSUI_ICONSTR(ICON_FA_TRIANGLE_EXCLAMATION, "Failed to Load State"),
|
||||
error.GetDescription());
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -10169,7 +10121,7 @@ TRANSLATE_NOOP("FullscreenUI", "Delete Save");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Close Menu");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Default Boot");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Delete State");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Incompatible Save State");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Failed to Load State");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Full Boot");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Reset Play Time");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Confirm Reset");
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "VMManager.h"
|
||||
|
||||
#include "common/BitUtils.h"
|
||||
#include "common/Error.h"
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/Path.h"
|
||||
#include "common/StringUtil.h"
|
||||
@@ -1325,7 +1326,10 @@ s32 SaveStateSelectorUI::GetCurrentSlot()
|
||||
void SaveStateSelectorUI::LoadCurrentSlot()
|
||||
{
|
||||
Host::RunOnCPUThread([slot = GetCurrentSlot()]() {
|
||||
VMManager::LoadStateFromSlot(slot);
|
||||
Error error;
|
||||
if (!VMManager::LoadStateFromSlot(slot, false, &error))
|
||||
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_TRIANGLE_EXCLAMATION,
|
||||
error.GetDescription(), Host::OSD_INFO_DURATION);
|
||||
});
|
||||
Close();
|
||||
}
|
||||
@@ -1333,7 +1337,10 @@ void SaveStateSelectorUI::LoadCurrentSlot()
|
||||
void SaveStateSelectorUI::LoadCurrentBackupSlot()
|
||||
{
|
||||
Host::RunOnCPUThread([slot = GetCurrentSlot()]() {
|
||||
VMManager::LoadStateFromSlot(slot, true);
|
||||
Error error;
|
||||
if (!VMManager::LoadStateFromSlot(slot, true, &error))
|
||||
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_TRIANGLE_EXCLAMATION,
|
||||
error.GetDescription(), Host::OSD_INFO_DURATION);
|
||||
});
|
||||
Close();
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "Elfheader.h"
|
||||
#include "PINE.h"
|
||||
#include "VMManager.h"
|
||||
#include "common/Error.h"
|
||||
#include "common/Threading.h"
|
||||
|
||||
#include <atomic>
|
||||
@@ -18,6 +19,7 @@
|
||||
#include <thread>
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "IconsFontAwesome6.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define read_portable(a, b, c) (recv(a, (char*)b, c, 0))
|
||||
@@ -654,7 +656,12 @@ PINEServer::IPCBuffer PINEServer::ParseCommand(std::span<u8> buf, std::vector<u8
|
||||
goto error;
|
||||
if (!SafetyChecks(buf_cnt, 1, ret_cnt, 0, buf_size)) [[unlikely]]
|
||||
goto error;
|
||||
Host::RunOnCPUThread([slot = FromSpan<u8>(buf, buf_cnt)] { VMManager::LoadStateFromSlot(slot); });
|
||||
Host::RunOnCPUThread([slot = FromSpan<u8>(buf, buf_cnt)] {
|
||||
Error state_error;
|
||||
if (!VMManager::LoadStateFromSlot(slot, false, &state_error))
|
||||
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_TRIANGLE_EXCLAMATION,
|
||||
state_error.GetDescription(), Host::OSD_INFO_DURATION);
|
||||
});
|
||||
buf_cnt += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ namespace VMManager
|
||||
static void PrecacheCDVDFile();
|
||||
|
||||
static std::string GetCurrentSaveStateFileName(s32 slot, bool backup = false);
|
||||
static bool DoLoadState(const char* filename);
|
||||
static bool DoLoadState(const char* filename, Error* error = nullptr);
|
||||
static bool DoSaveState(const char* filename, s32 slot_for_message, bool zip_on_thread, bool backup_old_state);
|
||||
static void ZipSaveState(std::unique_ptr<ArchiveEntryList> elist,
|
||||
std::unique_ptr<SaveStateScreenshotData> screenshot, std::string osd_key, const char* filename,
|
||||
@@ -1589,8 +1589,10 @@ bool VMManager::Initialize(VMBootParameters boot_params)
|
||||
// do we want to load state?
|
||||
if (!GSDumpReplayer::IsReplayingDump() && !state_to_load.empty())
|
||||
{
|
||||
if (!DoLoadState(state_to_load.c_str()))
|
||||
Error state_error;
|
||||
if (!DoLoadState(state_to_load.c_str(), &state_error))
|
||||
{
|
||||
Host::ReportErrorAsync(TRANSLATE_SV("VMManager", "Failed to load save state."), state_error.GetDescription());
|
||||
Shutdown(false);
|
||||
return false;
|
||||
}
|
||||
@@ -1824,19 +1826,18 @@ std::string VMManager::GetCurrentSaveStateFileName(s32 slot, bool backup)
|
||||
return GetSaveStateFileName(s_disc_serial.c_str(), s_disc_crc, slot, backup);
|
||||
}
|
||||
|
||||
bool VMManager::DoLoadState(const char* filename)
|
||||
bool VMManager::DoLoadState(const char* filename, Error* error)
|
||||
{
|
||||
if (GSDumpReplayer::IsReplayingDump())
|
||||
{
|
||||
Error::SetString(error, TRANSLATE_STR("VMManager", "Cannot load save state while replaying GS dump."));
|
||||
return false;
|
||||
}
|
||||
|
||||
Host::OnSaveStateLoading(filename);
|
||||
|
||||
Error error;
|
||||
if (!SaveState_UnzipFromDisk(filename, &error))
|
||||
{
|
||||
Host::ReportErrorAsync(TRANSLATE_SV("VMManager", "Failed to load save state"), error.GetDescription());
|
||||
if (!SaveState_UnzipFromDisk(filename, error))
|
||||
return false;
|
||||
}
|
||||
|
||||
Host::OnSaveStateLoaded(filename, true);
|
||||
if (g_InputRecording.isActive())
|
||||
@@ -1980,62 +1981,70 @@ u32 VMManager::DeleteSaveStates(const char* game_serial, u32 game_crc, bool also
|
||||
return deleted;
|
||||
}
|
||||
|
||||
bool VMManager::LoadState(const char* filename)
|
||||
bool VMManager::LoadState(const char* filename, Error* error)
|
||||
{
|
||||
if (Achievements::IsHardcoreModeActive())
|
||||
{
|
||||
Host::AddIconOSDMessage("LoadStateHardcoreBlocked", ICON_FA_TRIANGLE_EXCLAMATION,
|
||||
TRANSLATE_SV("VMManager", "Cannot load save state while RetroAchievements Hardcore Mode is active."),
|
||||
Host::OSD_WARNING_DURATION);
|
||||
Error::SetString(error,
|
||||
TRANSLATE_STR("VMManager", "Cannot load save state while RetroAchievements Hardcore Mode is active."));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (MemcardBusy::IsBusy())
|
||||
{
|
||||
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_TRIANGLE_EXCLAMATION,
|
||||
fmt::format(TRANSLATE_FS("VMManager", "Failed to load state (Memory card is busy)")),
|
||||
Host::OSD_QUICK_DURATION);
|
||||
Error::SetString(error,
|
||||
TRANSLATE_STR("VMManager", "Memory card is busy."));
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Save the current state so we don't need to reset.
|
||||
if (DoLoadState(filename))
|
||||
if (DoLoadState(filename, error))
|
||||
return true;
|
||||
|
||||
Reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VMManager::LoadStateFromSlot(s32 slot, bool backup)
|
||||
bool VMManager::LoadStateFromSlot(s32 slot, bool backup, Error* error)
|
||||
{
|
||||
const std::string filename = GetCurrentSaveStateFileName(slot, backup);
|
||||
if (filename.empty() || !FileSystem::FileExists(filename.c_str()))
|
||||
{
|
||||
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_TRIANGLE_EXCLAMATION,
|
||||
fmt::format(TRANSLATE_FS("VMManager", "There is no saved {} in slot {}."), backup ? TRANSLATE("VMManager", "backup state") : "state", slot),
|
||||
Host::OSD_QUICK_DURATION);
|
||||
if (backup)
|
||||
Error::SetStringFmt(error,
|
||||
TRANSLATE_FS("VMManager", "There is no save state in backup slot {}."), slot);
|
||||
else
|
||||
Error::SetStringFmt(error,
|
||||
TRANSLATE_FS("VMManager", "There is no save state in slot {}."), slot);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Achievements::IsHardcoreModeActive())
|
||||
{
|
||||
Host::AddIconOSDMessage("LoadStateHardcoreBlocked", ICON_FA_TRIANGLE_EXCLAMATION,
|
||||
fmt::format(TRANSLATE_FS("VMManager", "Cannot load save {} from slot {} while RetroAchievements Hardcore Mode is active."), backup ? TRANSLATE("VMManager", "backup state") : TRANSLATE("VMManager", "state"), slot),
|
||||
Host::OSD_WARNING_DURATION);
|
||||
if (backup)
|
||||
Error::SetStringFmt(error,
|
||||
TRANSLATE_FS("VMManager", "Cannot load save state from backup slot {} while RetroAchievements Hardcore Mode is active."), slot);
|
||||
else
|
||||
Error::SetStringFmt(error,
|
||||
TRANSLATE_FS("VMManager", "Cannot load save state from slot {} while RetroAchievements Hardcore Mode is active."), slot);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (MemcardBusy::IsBusy())
|
||||
{
|
||||
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_TRIANGLE_EXCLAMATION,
|
||||
fmt::format(TRANSLATE_FS("VMManager", "Failed to load {} from slot {} (Memory card is busy)"), backup ? TRANSLATE("VMManager", "backup state") : TRANSLATE("VMManager", "state"), slot),
|
||||
Host::OSD_QUICK_DURATION);
|
||||
if (backup)
|
||||
Error::SetStringFmt(error,
|
||||
TRANSLATE_FS("VMManager", "Failed to load save state from backup slot {} (memory card is busy)."), slot);
|
||||
else
|
||||
Error::SetStringFmt(error,
|
||||
TRANSLATE_FS("VMManager", "Failed to load save state from slot {} (memory card is busy)."), slot);
|
||||
return false;
|
||||
}
|
||||
|
||||
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_FOLDER_OPEN,
|
||||
fmt::format(TRANSLATE_FS("VMManager", "Loading {} from slot {}..."), backup ? TRANSLATE("VMManager", "backup state") : TRANSLATE("VMManager", "state"), slot), Host::OSD_QUICK_DURATION);
|
||||
return DoLoadState(filename.c_str());
|
||||
|
||||
return DoLoadState(filename.c_str(), error);
|
||||
}
|
||||
|
||||
bool VMManager::SaveState(const char* filename, bool zip_on_thread, bool backup_old_state)
|
||||
|
||||
@@ -127,10 +127,10 @@ namespace VMManager
|
||||
bool HasSaveStateInSlot(const char* game_serial, u32 game_crc, s32 slot);
|
||||
|
||||
/// Loads state from the specified file.
|
||||
bool LoadState(const char* filename);
|
||||
bool LoadState(const char* filename, Error* error = nullptr);
|
||||
|
||||
/// Loads state from the specified slot.
|
||||
bool LoadStateFromSlot(s32 slot, bool backup = false);
|
||||
bool LoadStateFromSlot(s32 slot, bool backup = false, Error* error = nullptr);
|
||||
|
||||
/// Saves state to the specified filename.
|
||||
bool SaveState(const char* filename, bool zip_on_thread = true, bool backup_old_state = false);
|
||||
|
||||