mirror of
https://github.com/PCSX2/pcsx2.git
synced 2025-12-16 04:08:48 +00:00
Formatting: Apply AlignWithSpaces
Some checks are pending
🐧 Linux Builds / AppImage (push) Waiting to run
🐧 Linux Builds / Flatpak (push) Waiting to run
🍎 MacOS Builds / Defaults (push) Waiting to run
🖥️ Windows Builds / Lint VS Project Files (push) Waiting to run
🖥️ Windows Builds / SSE4 (push) Blocked by required conditions
🖥️ Windows Builds / AVX2 (push) Blocked by required conditions
🖥️ Windows Builds / CMake (push) Waiting to run
Some checks are pending
🐧 Linux Builds / AppImage (push) Waiting to run
🐧 Linux Builds / Flatpak (push) Waiting to run
🍎 MacOS Builds / Defaults (push) Waiting to run
🖥️ Windows Builds / Lint VS Project Files (push) Waiting to run
🖥️ Windows Builds / SSE4 (push) Blocked by required conditions
🖥️ Windows Builds / AVX2 (push) Blocked by required conditions
🖥️ Windows Builds / CMake (push) Waiting to run
This commit is contained in:
parent
c5820a4f54
commit
8fd91cb7df
@ -600,7 +600,7 @@ bool SmallStringBase::starts_with(const char* str, bool case_sensitive) const
|
||||
return false;
|
||||
|
||||
return (case_sensitive) ? (std::strncmp(str, m_buffer, other_length) == 0) :
|
||||
(CASE_N_COMPARE(str, m_buffer, other_length) == 0);
|
||||
(CASE_N_COMPARE(str, m_buffer, other_length) == 0);
|
||||
}
|
||||
|
||||
bool SmallStringBase::starts_with(const SmallStringBase& str, bool case_sensitive) const
|
||||
@ -610,7 +610,7 @@ bool SmallStringBase::starts_with(const SmallStringBase& str, bool case_sensitiv
|
||||
return false;
|
||||
|
||||
return (case_sensitive) ? (std::strncmp(str.m_buffer, m_buffer, other_length) == 0) :
|
||||
(CASE_N_COMPARE(str.m_buffer, m_buffer, other_length) == 0);
|
||||
(CASE_N_COMPARE(str.m_buffer, m_buffer, other_length) == 0);
|
||||
}
|
||||
|
||||
bool SmallStringBase::starts_with(const std::string_view str, bool case_sensitive) const
|
||||
@ -620,7 +620,7 @@ bool SmallStringBase::starts_with(const std::string_view str, bool case_sensitiv
|
||||
return false;
|
||||
|
||||
return (case_sensitive) ? (std::strncmp(str.data(), m_buffer, other_length) == 0) :
|
||||
(CASE_N_COMPARE(str.data(), m_buffer, other_length) == 0);
|
||||
(CASE_N_COMPARE(str.data(), m_buffer, other_length) == 0);
|
||||
}
|
||||
|
||||
bool SmallStringBase::starts_with(const std::string& str, bool case_sensitive) const
|
||||
@ -630,7 +630,7 @@ bool SmallStringBase::starts_with(const std::string& str, bool case_sensitive) c
|
||||
return false;
|
||||
|
||||
return (case_sensitive) ? (std::strncmp(str.data(), m_buffer, other_length) == 0) :
|
||||
(CASE_N_COMPARE(str.data(), m_buffer, other_length) == 0);
|
||||
(CASE_N_COMPARE(str.data(), m_buffer, other_length) == 0);
|
||||
}
|
||||
|
||||
bool SmallStringBase::ends_with(const char* str, bool case_sensitive) const
|
||||
@ -641,7 +641,7 @@ bool SmallStringBase::ends_with(const char* str, bool case_sensitive) const
|
||||
|
||||
u32 start_offset = m_length - other_length;
|
||||
return (case_sensitive) ? (std::strncmp(str, m_buffer + start_offset, other_length) == 0) :
|
||||
(CASE_N_COMPARE(str, m_buffer + start_offset, other_length) == 0);
|
||||
(CASE_N_COMPARE(str, m_buffer + start_offset, other_length) == 0);
|
||||
}
|
||||
|
||||
bool SmallStringBase::ends_with(const SmallStringBase& str, bool case_sensitive) const
|
||||
@ -652,7 +652,7 @@ bool SmallStringBase::ends_with(const SmallStringBase& str, bool case_sensitive)
|
||||
|
||||
const u32 start_offset = m_length - other_length;
|
||||
return (case_sensitive) ? (std::strncmp(str.m_buffer, m_buffer + start_offset, other_length) == 0) :
|
||||
(CASE_N_COMPARE(str.m_buffer, m_buffer + start_offset, other_length) == 0);
|
||||
(CASE_N_COMPARE(str.m_buffer, m_buffer + start_offset, other_length) == 0);
|
||||
}
|
||||
|
||||
bool SmallStringBase::ends_with(const std::string_view str, bool case_sensitive) const
|
||||
@ -663,7 +663,7 @@ bool SmallStringBase::ends_with(const std::string_view str, bool case_sensitive)
|
||||
|
||||
const u32 start_offset = m_length - other_length;
|
||||
return (case_sensitive) ? (std::strncmp(str.data(), m_buffer + start_offset, other_length) == 0) :
|
||||
(CASE_N_COMPARE(str.data(), m_buffer + start_offset, other_length) == 0);
|
||||
(CASE_N_COMPARE(str.data(), m_buffer + start_offset, other_length) == 0);
|
||||
}
|
||||
|
||||
bool SmallStringBase::ends_with(const std::string& str, bool case_sensitive) const
|
||||
@ -674,7 +674,7 @@ bool SmallStringBase::ends_with(const std::string& str, bool case_sensitive) con
|
||||
|
||||
const u32 start_offset = m_length - other_length;
|
||||
return (case_sensitive) ? (std::strncmp(str.data(), m_buffer + start_offset, other_length) == 0) :
|
||||
(CASE_N_COMPARE(str.data(), m_buffer + start_offset, other_length) == 0);
|
||||
(CASE_N_COMPARE(str.data(), m_buffer + start_offset, other_length) == 0);
|
||||
}
|
||||
|
||||
void SmallStringBase::clear()
|
||||
|
||||
@ -47,16 +47,16 @@ AboutDialog::AboutDialog(QWidget* parent)
|
||||
m_ui.links->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
m_ui.links->setText(QStringLiteral(
|
||||
R"(<a href="%1">%2</a> | <a href="%3">%4</a> | <a href="%5">%6</a> | <a href="%7">%8</a> | <a href="%9">%10</a>)")
|
||||
.arg(getWebsiteUrl())
|
||||
.arg(tr("Website"))
|
||||
.arg(getSupportForumsUrl())
|
||||
.arg(tr("Support Forums"))
|
||||
.arg(getGitHubRepositoryUrl())
|
||||
.arg(tr("GitHub Repository"))
|
||||
.arg(getLicenseUrl())
|
||||
.arg(tr("License"))
|
||||
.arg(getThirdPartyLicensesUrl())
|
||||
.arg(tr("Third-Party Licenses")));
|
||||
.arg(getWebsiteUrl())
|
||||
.arg(tr("Website"))
|
||||
.arg(getSupportForumsUrl())
|
||||
.arg(tr("Support Forums"))
|
||||
.arg(getGitHubRepositoryUrl())
|
||||
.arg(tr("GitHub Repository"))
|
||||
.arg(getLicenseUrl())
|
||||
.arg(tr("License"))
|
||||
.arg(getThirdPartyLicensesUrl())
|
||||
.arg(tr("Third-Party Licenses")));
|
||||
|
||||
connect(m_ui.links, &QLabel::linkActivated, this, &AboutDialog::linksLinkActivated);
|
||||
connect(m_ui.buttonBox, &QDialogButtonBox::rejected, this, &QDialog::close);
|
||||
|
||||
@ -874,10 +874,10 @@ inline QString DisassemblyView::DisassemblyStringFromAddress(u32 address, QFont
|
||||
}
|
||||
|
||||
lineString = lineString.leftJustified(4, ' ') // Address / symbol
|
||||
.arg(line.name.c_str())
|
||||
.arg(line.params.c_str()) // opcode + arguments
|
||||
.arg(isConditional ? (isConditionalMet ? "# true" : "# false") : "")
|
||||
.arg(isCurrentPC ? "<--" : "");
|
||||
.arg(line.name.c_str())
|
||||
.arg(line.params.c_str()) // opcode + arguments
|
||||
.arg(isConditional ? (isConditionalMet ? "# true" : "# false") : "")
|
||||
.arg(isCurrentPC ? "<--" : "");
|
||||
|
||||
return lineString;
|
||||
}
|
||||
|
||||
@ -1129,8 +1129,8 @@ bool MainWindow::shouldHideMainWindow() const
|
||||
{
|
||||
// NOTE: We can't use isRenderingToMain() here, because this happens post-fullscreen-switch.
|
||||
return (Host::GetBoolSettingValue("UI", "HideMainWindowWhenRunning", false) && !g_emu_thread->shouldRenderToMain()) ||
|
||||
(g_emu_thread->shouldRenderToMain() && (isRenderingFullscreen() || m_is_temporarily_windowed)) ||
|
||||
Host::InNoGUIMode();
|
||||
(g_emu_thread->shouldRenderToMain() && (isRenderingFullscreen() || m_is_temporarily_windowed)) ||
|
||||
Host::InNoGUIMode();
|
||||
}
|
||||
|
||||
bool MainWindow::shouldMouseLock() const
|
||||
@ -1142,8 +1142,8 @@ bool MainWindow::shouldMouseLock() const
|
||||
return false;
|
||||
|
||||
bool windowsHidden = (!g_debugger_window || g_debugger_window->isHidden()) &&
|
||||
(!m_controller_settings_window || m_controller_settings_window->isHidden()) &&
|
||||
(!m_settings_window || m_settings_window->isHidden());
|
||||
(!m_controller_settings_window || m_controller_settings_window->isHidden()) &&
|
||||
(!m_settings_window || m_settings_window->isHidden());
|
||||
|
||||
return windowsHidden && (isActiveWindow() || isRenderingFullscreen());
|
||||
}
|
||||
|
||||
@ -1000,21 +1000,21 @@ void EmuThread::updatePerformanceMetrics(bool force)
|
||||
if (THREAD_VU1)
|
||||
{
|
||||
gs_stat = tr("Slot: %1 | Volume: %2% | %3 | EE: %4% | VU: %5% | GS: %6%")
|
||||
.arg(SaveStateSelectorUI::GetCurrentSlot())
|
||||
.arg(SPU2::GetOutputVolume())
|
||||
.arg(gs_stat_str.c_str())
|
||||
.arg(PerformanceMetrics::GetCPUThreadUsage(), 0, 'f', 0)
|
||||
.arg(PerformanceMetrics::GetVUThreadUsage(), 0, 'f', 0)
|
||||
.arg(PerformanceMetrics::GetGSThreadUsage(), 0, 'f', 0);
|
||||
.arg(SaveStateSelectorUI::GetCurrentSlot())
|
||||
.arg(SPU2::GetOutputVolume())
|
||||
.arg(gs_stat_str.c_str())
|
||||
.arg(PerformanceMetrics::GetCPUThreadUsage(), 0, 'f', 0)
|
||||
.arg(PerformanceMetrics::GetVUThreadUsage(), 0, 'f', 0)
|
||||
.arg(PerformanceMetrics::GetGSThreadUsage(), 0, 'f', 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
gs_stat = tr("Slot: %1 | Volume: %2% | %3 | EE: %4% | GS: %5%")
|
||||
.arg(SaveStateSelectorUI::GetCurrentSlot())
|
||||
.arg(SPU2::GetOutputVolume())
|
||||
.arg(gs_stat_str.c_str())
|
||||
.arg(PerformanceMetrics::GetCPUThreadUsage(), 0, 'f', 0)
|
||||
.arg(PerformanceMetrics::GetGSThreadUsage(), 0, 'f', 0);
|
||||
.arg(SaveStateSelectorUI::GetCurrentSlot())
|
||||
.arg(SPU2::GetOutputVolume())
|
||||
.arg(gs_stat_str.c_str())
|
||||
.arg(PerformanceMetrics::GetCPUThreadUsage(), 0, 'f', 0)
|
||||
.arg(PerformanceMetrics::GetGSThreadUsage(), 0, 'f', 0);
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(g_main_window->getStatusVerboseWidget(), "setText", Qt::QueuedConnection, Q_ARG(const QString&, gs_stat));
|
||||
@ -1129,9 +1129,9 @@ void Host::OnAchievementsRefreshed()
|
||||
game_id = Achievements::GetGameID();
|
||||
|
||||
game_info = qApp
|
||||
->translate("EmuThread", "Game: %1 (%2)\n")
|
||||
.arg(QString::fromStdString(Achievements::GetGameTitle()))
|
||||
.arg(game_id);
|
||||
->translate("EmuThread", "Game: %1 (%2)\n")
|
||||
.arg(QString::fromStdString(Achievements::GetGameTitle()))
|
||||
.arg(game_id);
|
||||
|
||||
const std::string& rich_presence_string = Achievements::GetRichPresenceString();
|
||||
if (!rich_presence_string.empty())
|
||||
@ -1181,7 +1181,7 @@ void Host::OpenHostFileSelectorAsync(std::string_view title, bool select_directo
|
||||
if (!filters.empty())
|
||||
{
|
||||
filters_str.append(QStringLiteral("All File Types (%1)")
|
||||
.arg(QString::fromStdString(StringUtil::JoinString(filters.begin(), filters.end(), " "))));
|
||||
.arg(QString::fromStdString(StringUtil::JoinString(filters.begin(), filters.end(), " "))));
|
||||
for (const std::string& filter : filters)
|
||||
{
|
||||
filters_str.append(
|
||||
|
||||
@ -90,9 +90,7 @@ namespace QtUtils
|
||||
|
||||
const int min_column_width = header->minimumSectionSize();
|
||||
const int scrollbar_width = ((view->verticalScrollBar() && view->verticalScrollBar()->isVisible()) ||
|
||||
view->verticalScrollBarPolicy() == Qt::ScrollBarAlwaysOn) ?
|
||||
view->verticalScrollBar()->width() :
|
||||
0;
|
||||
view->verticalScrollBarPolicy() == Qt::ScrollBarAlwaysOn) ? view->verticalScrollBar()->width() : 0;
|
||||
int num_flex_items = 0;
|
||||
int total_width = 0;
|
||||
int column_index = 0;
|
||||
|
||||
@ -242,8 +242,8 @@ namespace SettingWidgetBinder
|
||||
static std::optional<QString> getNullableStringValue(const QCheckBox* widget)
|
||||
{
|
||||
return (widget->checkState() == Qt::PartiallyChecked) ?
|
||||
std::nullopt :
|
||||
std::optional<QString>(widget->isChecked() ? QStringLiteral("1") : QStringLiteral("0"));
|
||||
std::nullopt :
|
||||
std::optional<QString>(widget->isChecked() ? QStringLiteral("1") : QStringLiteral("0"));
|
||||
}
|
||||
static void setNullableStringValue(QCheckBox* widget, std::optional<QString> value)
|
||||
{
|
||||
|
||||
@ -40,7 +40,7 @@ AchievementSettingsWidget::AchievementSettingsWidget(SettingsWindow* dialog, QWi
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.notificationPosition, "Achievements", "NotificationPosition", static_cast<int>(OsdOverlayPos::TopLeft));
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.encoreMode, "Achievements", "EncoreMode", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.spectatorMode, "Achievements", "SpectatorMode", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.unofficialAchievements, "Achievements", "UnofficialTestMode",false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.unofficialAchievements, "Achievements", "UnofficialTestMode", false);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.achievementNotificationsDuration, "Achievements", "NotificationsDuration", Pcsx2Config::AchievementsOptions::DEFAULT_NOTIFICATION_DURATION);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.leaderboardNotificationsDuration, "Achievements", "LeaderboardsDuration", Pcsx2Config::AchievementsOptions::DEFAULT_LEADERBOARD_DURATION);
|
||||
|
||||
@ -57,7 +57,7 @@ AchievementSettingsWidget::AchievementSettingsWidget(SettingsWindow* dialog, QWi
|
||||
dialog->registerWidgetHelp(m_ui.overlays, tr("Enable In-Game Overlays"), tr("Checked"), tr("Shows icons in the lower-right corner of the screen when a challenge/primed achievement is active."));
|
||||
dialog->registerWidgetHelp(m_ui.overlayPosition, tr("Overlay Position"), tr("Bottom Right"), tr("Determines where achievement overlays are positioned on the screen."));
|
||||
dialog->registerWidgetHelp(m_ui.notificationPosition, tr("Notification Position"), tr("Top Left"), tr("Determines where achievement notification popups are positioned on the screen."));
|
||||
dialog->registerWidgetHelp(m_ui.encoreMode, tr("Enable Encore Mode"), tr("Unchecked"),tr("When enabled, each session will behave as if no achievements have been unlocked."));
|
||||
dialog->registerWidgetHelp(m_ui.encoreMode, tr("Enable Encore Mode"), tr("Unchecked"), tr("When enabled, each session will behave as if no achievements have been unlocked."));
|
||||
dialog->registerWidgetHelp(m_ui.spectatorMode, tr("Enable Spectator Mode"), tr("Unchecked"), tr("When enabled, PCSX2 will assume all achievements are locked and not send any unlock notifications to the server."));
|
||||
dialog->registerWidgetHelp(m_ui.unofficialAchievements, tr("Test Unofficial Achievements"), tr("Unchecked"), tr("When enabled, PCSX2 will list achievements from unofficial sets. Please note that these achievements are not tracked by RetroAchievements, so they unlock every time."));
|
||||
|
||||
@ -211,8 +211,8 @@ void AchievementSettingsWidget::updateLoginState()
|
||||
StringUtil::FromChars<u64>(Host::GetBaseStringSettingValue("Achievements", "LoginTimestamp", "0")).value_or(0);
|
||||
const QDateTime login_timestamp(QDateTime::fromSecsSinceEpoch(static_cast<qint64>(login_unix_timestamp)));
|
||||
m_ui.loginStatus->setText(tr("Username: %1\nLogin token generated on %2.")
|
||||
.arg(QString::fromStdString(username))
|
||||
.arg(login_timestamp.toString(Qt::TextDate)));
|
||||
.arg(QString::fromStdString(username))
|
||||
.arg(login_timestamp.toString(Qt::TextDate)));
|
||||
m_ui.loginButton->setText(tr("Logout"));
|
||||
}
|
||||
else
|
||||
|
||||
@ -54,7 +54,7 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsWindow* dialog, QWidget*
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.patches, "EmuCore", "EnablePatches", true);
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.savestateSelector, tr("Use Save State Selector"), tr("Checked"),
|
||||
tr("Show a save state selector UI when switching slots instead of showing a notification bubble."));
|
||||
tr("Show a save state selector UI when switching slots instead of showing a notification bubble."));
|
||||
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.savestateCompressionMethod, "EmuCore", "SavestateCompressionType", static_cast<int>(SavestateCompressionMethod::Zstandard));
|
||||
@ -220,6 +220,6 @@ void AdvancedSettingsWidget::setClampingMode(int vunum, int index)
|
||||
void AdvancedSettingsWidget::onSavestateCompressionTypeChanged()
|
||||
{
|
||||
const bool uncompressed = (m_dialog->getEffectiveIntValue("EmuCore", "SavestateCompressionType", static_cast<int>(SavestateCompressionMethod::Zstandard)) ==
|
||||
static_cast<int>(SavestateCompressionMethod::Uncompressed));
|
||||
static_cast<int>(SavestateCompressionMethod::Uncompressed));
|
||||
m_ui.savestateCompressionLevel->setDisabled(uncompressed);
|
||||
}
|
||||
}
|
||||
|
||||
@ -160,20 +160,20 @@ void AudioSettingsWidget::onSyncModeChanged()
|
||||
{
|
||||
const Pcsx2Config::SPU2Options::SPU2SyncMode sync_mode =
|
||||
Pcsx2Config::SPU2Options::ParseSyncMode(
|
||||
m_dialog
|
||||
->getEffectiveStringValue("SPU2/Output", "SyncMode",
|
||||
Pcsx2Config::SPU2Options::GetSyncModeName(Pcsx2Config::SPU2Options::DEFAULT_SYNC_MODE))
|
||||
.c_str())
|
||||
.value_or(Pcsx2Config::SPU2Options::DEFAULT_SYNC_MODE);
|
||||
m_dialog->getEffectiveStringValue("SPU2/Output", "SyncMode",
|
||||
Pcsx2Config::SPU2Options::GetSyncModeName(Pcsx2Config::SPU2Options::DEFAULT_SYNC_MODE)
|
||||
).c_str()
|
||||
).value_or(Pcsx2Config::SPU2Options::DEFAULT_SYNC_MODE);
|
||||
m_ui.stretchSettings->setEnabled(sync_mode == Pcsx2Config::SPU2Options::SPU2SyncMode::TimeStretch);
|
||||
}
|
||||
|
||||
AudioBackend AudioSettingsWidget::getEffectiveBackend() const
|
||||
{
|
||||
return AudioStream::ParseBackendName(m_dialog->getEffectiveStringValue("SPU2/Output", "Backend",
|
||||
AudioStream::GetBackendName(Pcsx2Config::SPU2Options::DEFAULT_BACKEND))
|
||||
.c_str())
|
||||
.value_or(Pcsx2Config::SPU2Options::DEFAULT_BACKEND);
|
||||
return AudioStream::ParseBackendName(
|
||||
m_dialog->getEffectiveStringValue("SPU2/Output", "Backend",
|
||||
AudioStream::GetBackendName(Pcsx2Config::SPU2Options::DEFAULT_BACKEND)
|
||||
).c_str()
|
||||
).value_or(Pcsx2Config::SPU2Options::DEFAULT_BACKEND);
|
||||
}
|
||||
|
||||
void AudioSettingsWidget::updateDriverNames()
|
||||
@ -263,17 +263,17 @@ void AudioSettingsWidget::updateLatencyLabel()
|
||||
if (expand_buffer_ms > 0)
|
||||
{
|
||||
m_ui.bufferingLabel->setText(tr("Maximum Latency: %1 ms (%2 ms buffer + %3 ms expand + %4 ms output)")
|
||||
.arg(config_buffer_ms + expand_buffer_ms + output_latency_ms)
|
||||
.arg(config_buffer_ms)
|
||||
.arg(expand_buffer_ms)
|
||||
.arg(output_latency_ms));
|
||||
.arg(config_buffer_ms + expand_buffer_ms + output_latency_ms)
|
||||
.arg(config_buffer_ms)
|
||||
.arg(expand_buffer_ms)
|
||||
.arg(output_latency_ms));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui.bufferingLabel->setText(tr("Maximum Latency: %1 ms (%2 ms buffer + %3 ms output)")
|
||||
.arg(config_buffer_ms + output_latency_ms)
|
||||
.arg(config_buffer_ms)
|
||||
.arg(output_latency_ms));
|
||||
.arg(config_buffer_ms + output_latency_ms)
|
||||
.arg(config_buffer_ms)
|
||||
.arg(output_latency_ms));
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -281,8 +281,8 @@ void AudioSettingsWidget::updateLatencyLabel()
|
||||
if (expand_buffer_ms > 0)
|
||||
{
|
||||
m_ui.bufferingLabel->setText(tr("Maximum Latency: %1 ms (%2 ms expand, minimum output latency unknown)")
|
||||
.arg(expand_buffer_ms + config_buffer_ms)
|
||||
.arg(expand_buffer_ms));
|
||||
.arg(expand_buffer_ms + config_buffer_ms)
|
||||
.arg(expand_buffer_ms));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -206,7 +206,7 @@ void ControllerSettingsWindow::onRenameProfileClicked()
|
||||
{
|
||||
std::string game_settings_path(game_settings.FileName.c_str());
|
||||
std::unique_ptr<INISettingsInterface> update_sif(std::make_unique<INISettingsInterface>(std::move(game_settings_path)));
|
||||
|
||||
|
||||
update_sif->Load();
|
||||
|
||||
if (!old_profile_name.compare(update_sif->GetStringValue("EmuCore", "InputProfileName")))
|
||||
@ -458,9 +458,9 @@ void ControllerSettingsWindow::createWidgets()
|
||||
|
||||
QListWidgetItem* item = new QListWidgetItem();
|
||||
//: Controller Port is an official term from Sony. Find the official translation for your language inside the console's manual.
|
||||
item->setText(mtap_enabled[port] ? (tr("Controller Port %1%2\n%3").arg(port + 1).arg(s_mtap_slot_names[slot]).arg(display_name)) :
|
||||
//: Controller Port is an official term from Sony. Find the official translation for your language inside the console's manual.
|
||||
tr("Controller Port %1\n%2").arg(port + 1).arg(display_name));
|
||||
item->setText(mtap_enabled[port] ? (tr("Controller Port %1%2\n%3").arg(port + 1).arg(s_mtap_slot_names[slot]).arg(display_name))
|
||||
//: Controller Port is an official term from Sony. Find the official translation for your language inside the console's manual.
|
||||
: tr("Controller Port %1\n%2").arg(port + 1).arg(display_name));
|
||||
item->setIcon(m_port_bindings[global_slot]->getIcon());
|
||||
item->setData(Qt::UserRole, QVariant(global_slot));
|
||||
m_ui.settingsCategory->addItem(item);
|
||||
@ -514,9 +514,9 @@ void ControllerSettingsWindow::updateListDescription(u32 global_slot, Controller
|
||||
const QString display_name = QString::fromUtf8(ci ? ci->GetLocalizedName() : "Unknown");
|
||||
|
||||
//: Controller Port is an official term from Sony. Find the official translation for your language inside the console's manual.
|
||||
item->setText(mtap_enabled ? (tr("Controller Port %1%2\n%3").arg(port + 1).arg(s_mtap_slot_names[slot]).arg(display_name)) :
|
||||
//: Controller Port is an official term from Sony. Find the official translation for your language inside the console's manual.
|
||||
tr("Controller Port %1\n%2").arg(port + 1).arg(display_name));
|
||||
item->setText(mtap_enabled ? (tr("Controller Port %1%2\n%3").arg(port + 1).arg(s_mtap_slot_names[slot]).arg(display_name))
|
||||
//: Controller Port is an official term from Sony. Find the official translation for your language inside the console's manual.
|
||||
: tr("Controller Port %1\n%2").arg(port + 1).arg(display_name));
|
||||
item->setIcon(widget->getIcon());
|
||||
break;
|
||||
}
|
||||
|
||||
@ -290,7 +290,7 @@ void DEV9SettingsWidget::onEthDeviceChanged(int index)
|
||||
void DEV9SettingsWidget::onEthDHCPInterceptChanged(Qt::CheckState state)
|
||||
{
|
||||
const bool enabled = (state == Qt::CheckState::PartiallyChecked ? Host::GetBaseBoolSettingValue("DEV9/Eth", "InterceptDHCP", false) : state) ||
|
||||
((m_adapter_options & AdapterOptions::DHCP_ForcedOn) == AdapterOptions::DHCP_ForcedOn);
|
||||
((m_adapter_options & AdapterOptions::DHCP_ForcedOn) == AdapterOptions::DHCP_ForcedOn);
|
||||
|
||||
// clang-format off
|
||||
const bool ipOverride = (m_adapter_options & AdapterOptions::DHCP_OverrideIP) == AdapterOptions::DHCP_OverrideIP;
|
||||
|
||||
@ -55,11 +55,11 @@ EmulationSettingsWidget::EmulationSettingsWidget(SettingsWindow* dialog, QWidget
|
||||
connect(m_ui.manuallySetRealTimeClock, &QCheckBox::checkStateChanged, this, &EmulationSettingsWidget::onManuallySetRealTimeClockChanged);
|
||||
EmulationSettingsWidget::onManuallySetRealTimeClockChanged();
|
||||
|
||||
m_ui.eeCycleRate->insertItem(
|
||||
0, tr("Use Global Setting [%1]")
|
||||
.arg(m_ui.eeCycleRate->itemText(
|
||||
std::clamp(Host::GetBaseIntSettingValue("EmuCore/Speedhacks", "EECycleRate", DEFAULT_EE_CYCLE_RATE) - MINIMUM_EE_CYCLE_RATE,
|
||||
0, MAXIMUM_EE_CYCLE_RATE - MINIMUM_EE_CYCLE_RATE))));
|
||||
m_ui.eeCycleRate->insertItem(0,
|
||||
tr("Use Global Setting [%1]")
|
||||
.arg(m_ui.eeCycleRate->itemText(
|
||||
std::clamp(Host::GetBaseIntSettingValue("EmuCore/Speedhacks", "EECycleRate", DEFAULT_EE_CYCLE_RATE) - MINIMUM_EE_CYCLE_RATE,
|
||||
0, MAXIMUM_EE_CYCLE_RATE - MINIMUM_EE_CYCLE_RATE))));
|
||||
|
||||
// Disable cheats, use the cheats panel instead (move fastcvd up in its spot).
|
||||
const int count = m_ui.systemSettingsLayout->count();
|
||||
@ -92,9 +92,9 @@ EmulationSettingsWidget::EmulationSettingsWidget(SettingsWindow* dialog, QWidget
|
||||
|
||||
const std::optional<int> cycle_rate =
|
||||
m_dialog->getIntValue("EmuCore/Speedhacks", "EECycleRate", sif ? std::nullopt : std::optional<int>(DEFAULT_EE_CYCLE_RATE));
|
||||
m_ui.eeCycleRate->setCurrentIndex(cycle_rate.has_value() ? (std::clamp(cycle_rate.value(), MINIMUM_EE_CYCLE_RATE, MAXIMUM_EE_CYCLE_RATE) +
|
||||
(0 - MINIMUM_EE_CYCLE_RATE) + static_cast<int>(m_dialog->isPerGameSettings())) :
|
||||
0);
|
||||
m_ui.eeCycleRate->setCurrentIndex(cycle_rate.has_value() ? (std::clamp(cycle_rate.value(), MINIMUM_EE_CYCLE_RATE, MAXIMUM_EE_CYCLE_RATE)
|
||||
+ (0 - MINIMUM_EE_CYCLE_RATE) + static_cast<int>(m_dialog->isPerGameSettings()))
|
||||
: 0);
|
||||
connect(m_ui.eeCycleRate, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int index) {
|
||||
std::optional<int> value;
|
||||
if (!m_dialog->isPerGameSettings() || index > 0)
|
||||
@ -164,9 +164,9 @@ EmulationSettingsWidget::EmulationSettingsWidget(SettingsWindow* dialog, QWidget
|
||||
tr("Manually set a real-time clock to use for the virtual PlayStation 2 instead of using your OS' system clock."));
|
||||
dialog->registerWidgetHelp(m_ui.rtcDateTime, tr("Real-Time Clock"), tr("Current date and time"),
|
||||
tr("Real-time clock (RTC) used by the virtual PlayStation 2. Date format is the same as the one used by your OS. "
|
||||
"This time is only applied upon booting the PS2; changing it while in-game will have no effect. "
|
||||
"NOTE: This assumes you have your PS2 set to the default timezone of GMT+0 and default DST of Summer Time. "
|
||||
"Some games require an RTC date/time set after their release date."));
|
||||
"This time is only applied upon booting the PS2; changing it while in-game will have no effect. "
|
||||
"NOTE: This assumes you have your PS2 set to the default timezone of GMT+0 and default DST of Summer Time. "
|
||||
"Some games require an RTC date/time set after their release date."));
|
||||
|
||||
updateOptimalFramePacing();
|
||||
updateUseVSyncForTimingEnabled();
|
||||
|
||||
@ -205,7 +205,7 @@ void GameCheatSettingsWidget::reloadList()
|
||||
{
|
||||
u32 num_unlabelled_codes = 0;
|
||||
bool showAllCRCS = m_ui.allCRCsCheckbox->isChecked();
|
||||
m_patches = Patch::GetPatchInfo(m_dialog->getSerial(), m_dialog->getDiscCRC(), true, showAllCRCS, & num_unlabelled_codes);
|
||||
m_patches = Patch::GetPatchInfo(m_dialog->getSerial(), m_dialog->getDiscCRC(), true, showAllCRCS, &num_unlabelled_codes);
|
||||
m_enabled_patches =
|
||||
m_dialog->getSettingsInterface()->GetStringList(Patch::CHEATS_CONFIG_SECTION, Patch::PATCH_ENABLE_CONFIG_KEY);
|
||||
|
||||
|
||||
@ -340,15 +340,15 @@ void GameSummaryWidget::onVerifyClicked()
|
||||
if (!hentry->version.empty())
|
||||
{
|
||||
setVerifyResult(tr("Verified as %1 [%2] (Version %3).")
|
||||
.arg(QString::fromStdString(hentry->name))
|
||||
.arg(QString::fromStdString(hentry->serial))
|
||||
.arg(QString::fromStdString(hentry->version)));
|
||||
.arg(QString::fromStdString(hentry->name))
|
||||
.arg(QString::fromStdString(hentry->serial))
|
||||
.arg(QString::fromStdString(hentry->version)));
|
||||
}
|
||||
else
|
||||
{
|
||||
setVerifyResult(tr("Verified as %1 [%2].")
|
||||
.arg(QString::fromStdString(hentry->name))
|
||||
.arg(QString::fromStdString(hentry->serial)));
|
||||
.arg(QString::fromStdString(hentry->name))
|
||||
.arg(QString::fromStdString(hentry->serial)));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@ -1280,8 +1280,8 @@ void GraphicsSettingsWidget::populateUpscaleMultipliers(u32 max_upscale_multipli
|
||||
m_ui.upscaleMultiplier->clear();
|
||||
|
||||
const u32 max_shown_multiplier = m_ui.extendedUpscales && m_ui.extendedUpscales->checkState() == Qt::Checked ?
|
||||
max_upscale_multiplier :
|
||||
std::min(max_upscale_multiplier, max_non_advanced_multiplier);
|
||||
max_upscale_multiplier :
|
||||
std::min(max_upscale_multiplier, max_non_advanced_multiplier);
|
||||
for (const auto& [name, value] : templates)
|
||||
{
|
||||
if (value > max_shown_multiplier)
|
||||
|
||||
@ -260,7 +260,7 @@ void InputBindingWidget::clearBinding()
|
||||
void InputBindingWidget::reloadBinding()
|
||||
{
|
||||
m_bindings_settings = m_sif ? m_sif->GetStringList(m_section_name.c_str(), m_key_name.c_str()) :
|
||||
Host::GetBaseStringListSetting(m_section_name.c_str(), m_key_name.c_str());
|
||||
Host::GetBaseStringListSetting(m_section_name.c_str(), m_key_name.c_str());
|
||||
|
||||
m_bindings_ui.clear();
|
||||
m_bindings_ui.reserve(m_bindings_settings.size());
|
||||
|
||||
@ -250,7 +250,7 @@ void MemoryCardConvertDialog::ConvertCard()
|
||||
baseName.replace(extensionPos, 4, "");
|
||||
// Add _converted to the end of it
|
||||
baseName.append("_converted");
|
||||
|
||||
|
||||
size_t num = 0;
|
||||
QString destName = baseName;
|
||||
destName.append(".ps2");
|
||||
@ -322,5 +322,5 @@ void MemoryCardConvertDialog::SetType_Folder()
|
||||
|
||||
void MemoryCardConvertDialog::FileOpenError(const QString errmsg)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Cannot Convert Memory Card"),tr("There was an error when accessing the memory card directory. Error message: %0").arg(errmsg));
|
||||
QMessageBox::critical(this, tr("Cannot Convert Memory Card"), tr("There was an error when accessing the memory card directory. Error message: %0").arg(errmsg));
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ private:
|
||||
void SetType_64();
|
||||
void SetType_Folder();
|
||||
void FileOpenError(const QString errmsg);
|
||||
|
||||
|
||||
Ui::MemoryCardConvertDialog m_ui;
|
||||
|
||||
bool isSetup = false;
|
||||
@ -57,7 +57,7 @@ private:
|
||||
static constexpr u32 FLAGS = FILESYSTEM_FIND_RECURSIVE | FILESYSTEM_FIND_FOLDERS | FILESYSTEM_FIND_FILES;
|
||||
};
|
||||
|
||||
// Card capacities computed from freshly formatted superblocks.
|
||||
// Card capacities computed from freshly formatted superblocks.
|
||||
namespace CardCapacity
|
||||
{
|
||||
static constexpr size_t _8_MB = 0x1f40 * 512 * 2; //(0x1fc7 - 0x29) * 2 * 512;
|
||||
|
||||
@ -75,7 +75,7 @@ bool MemoryCardConvertWorker::ConvertToFile(const std::string& srcFolderName, co
|
||||
{
|
||||
sourceFolderMemoryCard.Read(sourceBuffer.data() + address, address, FolderMemoryCard::PageSizeRaw);
|
||||
address += FolderMemoryCard::PageSizeRaw;
|
||||
|
||||
|
||||
// Only report progress every 16 pages. Substantially speeds up the conversion.
|
||||
if (address % (FolderMemoryCard::PageSizeRaw * 16) == 0)
|
||||
this->SetProgressValue(address);
|
||||
@ -140,7 +140,7 @@ bool MemoryCardConvertWorker::ConvertToFolder(const std::string& srcFileName, co
|
||||
{
|
||||
targetFolderMemoryCard.Save(sourceBuffer.data() + address, address, FolderMemoryCard::PageSizeRaw);
|
||||
address += FolderMemoryCard::PageSizeRaw;
|
||||
|
||||
|
||||
// Only report progress every 16 pages. Substantially speeds up the conversion.
|
||||
if (address % (FolderMemoryCard::PageSizeRaw * 16) == 0)
|
||||
this->SetProgressValue(address + (i * sourceBuffer.size()));
|
||||
|
||||
@ -101,7 +101,7 @@ void MemoryCardCreateDialog::createCard()
|
||||
const QString name = m_ui.name->text();
|
||||
const std::string name_str = QStringLiteral("%1.%2").arg(name)
|
||||
.arg((m_fileType == MemoryCardFileType::PS1) ? QStringLiteral("mcr") : QStringLiteral("ps2"))
|
||||
.toStdString();
|
||||
.toStdString();
|
||||
if (!Path::IsValidFileName(name_str, false))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Create Memory Card"),
|
||||
@ -123,7 +123,7 @@ void MemoryCardCreateDialog::createCard()
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
if (m_type == MemoryCardType::File)
|
||||
{
|
||||
const std::string fullPath = Path::Combine(EmuFolders::MemoryCards, name_str);
|
||||
|
||||
@ -701,13 +701,13 @@ uint32_t Achievements::ClientReadMemory(uint32_t address, uint8_t* buffer, uint3
|
||||
void Achievements::ClientServerCall(
|
||||
const rc_api_request_t* request, rc_client_server_callback_t callback, void* callback_data, rc_client_t* client)
|
||||
{
|
||||
HTTPDownloader::Request::Callback hd_callback = [callback, callback_data](s32 status_code, const std::string& content_type,
|
||||
HTTPDownloader::Request::Data data) {
|
||||
HTTPDownloader::Request::Callback hd_callback = [callback, callback_data](s32 status_code, const std::string& content_type, HTTPDownloader::Request::Data data)
|
||||
{
|
||||
rc_api_server_response_t rr;
|
||||
rr.http_status_code = (status_code <= 0) ? (status_code == HTTPDownloader::HTTP_STATUS_CANCELLED ?
|
||||
RC_API_SERVER_RESPONSE_CLIENT_ERROR :
|
||||
RC_API_SERVER_RESPONSE_RETRYABLE_CLIENT_ERROR) :
|
||||
status_code;
|
||||
RC_API_SERVER_RESPONSE_CLIENT_ERROR :
|
||||
RC_API_SERVER_RESPONSE_RETRYABLE_CLIENT_ERROR)
|
||||
: status_code;
|
||||
rr.body_length = data.size();
|
||||
rr.body = reinterpret_cast<const char*>(data.data());
|
||||
|
||||
@ -1486,7 +1486,7 @@ bool Achievements::ResetHardcoreMode(bool is_booting)
|
||||
// because the gameid can be cached, and identify immediately on GameChanged(),
|
||||
// which gets called before ResetHardcoreMode().
|
||||
const bool wanted_hardcore_mode = (IsLoggedInOrLoggingIn() || s_load_game_request) &&
|
||||
EmuConfig.Achievements.HardcoreMode;
|
||||
EmuConfig.Achievements.HardcoreMode;
|
||||
if (s_hardcore_mode == wanted_hardcore_mode)
|
||||
return false;
|
||||
|
||||
|
||||
@ -12,13 +12,15 @@ using namespace R5900::Interpreter;
|
||||
//#define CP2COND (vif1Regs.stat.VEW)
|
||||
|
||||
//Run the FINISH either side of the VCALL's as we have no control over it past here.
|
||||
void VCALLMS() {
|
||||
void VCALLMS()
|
||||
{
|
||||
_vu0FinishMicro();
|
||||
vu0ExecMicro(((cpuRegs.code >> 6) & 0x7FFF));
|
||||
//vif0Regs.stat.VEW = false;
|
||||
}
|
||||
|
||||
void VCALLMSR() {
|
||||
void VCALLMSR()
|
||||
{
|
||||
_vu0FinishMicro();
|
||||
vu0ExecMicro(VU0.VI[REG_CMSAR0].US[0]);
|
||||
//vif0Regs.stat.VEW = false;
|
||||
@ -50,7 +52,7 @@ void BC2FL()
|
||||
}
|
||||
else
|
||||
{
|
||||
cpuRegs.pc+= 4;
|
||||
cpuRegs.pc += 4;
|
||||
}
|
||||
}
|
||||
void BC2TL()
|
||||
@ -62,6 +64,6 @@ void BC2TL()
|
||||
}
|
||||
else
|
||||
{
|
||||
cpuRegs.pc+= 4;
|
||||
cpuRegs.pc += 4;
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ namespace
|
||||
// When this happens, the cache still fills with the data and when it gets evicted the data is lost.
|
||||
// We don't emulate memory access on a logic level, so we need to ensure that we don't try to load/store to a non-existant physical address.
|
||||
// This fixes the Find My Own Way demo.
|
||||
|
||||
|
||||
// The lower parts of a cache tags structure is as follows:
|
||||
// 31 - 12: The physical address cache tag.
|
||||
// 11: Used by PCSX2 to indicate if the physical address is valid.
|
||||
@ -468,7 +468,7 @@ namespace R5900
|
||||
const int way = addr & 0x1;
|
||||
CacheLine line = cache.lineAt(index, way);
|
||||
|
||||
line.tag.setAddr(cpuRegs.CP0.n.TagLo);
|
||||
line.tag.setAddr(cpuRegs.CP0.n.TagLo);
|
||||
line.tag.rawValue &= ~CacheTag::ALL_FLAGS;
|
||||
line.tag.rawValue |= (cpuRegs.CP0.n.TagLo & CacheTag::ALL_FLAGS);
|
||||
|
||||
|
||||
@ -234,7 +234,7 @@ static void vSyncInfoCalc(vSyncTimingInfo* info, double framesPerSecond, u32 sca
|
||||
{
|
||||
hBlank /= 2;
|
||||
hRender /= 2;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Carry fixed-point math all the way through the entire vsync and hsync counting processes, and continually apply rounding
|
||||
//as needed for each scheduled v/hsync related event. Much better to handle than this messed state.
|
||||
@ -412,8 +412,8 @@ void UpdateVSyncRate(bool force)
|
||||
s32 vdiff = vsyncCounter.deltaCycles;
|
||||
hsyncCounter.deltaCycles = (hsyncCounter.Mode == MODE_HBLANK) ? vSyncInfo.hBlank : vSyncInfo.hRender;
|
||||
vsyncCounter.deltaCycles = (vsyncCounter.Mode == MODE_GSBLANK) ?
|
||||
vSyncInfo.GSBlank :
|
||||
((vsyncCounter.Mode == MODE_VBLANK) ? vSyncInfo.Blank : vSyncInfo.Render);
|
||||
vSyncInfo.GSBlank :
|
||||
((vsyncCounter.Mode == MODE_VBLANK) ? vSyncInfo.Blank : vSyncInfo.Render);
|
||||
|
||||
hsyncCounter.startCycle += hdiff - hsyncCounter.deltaCycles;
|
||||
vsyncCounter.startCycle += vdiff - vsyncCounter.deltaCycles;
|
||||
@ -653,10 +653,10 @@ __fi void rcntUpdate_hScanline()
|
||||
}
|
||||
else
|
||||
{ //HBLANK START / HRENDER End
|
||||
|
||||
|
||||
// set up the hblank's start and end cycle information:
|
||||
hsyncCounter.startCycle += vSyncInfo.hRender; // start (absolute cycle value)
|
||||
hsyncCounter.deltaCycles = vSyncInfo.hBlank; // endpoint (delta from start value)
|
||||
hsyncCounter.deltaCycles = vSyncInfo.hBlank; // endpoint (delta from start value)
|
||||
if (!GSSMODE1reg.SINT)
|
||||
{
|
||||
if (!CSRreg.HSINT)
|
||||
@ -765,7 +765,7 @@ __fi void rcntUpdate()
|
||||
rcntSyncCounter(i);
|
||||
|
||||
if (counters[i].mode.ClockSource == 0x3 || !rcntCanCount(i)) // don't count hblank sources
|
||||
continue;
|
||||
continue;
|
||||
|
||||
_cpuTestOverflow(i);
|
||||
_cpuTestTarget(i);
|
||||
@ -813,7 +813,7 @@ static __fi void rcntStartGate(bool isVblank, u32 sCycle)
|
||||
|
||||
switch (counters[i].mode.GateMode)
|
||||
{
|
||||
case 0x0: //Count When Signal is low (V_RENDER ONLY)
|
||||
case 0x0: // Count When Signal is low (V_RENDER ONLY)
|
||||
|
||||
// Just set the start cycle -- counting will be done as needed
|
||||
// for events (overflows, targets, mode changes, and the gate off below)
|
||||
@ -955,7 +955,7 @@ __fi u32 rcntRcount(int index)
|
||||
u32 ret;
|
||||
|
||||
rcntSyncCounter(index);
|
||||
|
||||
|
||||
ret = counters[index].count;
|
||||
|
||||
// Spams the Console.
|
||||
|
||||
@ -355,10 +355,10 @@ bool GSopen(const Pcsx2Config::GSOptions& config, GSRendererType renderer, u8* b
|
||||
|
||||
if (!res)
|
||||
{
|
||||
Host::ReportErrorAsync(
|
||||
"Error", fmt::format(TRANSLATE_FS("GS","Failed to create render device. This may be due to your GPU not supporting the "
|
||||
"chosen renderer ({}), or because your graphics drivers need to be updated."),
|
||||
Pcsx2Config::GSOptions::GetRendererName(GSConfig.Renderer)));
|
||||
Host::ReportErrorAsync("Error",
|
||||
fmt::format(TRANSLATE_FS("GS", "Failed to create render device. This may be due to your GPU not supporting the "
|
||||
"chosen renderer ({}), or because your graphics drivers need to be updated."),
|
||||
Pcsx2Config::GSOptions::GetRendererName(GSConfig.Renderer)));
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -500,7 +500,7 @@ void GSEndCapture()
|
||||
{
|
||||
if (g_gs_renderer)
|
||||
g_gs_renderer->EndCapture();
|
||||
}
|
||||
}
|
||||
|
||||
void GSPresentCurrentFrame()
|
||||
{
|
||||
@ -661,7 +661,7 @@ void GSgetStats(SmallStringBase& info)
|
||||
const double fillrate = pm.Get(GSPerfMon::Fillrate);
|
||||
double pps = fps * fillrate;
|
||||
char prefix = '\0';
|
||||
|
||||
|
||||
if (pps >= 170000000)
|
||||
{
|
||||
pps /= 1073741824; // Gpps
|
||||
@ -689,7 +689,7 @@ void GSgetStats(SmallStringBase& info)
|
||||
(int)pm.Get(GSPerfMon::Draw),
|
||||
pm.Get(GSPerfMon::Swizzle) / 1024,
|
||||
pm.Get(GSPerfMon::Unswizzle) / 1024,
|
||||
pps,prefix);
|
||||
pps, prefix);
|
||||
}
|
||||
else if (GSCurrentRenderer == GSRendererType::Null)
|
||||
{
|
||||
|
||||
@ -1384,12 +1384,12 @@ TinyString GSCapture::GetElapsedTime()
|
||||
if (s_video_stream)
|
||||
{
|
||||
seconds = (s_next_video_pts * static_cast<s64>(s_video_codec_context->time_base.num)) /
|
||||
static_cast<s64>(s_video_codec_context->time_base.den);
|
||||
static_cast<s64>(s_video_codec_context->time_base.den);
|
||||
}
|
||||
else if (s_audio_stream)
|
||||
{
|
||||
seconds = (s_next_audio_pts * static_cast<s64>(s_audio_codec_context->time_base.num)) /
|
||||
static_cast<s64>(s_audio_codec_context->time_base.den);
|
||||
static_cast<s64>(s_audio_codec_context->time_base.den);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -38,7 +38,7 @@ namespace GSCapture
|
||||
CodecList GetVideoCodecList(const char* container);
|
||||
CodecList GetAudioCodecList(const char* container);
|
||||
|
||||
using FormatName = std::pair<int , std::string>; // id,name
|
||||
using FormatName = std::pair<int, std::string>; // id,name
|
||||
using FormatList = std::vector<FormatName>;
|
||||
FormatList GetVideoFormatList(const char* codec);
|
||||
}; // namespace GSCapture
|
||||
|
||||
@ -185,7 +185,7 @@ bool GSClut::CanLoadCLUT(const GIFRegTEX0& TEX0, const bool update_CBP)
|
||||
case 4:
|
||||
if (m_CBP[0] == TEX0.CBP)
|
||||
return false;
|
||||
if(update_CBP)
|
||||
if (update_CBP)
|
||||
m_CBP[0] = TEX0.CBP;
|
||||
break;
|
||||
case 5:
|
||||
@ -531,7 +531,7 @@ void GSClut::GetAlphaMinMax32(int& amin_out, int& amax_out)
|
||||
void GSClut::WriteCLUT_T32_I8_CSM1(const u32* RESTRICT src, u16* RESTRICT clut, u16 offset)
|
||||
{
|
||||
// This is required when CSA is offset from the base of the CLUT so we point to the right data
|
||||
for (int i = offset; i < 16; i ++)
|
||||
for (int i = offset; i < 16; i++)
|
||||
{
|
||||
const int off = i << 4; // WriteCLUT_T32_I4_CSM1 loads 16 at a time
|
||||
// Source column
|
||||
|
||||
@ -509,15 +509,15 @@ GSVector4i GSLocalMemory::GetRectForPageOffset(u32 base_bp, u32 offset_bp, u32 b
|
||||
return GSVector4i(pgs * page_offset_xy).xyxy() + GSVector4i::loadh(pgs);
|
||||
}
|
||||
|
||||
bool GSLocalMemory::HasOverlap(const u32 src_bp, const u32 src_bw, const u32 src_psm, const GSVector4i src_rect
|
||||
, const u32 dst_bp, const u32 dst_bw, const u32 dst_psm, const GSVector4i dst_rect)
|
||||
bool GSLocalMemory::HasOverlap(const u32 src_bp, const u32 src_bw, const u32 src_psm, const GSVector4i src_rect,
|
||||
const u32 dst_bp, const u32 dst_bw, const u32 dst_psm, const GSVector4i dst_rect)
|
||||
{
|
||||
const u32 src_start_bp = GSLocalMemory::GetStartBlockAddress(src_bp, src_bw, src_psm, src_rect) & ~(GS_BLOCKS_PER_PAGE - 1);
|
||||
const u32 dst_start_bp = GSLocalMemory::GetStartBlockAddress(dst_bp, dst_bw, dst_psm, dst_rect) & ~(GS_BLOCKS_PER_PAGE - 1);
|
||||
|
||||
u32 src_end_bp = ((GSLocalMemory::GetEndBlockAddress(src_bp, src_bw, src_psm, src_rect) + 1) + (GS_BLOCKS_PER_PAGE - 1)) & ~(GS_BLOCKS_PER_PAGE - 1);
|
||||
u32 dst_end_bp = ((GSLocalMemory::GetEndBlockAddress(dst_bp, dst_bw, dst_psm, dst_rect) + 1) + (GS_BLOCKS_PER_PAGE - 1)) & ~(GS_BLOCKS_PER_PAGE - 1);
|
||||
|
||||
|
||||
if (src_start_bp == src_end_bp)
|
||||
{
|
||||
src_end_bp = (src_end_bp + GS_BLOCKS_PER_PAGE) & ~(GS_MAX_BLOCKS - 1);
|
||||
|
||||
@ -23,7 +23,7 @@ void GSPerfMon::EndFrame(bool frame_only)
|
||||
{
|
||||
m_frame++;
|
||||
|
||||
if(!frame_only)
|
||||
if (!frame_only)
|
||||
m_count++;
|
||||
}
|
||||
|
||||
|
||||
@ -586,8 +586,8 @@ void GSDevice11::SetFeatures(IDXGIAdapter1* adapter)
|
||||
{
|
||||
// Check all three formats, since the feature means any can be used.
|
||||
m_features.dxt_textures = SupportsTextureFormat(m_dev.get(), DXGI_FORMAT_BC1_UNORM) &&
|
||||
SupportsTextureFormat(m_dev.get(), DXGI_FORMAT_BC2_UNORM) &&
|
||||
SupportsTextureFormat(m_dev.get(), DXGI_FORMAT_BC3_UNORM);
|
||||
SupportsTextureFormat(m_dev.get(), DXGI_FORMAT_BC2_UNORM) &&
|
||||
SupportsTextureFormat(m_dev.get(), DXGI_FORMAT_BC3_UNORM);
|
||||
|
||||
m_features.bptc_textures = SupportsTextureFormat(m_dev.get(), DXGI_FORMAT_BC7_UNORM);
|
||||
|
||||
@ -595,8 +595,8 @@ void GSDevice11::SetFeatures(IDXGIAdapter1* adapter)
|
||||
m_features.cas_sharpening = (m_feature_level >= D3D_FEATURE_LEVEL_11_0);
|
||||
|
||||
m_max_texture_size = (m_feature_level >= D3D_FEATURE_LEVEL_11_0) ?
|
||||
D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION :
|
||||
D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;
|
||||
D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION :
|
||||
D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;
|
||||
}
|
||||
|
||||
bool GSDevice11::HasSurface() const
|
||||
@ -752,7 +752,7 @@ bool GSDevice11::CreateSwapChain()
|
||||
else
|
||||
{
|
||||
Console.ErrorFmt("D3D11: GetParent() on swap chain to get factory failed: {}", Error::CreateHResult(hr).GetDescription());
|
||||
}
|
||||
}
|
||||
|
||||
if (!CreateSwapChainRTV())
|
||||
{
|
||||
@ -801,7 +801,7 @@ bool GSDevice11::CreateSwapChainRTV()
|
||||
SUCCEEDED(m_swap_chain->GetDesc(&desc)))
|
||||
{
|
||||
m_window_info.surface_refresh_rate = static_cast<float>(desc.BufferDesc.RefreshRate.Numerator) /
|
||||
static_cast<float>(desc.BufferDesc.RefreshRate.Denominator);
|
||||
static_cast<float>(desc.BufferDesc.RefreshRate.Denominator);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1263,7 +1263,7 @@ void GSDevice11::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture*
|
||||
void GSDevice11::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, bool red, bool green, bool blue, bool alpha, ShaderConvert shader)
|
||||
{
|
||||
const u8 index = static_cast<u8>(red) | (static_cast<u8>(green) << 1) | (static_cast<u8>(blue) << 2) |
|
||||
(static_cast<u8>(alpha) << 3);
|
||||
(static_cast<u8>(alpha) << 3);
|
||||
StretchRect(sTex, sRect, dTex, dRect, m_convert.ps[static_cast<int>(shader)].get(), nullptr,
|
||||
m_convert.bs[index].get(), false);
|
||||
}
|
||||
@ -1316,7 +1316,7 @@ void GSDevice11::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture*
|
||||
};
|
||||
|
||||
|
||||
IASetVertexBuffer(vertices, sizeof(vertices[0]), std::size(vertices));
|
||||
IASetVertexBuffer(vertices, sizeof(vertices[0]), std::size(vertices));
|
||||
IASetInputLayout(m_convert.il.get());
|
||||
IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
|
||||
@ -1795,8 +1795,8 @@ void GSDevice11::SetupPS(const PSSelector& sel, const GSHWDrawConfig::PSConstant
|
||||
}};
|
||||
|
||||
const u8 index = (static_cast<u8>(ssel.IsMipFilterLinear()) << 2) |
|
||||
(static_cast<u8>(ssel.IsMagFilterLinear()) << 1) |
|
||||
static_cast<u8>(ssel.IsMinFilterLinear());
|
||||
(static_cast<u8>(ssel.IsMagFilterLinear()) << 1) |
|
||||
static_cast<u8>(ssel.IsMinFilterLinear());
|
||||
sd.Filter = filters[index];
|
||||
}
|
||||
|
||||
|
||||
@ -63,7 +63,7 @@ bool GSTexture11::Update(const GSVector4i& r, const void* data, int pitch, int l
|
||||
g_perfmon.Put(GSPerfMon::TextureUploads, 1);
|
||||
|
||||
const u32 bs = GetCompressedBlockSize();
|
||||
|
||||
|
||||
const D3D11_BOX box = {Common::AlignDownPow2((u32)r.left, bs), Common::AlignDownPow2((u32)r.top, bs), 0U,
|
||||
Common::AlignUpPow2((u32)r.right, bs), Common::AlignUpPow2((u32)r.bottom, bs), 1U};
|
||||
const UINT subresource = layer; // MipSlice + (ArraySlice * MipLevels).
|
||||
|
||||
@ -134,7 +134,7 @@ bool GSDevice12::SupportsTextureFormat(DXGI_FORMAT format)
|
||||
|
||||
D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {format};
|
||||
return SUCCEEDED(m_device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &support, sizeof(support))) &&
|
||||
(support.Support1 & required) == required;
|
||||
(support.Support1 & required) == required;
|
||||
}
|
||||
|
||||
u32 GSDevice12::GetAdapterVendorID() const
|
||||
@ -958,7 +958,7 @@ bool GSDevice12::CreateSwapChainRTV()
|
||||
SUCCEEDED(m_swap_chain->GetDesc(&desc)))
|
||||
{
|
||||
m_window_info.surface_refresh_rate = static_cast<float>(desc.BufferDesc.RefreshRate.Numerator) /
|
||||
static_cast<float>(desc.BufferDesc.RefreshRate.Denominator);
|
||||
static_cast<float>(desc.BufferDesc.RefreshRate.Denominator);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1238,8 +1238,8 @@ bool GSDevice12::CheckFeatures(const u32& vendor_id)
|
||||
m_features.vs_expand = !GSConfig.DisableVertexShaderExpand;
|
||||
|
||||
m_features.dxt_textures = SupportsTextureFormat(DXGI_FORMAT_BC1_UNORM) &&
|
||||
SupportsTextureFormat(DXGI_FORMAT_BC2_UNORM) &&
|
||||
SupportsTextureFormat(DXGI_FORMAT_BC3_UNORM);
|
||||
SupportsTextureFormat(DXGI_FORMAT_BC2_UNORM) &&
|
||||
SupportsTextureFormat(DXGI_FORMAT_BC3_UNORM);
|
||||
m_features.bptc_textures = SupportsTextureFormat(DXGI_FORMAT_BC7_UNORM);
|
||||
|
||||
m_max_texture_size = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION;
|
||||
@ -1643,8 +1643,8 @@ void GSDevice12::BeginRenderPassForStretchRect(
|
||||
GSTexture12* dTex, const GSVector4i& dtex_rc, const GSVector4i& dst_rc, bool allow_discard)
|
||||
{
|
||||
const D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE load_op = (allow_discard && dst_rc.eq(dtex_rc)) ?
|
||||
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_DISCARD :
|
||||
GetLoadOpForTexture(dTex);
|
||||
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_DISCARD :
|
||||
GetLoadOpForTexture(dTex);
|
||||
dTex->SetState(GSTexture::State::Dirty);
|
||||
|
||||
if (dTex->GetType() != GSTexture::Type::DepthStencil)
|
||||
@ -1742,8 +1742,8 @@ void GSDevice12::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
|
||||
(sTex[0] && (sTex[0]->GetState() == GSTexture::State::Dirty ||
|
||||
(sTex[0]->GetState() == GSTexture::State::Cleared || sTex[0]->GetClearColor() != 0)));
|
||||
const bool has_input_1 = (PMODE.SLBG == 0 || feedback_write_2_but_blend_bg) && sTex[1] &&
|
||||
(sTex[1]->GetState() == GSTexture::State::Dirty ||
|
||||
(sTex[1]->GetState() == GSTexture::State::Cleared || sTex[1]->GetClearColor() != 0));
|
||||
(sTex[1]->GetState() == GSTexture::State::Dirty ||
|
||||
(sTex[1]->GetState() == GSTexture::State::Cleared || sTex[1]->GetClearColor() != 0));
|
||||
if (has_input_0)
|
||||
{
|
||||
static_cast<GSTexture12*>(sTex[0])->CommitClear();
|
||||
@ -2261,7 +2261,7 @@ bool GSDevice12::GetSampler(D3D12DescriptorHandle* cpu_handle, GSHWDrawConfig::S
|
||||
}};
|
||||
|
||||
const u8 index = (static_cast<u8>(ss.IsMipFilterLinear()) << 2) |
|
||||
(static_cast<u8>(ss.IsMagFilterLinear()) << 1) | static_cast<u8>(ss.IsMinFilterLinear());
|
||||
(static_cast<u8>(ss.IsMagFilterLinear()) << 1) | static_cast<u8>(ss.IsMinFilterLinear());
|
||||
sd.Filter = filters[index];
|
||||
}
|
||||
|
||||
@ -2448,8 +2448,7 @@ bool GSDevice12::CompileConvertPipelines()
|
||||
gpb.SetNoBlendingState();
|
||||
gpb.SetVertexShader(m_convert_vs.get());
|
||||
|
||||
for (ShaderConvert i = ShaderConvert::COPY; static_cast<int>(i) < static_cast<int>(ShaderConvert::Count);
|
||||
i = static_cast<ShaderConvert>(static_cast<int>(i) + 1))
|
||||
for (ShaderConvert i = ShaderConvert::COPY; i < ShaderConvert::Count; i = static_cast<ShaderConvert>(static_cast<int>(i) + 1))
|
||||
{
|
||||
const bool depth = HasDepthOutput(i);
|
||||
const int index = static_cast<int>(i);
|
||||
@ -2621,8 +2620,7 @@ bool GSDevice12::CompilePresentPipelines()
|
||||
gpb.SetNoStencilState();
|
||||
gpb.SetRenderTarget(0, DXGI_FORMAT_R8G8B8A8_UNORM);
|
||||
|
||||
for (PresentShader i = PresentShader::COPY; static_cast<int>(i) < static_cast<int>(PresentShader::Count);
|
||||
i = static_cast<PresentShader>(static_cast<int>(i) + 1))
|
||||
for (PresentShader i = PresentShader::COPY; i < PresentShader::Count; i = static_cast<PresentShader>(static_cast<int>(i) + 1))
|
||||
{
|
||||
const int index = static_cast<int>(i);
|
||||
|
||||
@ -2963,8 +2961,8 @@ GSDevice12::ComPtr<ID3D12PipelineState> GSDevice12::CreateTFXPipeline(const Pipe
|
||||
if (p.rt)
|
||||
{
|
||||
const GSTexture::Format format = IsDATEModePrimIDInit(p.ps.date) ?
|
||||
GSTexture::Format::PrimID :
|
||||
(p.ps.colclip_hw ? GSTexture::Format::ColorClip : GSTexture::Format::Color);
|
||||
GSTexture::Format::PrimID :
|
||||
(p.ps.colclip_hw ? GSTexture::Format::ColorClip : GSTexture::Format::Color);
|
||||
|
||||
DXGI_FORMAT native_format;
|
||||
LookupNativeFormat(format, nullptr, nullptr, &native_format, nullptr);
|
||||
@ -3650,8 +3648,8 @@ bool GSDevice12::ApplyTFXState(bool already_execed)
|
||||
{
|
||||
m_current_root_signature = RootSignature::TFX;
|
||||
flags |= DIRTY_FLAG_VS_CONSTANT_BUFFER_BINDING | DIRTY_FLAG_PS_CONSTANT_BUFFER_BINDING |
|
||||
DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE | DIRTY_FLAG_SAMPLERS_DESCRIPTOR_TABLE |
|
||||
DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE_2 | DIRTY_FLAG_PIPELINE;
|
||||
DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE | DIRTY_FLAG_SAMPLERS_DESCRIPTOR_TABLE |
|
||||
DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE_2 | DIRTY_FLAG_PIPELINE;
|
||||
cmdlist->SetGraphicsRootSignature(m_tfx_root_signature.get());
|
||||
}
|
||||
|
||||
|
||||
@ -544,11 +544,11 @@ private:
|
||||
DIRTY_FLAG_STENCIL_REF = (1 << 19),
|
||||
|
||||
DIRTY_BASE_STATE = DIRTY_FLAG_VS_CONSTANT_BUFFER_BINDING | DIRTY_FLAG_PS_CONSTANT_BUFFER_BINDING |
|
||||
DIRTY_FLAG_VS_VERTEX_BUFFER_BINDING | DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE |
|
||||
DIRTY_FLAG_SAMPLERS_DESCRIPTOR_TABLE | DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE_2 |
|
||||
DIRTY_FLAG_VERTEX_BUFFER | DIRTY_FLAG_INDEX_BUFFER | DIRTY_FLAG_PRIMITIVE_TOPOLOGY |
|
||||
DIRTY_FLAG_VIEWPORT | DIRTY_FLAG_SCISSOR | DIRTY_FLAG_RENDER_TARGET | DIRTY_FLAG_PIPELINE |
|
||||
DIRTY_FLAG_BLEND_CONSTANTS | DIRTY_FLAG_STENCIL_REF,
|
||||
DIRTY_FLAG_VS_VERTEX_BUFFER_BINDING | DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE |
|
||||
DIRTY_FLAG_SAMPLERS_DESCRIPTOR_TABLE | DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE_2 |
|
||||
DIRTY_FLAG_VERTEX_BUFFER | DIRTY_FLAG_INDEX_BUFFER | DIRTY_FLAG_PRIMITIVE_TOPOLOGY |
|
||||
DIRTY_FLAG_VIEWPORT | DIRTY_FLAG_SCISSOR | DIRTY_FLAG_RENDER_TARGET | DIRTY_FLAG_PIPELINE |
|
||||
DIRTY_FLAG_BLEND_CONSTANTS | DIRTY_FLAG_STENCIL_REF,
|
||||
|
||||
DIRTY_TFX_STATE =
|
||||
DIRTY_BASE_STATE | DIRTY_FLAG_TFX_TEXTURES | DIRTY_FLAG_TFX_SAMPLERS | DIRTY_FLAG_TFX_RT_TEXTURES,
|
||||
|
||||
@ -125,7 +125,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
||||
// This is a little annoying. basically, to do mipmap generation, we need to be a render target.
|
||||
// If it's a compressed texture, we won't be generating mips anyway, so this should be fine.
|
||||
desc.Flags = (levels > 1 && !IsCompressedFormat(format)) ? D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET :
|
||||
D3D12_RESOURCE_FLAG_NONE;
|
||||
D3D12_RESOURCE_FLAG_NONE;
|
||||
state = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1093,7 +1093,7 @@ bool GSHwHack::OI_SonicUnleashed(GSRendererHW& r, GSTexture* rt, GSTexture* ds,
|
||||
rt_again->m_texture = tex;
|
||||
rt = tex;
|
||||
}
|
||||
|
||||
|
||||
GSVector2i rt_size(rt->GetSize());
|
||||
|
||||
// This is awful, but so is the CRC hack... it's a texture shuffle split horizontally instead of vertically.
|
||||
@ -1102,14 +1102,14 @@ bool GSHwHack::OI_SonicUnleashed(GSRendererHW& r, GSTexture* rt, GSTexture* ds,
|
||||
if (rt_again->m_unscaled_size.x < src->m_unscaled_size.x || rt_again->m_unscaled_size.y < src->m_unscaled_size.y)
|
||||
{
|
||||
GSVector2i new_size = GSVector2i(std::max(rt_again->m_unscaled_size.x, src->m_unscaled_size.x),
|
||||
std::max(rt_again->m_unscaled_size.y, src->m_unscaled_size.y));
|
||||
std::max(rt_again->m_unscaled_size.y, src->m_unscaled_size.y));
|
||||
rt_again->ResizeTexture(new_size.x, new_size.y);
|
||||
rt = rt_again->m_texture;
|
||||
rt_size = new_size * GSVector2i(src->GetScale());
|
||||
rt_again->UpdateDrawn(GSVector4i::loadh(new_size));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const GSVector2i copy_size(std::min(rt_size.x, src_size.x), std::min(rt_size.y, src_size.y));
|
||||
|
||||
|
||||
@ -332,7 +332,7 @@ void GSRendererHW::ConvertSpriteTextureShuffle(u32& process_rg, u32& process_ba,
|
||||
const GSVertex second_vert = (start_verts[0].XYZ.X <= start_verts[1].XYZ.X) ? start_verts[1] : start_verts[0];
|
||||
// vertex position is 8 to 16 pixels, therefore it is the 16-31 bits of the colors
|
||||
const int pos = (first_vert.XYZ.X - o.OFX) & 0xFF;
|
||||
|
||||
|
||||
// Read texture is 8 to 16 pixels (same as above)
|
||||
const float tw = static_cast<float>(1u << m_cached_ctx.TEX0.TW);
|
||||
int tex_pos = (PRIM->FST) ? first_vert.U : static_cast<int>(tw * first_vert.ST.S * 16.0f);
|
||||
@ -359,7 +359,7 @@ void GSRendererHW::ConvertSpriteTextureShuffle(u32& process_rg, u32& process_ba,
|
||||
const u32 minu = (m_cached_ctx.CLAMP.MINU & 8);
|
||||
if (maxu)
|
||||
{
|
||||
process_ba |= SHUFFLE_READ;
|
||||
process_ba |= SHUFFLE_READ;
|
||||
process_rg &= ~SHUFFLE_READ;
|
||||
if (!PRIM->ABE && (process_rg & SHUFFLE_WRITE))
|
||||
{
|
||||
@ -1124,7 +1124,7 @@ GSVector2i GSRendererHW::GetValidSize(const GSTextureCache::Source* tex, const b
|
||||
height = std::min(height, valid_max_size);
|
||||
}
|
||||
|
||||
return GSVector2i(width, height);
|
||||
return GSVector2i(width, height);
|
||||
}
|
||||
|
||||
GSVector2i GSRendererHW::GetTargetSize(const GSTextureCache::Source* tex, const bool can_expand, const bool is_shuffle)
|
||||
@ -1167,7 +1167,7 @@ bool GSRendererHW::IsPossibleChannelShuffle() const
|
||||
const int draw_height = std::abs(v[1].XYZ.Y - v[0].XYZ.Y) >> 4;
|
||||
|
||||
const bool mask_clamp = (m_cached_ctx.CLAMP.WMS | m_cached_ctx.CLAMP.WMT) & 0x2;
|
||||
|
||||
|
||||
const bool draw_match = (draw_height == 2) || (draw_width == 8);
|
||||
|
||||
if (draw_match || mask_clamp)
|
||||
@ -1616,18 +1616,18 @@ bool GSRendererHW::IsRTWritten()
|
||||
const u32 written_bits = (~m_cached_ctx.FRAME.FBMSK & GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].fmsk);
|
||||
const GIFRegALPHA ALPHA = m_context->ALPHA;
|
||||
return (
|
||||
// A not masked
|
||||
(written_bits & 0xFF000000u) != 0) ||
|
||||
(
|
||||
// RGB not entirely masked
|
||||
((written_bits & 0x00FFFFFFu) != 0) &&
|
||||
// RGB written through no-blending, or blend result being non-zero
|
||||
(!PRIM->ABE || // not blending
|
||||
ALPHA.D != 1 || // additive to Cs
|
||||
(ALPHA.A != ALPHA.B && // left side is not zero
|
||||
(ALPHA.C == 1 || // multiply by Ad
|
||||
(ALPHA.C == 2 && ALPHA.FIX != 0) || // multiply by 0
|
||||
(ALPHA.C == 0 && GetAlphaMinMax().max != 0)))));
|
||||
// A not masked
|
||||
(written_bits & 0xFF000000u) != 0) ||
|
||||
(
|
||||
// RGB not entirely masked
|
||||
((written_bits & 0x00FFFFFFu) != 0) &&
|
||||
// RGB written through no-blending, or blend result being non-zero
|
||||
(!PRIM->ABE || // not blending
|
||||
ALPHA.D != 1 || // additive to Cs
|
||||
(ALPHA.A != ALPHA.B && // left side is not zero
|
||||
(ALPHA.C == 1 || // multiply by Ad
|
||||
(ALPHA.C == 2 && ALPHA.FIX != 0) || // multiply by 0
|
||||
(ALPHA.C == 0 && GetAlphaMinMax().max != 0)))));
|
||||
}
|
||||
|
||||
bool GSRendererHW::IsDepthAlwaysPassing()
|
||||
@ -1636,8 +1636,8 @@ bool GSRendererHW::IsDepthAlwaysPassing()
|
||||
const int check_index = m_vt.m_primclass == GS_SPRITE_CLASS ? 1 : 0;
|
||||
// Depth is always pass/fail (no read) and write are discarded.
|
||||
return (!m_cached_ctx.TEST.ZTE || m_cached_ctx.TEST.ZTST <= ZTST_ALWAYS) ||
|
||||
// Depth test will always pass
|
||||
(m_cached_ctx.TEST.ZTST == ZTST_GEQUAL && m_vt.m_eq.z && std::min(m_vertex.buff[check_index].XYZ.Z, max_z) == max_z);
|
||||
// Depth test will always pass
|
||||
(m_cached_ctx.TEST.ZTST == ZTST_GEQUAL && m_vt.m_eq.z && std::min(m_vertex.buff[check_index].XYZ.Z, max_z) == max_z);
|
||||
}
|
||||
|
||||
bool GSRendererHW::IsUsingCsInBlend()
|
||||
@ -1673,14 +1673,14 @@ bool GSRendererHW::IsTBPFrameOrZ(u32 tbp, bool frame_only)
|
||||
const u32 max_z = (0xFFFFFFFF >> (GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].fmt * 8));
|
||||
const bool no_rt = (!IsRTWritten() && !m_cached_ctx.TEST.DATE);
|
||||
const bool no_ds = (
|
||||
// Depth is always pass/fail (no read) and write are discarded.
|
||||
(zm != 0 && m_cached_ctx.TEST.ZTST <= ZTST_ALWAYS) ||
|
||||
// Depth test will always pass
|
||||
(zm != 0 && m_cached_ctx.TEST.ZTST == ZTST_GEQUAL && m_vt.m_eq.z && std::min(m_vertex.buff[0].XYZ.Z, max_z) == max_z) ||
|
||||
// Depth will be written through the RT
|
||||
(!no_rt && m_cached_ctx.FRAME.FBP == m_cached_ctx.ZBUF.ZBP && !PRIM->TME && zm == 0 && (fm & fm_mask) == 0 && m_cached_ctx.TEST.ZTE)) ||
|
||||
// No color or Z being written.
|
||||
(no_rt && zm != 0);
|
||||
// Depth is always pass/fail (no read) and write are discarded.
|
||||
(zm != 0 && m_cached_ctx.TEST.ZTST <= ZTST_ALWAYS) ||
|
||||
// Depth test will always pass
|
||||
(zm != 0 && m_cached_ctx.TEST.ZTST == ZTST_GEQUAL && m_vt.m_eq.z && std::min(m_vertex.buff[0].XYZ.Z, max_z) == max_z) ||
|
||||
// Depth will be written through the RT
|
||||
(!no_rt && m_cached_ctx.FRAME.FBP == m_cached_ctx.ZBUF.ZBP && !PRIM->TME && zm == 0 && (fm & fm_mask) == 0 && m_cached_ctx.TEST.ZTE)) ||
|
||||
// No color or Z being written.
|
||||
(no_rt && zm != 0);
|
||||
|
||||
// Relying a lot on the optimizer here... I don't like it.
|
||||
return (is_frame && !no_rt) || (is_z && !no_ds && !frame_only);
|
||||
@ -1777,7 +1777,7 @@ void GSRendererHW::InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, const GS
|
||||
|
||||
if (!(iter->draw == s_n && BITBLTBUF.SBP == iter->blit.DBP && iter->blit.DPSM == BITBLTBUF.SPSM && r.eq(iter->rect)))
|
||||
continue;
|
||||
|
||||
|
||||
g_texture_cache->InvalidateVideoMem(m_mem.GetOffset(BITBLTBUF.SBP, BITBLTBUF.SBW, BITBLTBUF.SPSM), r);
|
||||
skip = true;
|
||||
break;
|
||||
@ -1917,12 +1917,12 @@ void GSRendererHW::SwSpriteRender()
|
||||
|
||||
const GSVertex& v = m_index.tail > 0 ? m_vertex.buff[m_index.buff[m_index.tail - 1]] : GSVertex(); // Last vertex if any.
|
||||
const GSVector4i vc = GSVector4i(v.RGBAQ.R, v.RGBAQ.G, v.RGBAQ.B, v.RGBAQ.A) // 0x000000AA000000BB000000GG000000RR
|
||||
.ps32(); // 0x00AA00BB00GG00RR00AA00BB00GG00RR
|
||||
.ps32(); // 0x00AA00BB00GG00RR00AA00BB00GG00RR
|
||||
|
||||
const GSVector4i a_mask = GSVector4i::xff000000().u8to16(); // 0x00FF00000000000000FF000000000000
|
||||
const GSVector4i a_mask = GSVector4i::xff000000().u8to16(); // 0x00FF00000000000000FF000000000000
|
||||
|
||||
const bool fb_mask_enabled = m_cached_ctx.FRAME.FBMSK != 0x0;
|
||||
const GSVector4i fb_mask = GSVector4i(m_cached_ctx.FRAME.FBMSK).u8to16(); // 0x00AA00BB00GG00RR00AA00BB00GG00RR
|
||||
const GSVector4i fb_mask = GSVector4i(m_cached_ctx.FRAME.FBMSK).u8to16(); // 0x00AA00BB00GG00RR00AA00BB00GG00RR
|
||||
|
||||
const u8 tex0_tfx = m_cached_ctx.TEX0.TFX;
|
||||
const u8 tex0_tcc = m_cached_ctx.TEX0.TCC;
|
||||
@ -2250,8 +2250,8 @@ void GSRendererHW::Draw()
|
||||
// Tomb Raider: Underworld does similar, except with R, G, B in separate palettes, therefore
|
||||
// we need to split on those too.
|
||||
m_channel_shuffle = !m_channel_shuffle_abort && IsPossibleChannelShuffle() && m_last_channel_shuffle_fbmsk == m_context->FRAME.FBMSK &&
|
||||
m_last_channel_shuffle_fbp <= m_context->FRAME.Block() && m_last_channel_shuffle_end_block > m_context->FRAME.Block() &&
|
||||
m_last_channel_shuffle_tbp <= m_context->TEX0.TBP0;
|
||||
m_last_channel_shuffle_fbp <= m_context->FRAME.Block() && m_last_channel_shuffle_end_block > m_context->FRAME.Block() &&
|
||||
m_last_channel_shuffle_tbp <= m_context->TEX0.TBP0;
|
||||
|
||||
if (m_channel_shuffle)
|
||||
{
|
||||
@ -2296,7 +2296,7 @@ void GSRendererHW::Draw()
|
||||
else
|
||||
m_conf.scissor.z = std::min(m_conf.scissor.z, static_cast<int>((m_channel_shuffle_width * 64) * m_conf.cb_ps.ScaleFactor.z));
|
||||
}
|
||||
|
||||
|
||||
m_last_rt->UpdateValidity(valid_area);
|
||||
|
||||
g_gs_device->RenderHW(m_conf);
|
||||
@ -2308,7 +2308,7 @@ void GSRendererHW::Draw()
|
||||
if (m_last_rt && GSConfig.SaveRT)
|
||||
{
|
||||
const u64 frame = g_perfmon.GetFrame();
|
||||
|
||||
|
||||
std::string s = GetDrawDumpPath("%05d_f%05lld_rt1_%05x_(%05x)_%s.bmp", s_n - 1, frame, m_last_channel_shuffle_fbp, m_last_rt->m_TEX0.TBP0, GSUtil::GetPSMName(m_cached_ctx.FRAME.PSM));
|
||||
|
||||
m_last_rt->m_texture->Save(s);
|
||||
@ -2354,9 +2354,9 @@ void GSRendererHW::Draw()
|
||||
// Note: do it first so we know if frame/depth writes are masked
|
||||
u32 fm = m_cached_ctx.FRAME.FBMSK;
|
||||
u32 zm = (m_cached_ctx.ZBUF.ZMSK || m_cached_ctx.TEST.ZTE == 0 ||
|
||||
(m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.ATST == ZTST_NEVER && m_cached_ctx.TEST.AFAIL != AFAIL_ZB_ONLY)) ?
|
||||
0xffffffffu :
|
||||
0;
|
||||
(m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.ATST == ZTST_NEVER && m_cached_ctx.TEST.AFAIL != AFAIL_ZB_ONLY)) ?
|
||||
0xffffffffu :
|
||||
0;
|
||||
const u32 fm_mask = GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].fmsk;
|
||||
|
||||
// Note required to compute TryAlphaTest below. So do it now.
|
||||
@ -2424,8 +2424,8 @@ void GSRendererHW::Draw()
|
||||
bool no_rt = (!IsRTWritten() && !m_cached_ctx.TEST.DATE);
|
||||
const bool all_depth_tests_pass = IsDepthAlwaysPassing();
|
||||
bool no_ds = (zm != 0 && all_depth_tests_pass) ||
|
||||
// No color or Z being written.
|
||||
(no_rt && zm != 0);
|
||||
// No color or Z being written.
|
||||
(no_rt && zm != 0);
|
||||
|
||||
// No Z test if no z buffer.
|
||||
if (no_ds || all_depth_tests_pass)
|
||||
@ -2465,7 +2465,6 @@ void GSRendererHW::Draw()
|
||||
g_gs_device->Recycle(colclip_texture);
|
||||
|
||||
g_gs_device->SetColorClipTexture(nullptr);
|
||||
|
||||
}
|
||||
else
|
||||
DevCon.Warning("HW: Error resolving colclip texture for pre-draw resolve");
|
||||
@ -2922,13 +2921,13 @@ void GSRendererHW::Draw()
|
||||
(m_vt.m_primclass == GS_SPRITE_CLASS || (m_vt.m_primclass == GS_TRIANGLE_CLASS && (m_index.tail % 6) == 0 && TrianglesAreQuads(true) && m_index.tail > 6)))
|
||||
{
|
||||
// Tail check is to make sure we have enough strips to go all the way across the page, or if it's using a region clamp could be used to draw strips.
|
||||
if (GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp == 16 &&
|
||||
if (GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp == 16 &&
|
||||
(m_index.tail >= (m_cached_ctx.TEX0.TBW * 2) || m_cached_ctx.TEX0.TBP0 == m_cached_ctx.FRAME.Block() || m_cached_ctx.CLAMP.WMS > CLAMP_CLAMP || m_cached_ctx.CLAMP.WMT > CLAMP_CLAMP))
|
||||
{
|
||||
const GSVertex* v = &m_vertex.buff[0];
|
||||
|
||||
const int first_x = std::clamp((static_cast<int>(((v[0].XYZ.X - m_context->XYOFFSET.OFX) + 8))) >> 4, 0, 2048);
|
||||
const bool offset_last = PRIM->FST ? (v[1].U > v[0].U) : ((v[1].ST.S / v[1].RGBAQ.Q) > (v[0].ST.S / v[1].RGBAQ.Q));
|
||||
const bool offset_last = PRIM->FST ? (v[1].U > v[0].U) : ((v[1].ST.S / v[1].RGBAQ.Q) > (v[0].ST.S / v[1].RGBAQ.Q));
|
||||
const int first_u = PRIM->FST ? ((v[0].U + (offset_last ? 0 : 9)) >> 4) : std::clamp(static_cast<int>(((1 << m_cached_ctx.TEX0.TW) * (v[0].ST.S / v[1].RGBAQ.Q)) + (offset_last ? 0.0f : 0.6f)), 0, 2048);
|
||||
const int second_u = PRIM->FST ? ((v[1].U + (offset_last ? 9 : 0)) >> 4) : std::clamp(static_cast<int>(((1 << m_cached_ctx.TEX0.TW) * (v[1].ST.S / v[1].RGBAQ.Q)) + (offset_last ? 0.6f : 0.0f)), 0, 2048);
|
||||
// offset coordinates swap around RG/BA. (Ace Combat)
|
||||
@ -3007,9 +3006,9 @@ void GSRendererHW::Draw()
|
||||
}
|
||||
else
|
||||
{
|
||||
src = tex_psm.depth ? g_texture_cache->LookupDepthSource(true, TEX0, m_cached_ctx.TEXA, MIP_CLAMP, tmm.coverage, possible_shuffle, m_vt.IsLinear(), m_cached_ctx.FRAME, req_color, req_alpha) :
|
||||
g_texture_cache->LookupSource(true, TEX0, m_cached_ctx.TEXA, MIP_CLAMP, tmm.coverage, (GSConfig.HWMipmap || GSConfig.TriFilter == TriFiltering::Forced) ? &hash_lod_range : nullptr,
|
||||
possible_shuffle, m_vt.IsLinear(), m_cached_ctx.FRAME, req_color, req_alpha);
|
||||
src = tex_psm.depth ? g_texture_cache->LookupDepthSource(true, TEX0, m_cached_ctx.TEXA, MIP_CLAMP, tmm.coverage, possible_shuffle, m_vt.IsLinear(), m_cached_ctx.FRAME, req_color, req_alpha)
|
||||
: g_texture_cache->LookupSource(true, TEX0, m_cached_ctx.TEXA, MIP_CLAMP, tmm.coverage, (GSConfig.HWMipmap || GSConfig.TriFilter == TriFiltering::Forced) ? &hash_lod_range : nullptr,
|
||||
possible_shuffle, m_vt.IsLinear(), m_cached_ctx.FRAME, req_color, req_alpha);
|
||||
|
||||
if (!src) [[unlikely]]
|
||||
{
|
||||
@ -3022,9 +3021,8 @@ void GSRendererHW::Draw()
|
||||
|
||||
const u32 draw_end = GSLocalMemory::GetEndBlockAddress(m_cached_ctx.FRAME.Block(), m_cached_ctx.FRAME.FBW, m_cached_ctx.FRAME.PSM, m_r) + 1;
|
||||
const u32 draw_start = GSLocalMemory::GetStartBlockAddress(m_cached_ctx.FRAME.Block(), m_cached_ctx.FRAME.FBW, m_cached_ctx.FRAME.PSM, m_r);
|
||||
draw_uses_target = src->m_from_target && ((src->m_from_target_TEX0.TBP0 <= draw_start &&
|
||||
src->m_from_target->UnwrappedEndBlock() > m_cached_ctx.FRAME.Block()) ||
|
||||
(m_cached_ctx.FRAME.Block() < src->m_from_target_TEX0.TBP0 && draw_end > src->m_from_target_TEX0.TBP0));
|
||||
draw_uses_target = src->m_from_target && ((src->m_from_target_TEX0.TBP0 <= draw_start && src->m_from_target->UnwrappedEndBlock() > m_cached_ctx.FRAME.Block()) ||
|
||||
(m_cached_ctx.FRAME.Block() < src->m_from_target_TEX0.TBP0 && draw_end > src->m_from_target_TEX0.TBP0));
|
||||
|
||||
if (possible_shuffle && GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp != 16)
|
||||
possible_shuffle &= draw_uses_target;
|
||||
@ -3047,9 +3045,9 @@ void GSRendererHW::Draw()
|
||||
|
||||
u32 new_fm = m_context->FRAME.FBMSK;
|
||||
u32 new_zm = (m_cached_ctx.ZBUF.ZMSK || m_cached_ctx.TEST.ZTE == 0 ||
|
||||
(m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.ATST == ZTST_NEVER && m_cached_ctx.TEST.AFAIL != AFAIL_ZB_ONLY)) ?
|
||||
0xffffffffu :
|
||||
0;
|
||||
(m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.ATST == ZTST_NEVER && m_cached_ctx.TEST.AFAIL != AFAIL_ZB_ONLY)) ?
|
||||
0xffffffffu :
|
||||
0;
|
||||
if (m_cached_ctx.TEST.ATE && GSRenderer::TryAlphaTest(new_fm, new_zm))
|
||||
{
|
||||
m_cached_ctx.TEST.ATE = false;
|
||||
@ -3059,10 +3057,10 @@ void GSRendererHW::Draw()
|
||||
zm = new_zm;
|
||||
no_rt = no_rt || (!IsRTWritten() && !m_cached_ctx.TEST.DATE);
|
||||
no_ds = no_ds || (zm != 0 && all_depth_tests_pass) ||
|
||||
// Depth will be written through the RT
|
||||
(!no_rt && m_cached_ctx.FRAME.FBP == m_cached_ctx.ZBUF.ZBP && !PRIM->TME && zm == 0 && (fm & fm_mask) == 0 && m_cached_ctx.TEST.ZTE) ||
|
||||
// No color or Z being written.
|
||||
(no_rt && zm != 0);
|
||||
// Depth will be written through the RT
|
||||
(!no_rt && m_cached_ctx.FRAME.FBP == m_cached_ctx.ZBUF.ZBP && !PRIM->TME && zm == 0 && (fm & fm_mask) == 0 && m_cached_ctx.TEST.ZTE) ||
|
||||
// No color or Z being written.
|
||||
(no_rt && zm != 0);
|
||||
if (no_rt && no_ds)
|
||||
{
|
||||
GL_INS("HW: Late draw cancel because no pixels pass alpha test.");
|
||||
@ -3362,16 +3360,18 @@ void GSRendererHW::Draw()
|
||||
|
||||
if (!no_rt)
|
||||
{
|
||||
possible_shuffle |= draw_sprite_tex && m_process_texture && m_primitive_covers_without_gaps != NoGapsType::FullCover && (((src && src->m_target && src->m_from_target && src->m_from_target->m_32_bits_fmt) &&
|
||||
(GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp == 16 || draw_uses_target) && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16) ||
|
||||
IsPossibleChannelShuffle());
|
||||
possible_shuffle |= draw_sprite_tex && m_process_texture && m_primitive_covers_without_gaps != NoGapsType::FullCover &&
|
||||
(((src && src->m_target && src->m_from_target && src->m_from_target->m_32_bits_fmt) &&
|
||||
(GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp == 16 || draw_uses_target) &&
|
||||
GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16) ||
|
||||
IsPossibleChannelShuffle());
|
||||
|
||||
const bool possible_horizontal_texture_shuffle = possible_shuffle && src && src->m_from_target && m_r.w <= src->m_from_target->m_valid.w && m_r.z > src->m_from_target->m_valid.z && m_cached_ctx.FRAME.FBW > src->m_from_target_TEX0.TBW;
|
||||
|
||||
// FBW is going to be wrong for channel shuffling into a new target, so take it from the source.
|
||||
FRAME_TEX0.U64 = 0;
|
||||
FRAME_TEX0.TBP0 = ((m_last_channel_shuffle_end_block + 1) == m_cached_ctx.FRAME.Block() && possible_shuffle) ? m_last_channel_shuffle_fbp : m_cached_ctx.FRAME.Block();
|
||||
FRAME_TEX0.TBW = (possible_horizontal_texture_shuffle || (possible_shuffle && src && src->m_from_target && IsPossibleChannelShuffle()&& m_cached_ctx.FRAME.FBW <= 2)) ? src->m_from_target_TEX0.TBW : m_cached_ctx.FRAME.FBW;
|
||||
FRAME_TEX0.TBW = (possible_horizontal_texture_shuffle || (possible_shuffle && src && src->m_from_target && IsPossibleChannelShuffle() && m_cached_ctx.FRAME.FBW <= 2)) ? src->m_from_target_TEX0.TBW : m_cached_ctx.FRAME.FBW;
|
||||
FRAME_TEX0.PSM = m_cached_ctx.FRAME.PSM;
|
||||
|
||||
// Don't clamp on shuffle, the height cache may troll us with the REAL height.
|
||||
@ -3459,8 +3459,8 @@ void GSRendererHW::Draw()
|
||||
return;
|
||||
}
|
||||
|
||||
rt = g_texture_cache->CreateTarget(FRAME_TEX0, t_size, GetValidSize(src, possible_shuffle), (GSConfig.UserHacks_NativeScaling != GSNativeScaling::Off && scale_draw < 0 && is_possible_mem_clear != ClearType::NormalClear) ? ((src && src->m_from_target) ? src->m_from_target->GetScale() : (ds ? ds->m_scale : 1.0f)) : target_scale,
|
||||
GSTextureCache::RenderTarget, true, fm, false, force_preload, preserve_rt_color || possible_shuffle, lookup_rect, src);
|
||||
rt = g_texture_cache->CreateTarget(FRAME_TEX0, t_size, GetValidSize(src, possible_shuffle), (GSConfig.UserHacks_NativeScaling != GSNativeScaling::Off && scale_draw < 0 && is_possible_mem_clear != ClearType::NormalClear) ? ((src && src->m_from_target) ? src->m_from_target->GetScale() : (ds ? ds->m_scale : 1.0f)) : target_scale,
|
||||
GSTextureCache::RenderTarget, true, fm, false, force_preload, preserve_rt_color || possible_shuffle, lookup_rect, src);
|
||||
|
||||
if (!rt) [[unlikely]]
|
||||
{
|
||||
@ -3474,8 +3474,8 @@ void GSRendererHW::Draw()
|
||||
rt->UpdateValidity(GSVector4i::loadh(GSVector2i(GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].pgs.x, GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].pgs.y)), true);
|
||||
}
|
||||
|
||||
if (src && !src->m_from_target && GSLocalMemory::m_psm[src->m_TEX0.PSM].bpp == GSLocalMemory::m_psm[m_context->FRAME.PSM].bpp &&
|
||||
(GSUtil::GetChannelMask(src->m_TEX0.PSM) & GSUtil::GetChannelMask(m_context->FRAME.PSM)) != 0)
|
||||
if (src && !src->m_from_target && GSLocalMemory::m_psm[src->m_TEX0.PSM].bpp == GSLocalMemory::m_psm[m_context->FRAME.PSM].bpp &&
|
||||
(GSUtil::GetChannelMask(src->m_TEX0.PSM) & GSUtil::GetChannelMask(m_context->FRAME.PSM)) != 0)
|
||||
{
|
||||
const u32 draw_end = GSLocalMemory::GetEndBlockAddress(m_cached_ctx.FRAME.Block(), m_cached_ctx.FRAME.FBW, m_cached_ctx.FRAME.PSM, m_r) + 1;
|
||||
const u32 draw_start = GSLocalMemory::GetStartBlockAddress(m_cached_ctx.FRAME.Block(), m_cached_ctx.FRAME.FBW, m_cached_ctx.FRAME.PSM, m_r);
|
||||
@ -3494,7 +3494,7 @@ void GSRendererHW::Draw()
|
||||
src->m_valid_rect = rt->m_valid;
|
||||
src->m_alpha_minmax.first = rt->m_alpha_min;
|
||||
src->m_alpha_minmax.second = rt->m_alpha_max;
|
||||
|
||||
|
||||
const int target_width = std::max(FRAME_TEX0.TBW, 1U);
|
||||
const int page_offset = (src->m_TEX0.TBP0 - rt->m_TEX0.TBP0) >> 5;
|
||||
const int vertical_page_offset = page_offset / target_width;
|
||||
@ -3652,7 +3652,7 @@ void GSRendererHW::Draw()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Z or RT are offset from each other, so we need a temp Z to align it
|
||||
if (ds && rt && ((m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0) != (m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0) || (g_texture_cache->GetTemporaryZ() != nullptr && g_texture_cache->GetTemporaryZInfo().ZBP == ds->m_TEX0.TBP0)))
|
||||
{
|
||||
@ -3716,7 +3716,7 @@ void GSRendererHW::Draw()
|
||||
const GSDrawingContext& next_ctx = m_env.CTXT[get_next_ctx];
|
||||
const int vertical_page_offset = (rt_page_offset / std::max(static_cast<int>(rt->m_TEX0.TBW), 1));
|
||||
const int vertical_offset = vertical_page_offset * frame_psm.pgs.y;
|
||||
const int horizontal_offset = (rt_page_offset - (vertical_page_offset * std::max(static_cast<int>(rt->m_TEX0.TBW), 1))) * frame_psm.pgs.x;
|
||||
const int horizontal_offset = (rt_page_offset - (vertical_page_offset * std::max(static_cast<int>(rt->m_TEX0.TBW), 1))) * frame_psm.pgs.x;
|
||||
|
||||
const u32 horizontal_size = std::max(rt->m_unscaled_size.x, ds->m_unscaled_size.x);
|
||||
const u32 vertical_size = std::max(rt->m_unscaled_size.y, ds->m_unscaled_size.y);
|
||||
@ -3768,7 +3768,6 @@ void GSRendererHW::Draw()
|
||||
src->m_texture = rt->m_texture;
|
||||
src->m_scale = rt->GetScale();
|
||||
src->m_unscaled_size = rt->m_unscaled_size;
|
||||
|
||||
}
|
||||
|
||||
target_scale = rt->GetScale();
|
||||
@ -3884,17 +3883,16 @@ void GSRendererHW::Draw()
|
||||
|
||||
// copy of a 16bit source in to this target, make sure it's opaque and not bilinear to reduce false positives.
|
||||
m_copy_16bit_to_target_shuffle = m_cached_ctx.TEX0.TBP0 != m_cached_ctx.FRAME.Block() && rt->m_32_bits_fmt == true && IsOpaque()
|
||||
&& !(context->TEX1.MMIN & 1) && !src->m_32_bits_fmt && m_cached_ctx.FRAME.FBMSK;
|
||||
&& !(context->TEX1.MMIN & 1) && !src->m_32_bits_fmt && m_cached_ctx.FRAME.FBMSK;
|
||||
|
||||
// It's not actually possible to do a C16->C16 texture shuffle of B to A as they are the same group
|
||||
// However you can do it by using C32 and offsetting the target verticies to point to B A, then mask as appropriate.
|
||||
m_same_group_texture_shuffle = draw_uses_target && (m_cached_ctx.TEX0.PSM & 0xE) == PSMCT32 && (m_cached_ctx.FRAME.PSM & 0x7) == PSMCT16 && (m_vt.m_min.p.x == 8.0f);
|
||||
|
||||
// Both input and output are 16 bits and texture was initially 32 bits! Same for the target, Sonic Unleash makes a new target which really is 16bit.
|
||||
m_texture_shuffle = ((m_same_group_texture_shuffle || (tex_psm.bpp == 16)) && (GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16) &&
|
||||
(shuffle_coords || rt->m_32_bits_fmt)) &&
|
||||
(src->m_32_bits_fmt || m_copy_16bit_to_target_shuffle) &&
|
||||
(draw_sprite_tex || (m_vt.m_primclass == GS_TRIANGLE_CLASS && (m_index.tail % 6) == 0 && TrianglesAreQuads(true)));
|
||||
m_texture_shuffle = ((m_same_group_texture_shuffle || (tex_psm.bpp == 16)) && (GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16) && (shuffle_coords || rt->m_32_bits_fmt)) &&
|
||||
(src->m_32_bits_fmt || m_copy_16bit_to_target_shuffle) &&
|
||||
(draw_sprite_tex || (m_vt.m_primclass == GS_TRIANGLE_CLASS && (m_index.tail % 6) == 0 && TrianglesAreQuads(true)));
|
||||
|
||||
if (m_texture_shuffle && IsSplitTextureShuffle(rt->m_TEX0, rt->m_valid))
|
||||
{
|
||||
@ -4285,7 +4283,8 @@ void GSRendererHW::Draw()
|
||||
{
|
||||
// if the height cache gave a different size to our final size, we need to check if it needs preloading.
|
||||
// Pirates - Legend of the Black Kat starts a draw of 416, but Z is 448 and it preloads the background.
|
||||
if (rt->m_drawn_since_read.rempty() && rt->m_dirty.size() > 0 && new_height && (preserve_rt_color || preserve_rt_alpha)) {
|
||||
if (rt->m_drawn_since_read.rempty() && rt->m_dirty.size() > 0 && new_height && (preserve_rt_color || preserve_rt_alpha))
|
||||
{
|
||||
RGBAMask mask;
|
||||
mask._u32 = preserve_rt_color ? 0x7 : 0;
|
||||
mask.c.a |= preserve_rt_alpha;
|
||||
@ -4659,8 +4658,11 @@ void GSRendererHW::Draw()
|
||||
if (!m_temp_z_full_copy && was_written)
|
||||
{
|
||||
GSVector4i dRect = GSVector4i((z_horizontal_offset + (real_rect.x - horizontal_offset)) * ds->m_scale, (z_vertical_offset + (real_rect.y - vertical_offset)) * ds->m_scale, ((z_horizontal_offset + real_rect.z + (1.0f / ds->m_scale)) - horizontal_offset) * ds->m_scale, (z_vertical_offset + (real_rect.w + (1.0f / ds->m_scale) - vertical_offset)) * ds->m_scale);
|
||||
GSVector4 sRect = GSVector4((real_rect.x * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetWidth()), static_cast<float>(real_rect.y * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetHeight()), ((real_rect.z + (1.0f / ds->m_scale)) * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetWidth()),
|
||||
static_cast<float>((real_rect.w + (1.0f / ds->m_scale)) * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetHeight()));
|
||||
GSVector4 sRect = GSVector4(
|
||||
(real_rect.x * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetWidth()),
|
||||
static_cast<float>(real_rect.y * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetHeight()),
|
||||
((real_rect.z + (1.0f / ds->m_scale)) * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetWidth()),
|
||||
static_cast<float>((real_rect.w + (1.0f / ds->m_scale)) * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetHeight()));
|
||||
|
||||
GL_CACHE("HW: RT in RT Z copy back draw %d z_vert_offset %d rt_vert_offset %d z_horz_offset %d rt_horz_offset %d", s_n, z_vertical_offset, vertical_offset, z_horizontal_offset, horizontal_offset);
|
||||
g_gs_device->StretchRect(g_texture_cache->GetTemporaryZ(), sRect, ds->m_texture, GSVector4(dRect), ShaderConvert::DEPTH_COPY, false);
|
||||
@ -4669,7 +4671,10 @@ void GSRendererHW::Draw()
|
||||
else if (m_temp_z_full_copy)
|
||||
{
|
||||
GSVector4i dRect = GSVector4i((ds->m_valid.x + z_horizontal_offset) * ds->m_scale, (ds->m_valid.y + z_vertical_offset) * ds->m_scale, (ds->m_valid.z + z_horizontal_offset + (1.0f / ds->m_scale)) * ds->m_scale, (ds->m_valid.w + z_vertical_offset + (1.0f / ds->m_scale)) * ds->m_scale);
|
||||
GSVector4 sRect = GSVector4(((ds->m_valid.x + horizontal_offset) * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetWidth()), static_cast<float>((ds->m_valid.y + vertical_offset) * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetHeight()), (((ds->m_valid.z + horizontal_offset) + (1.0f / ds->m_scale)) * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetWidth()),
|
||||
GSVector4 sRect = GSVector4(
|
||||
((ds->m_valid.x + horizontal_offset) * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetWidth()),
|
||||
static_cast<float>((ds->m_valid.y + vertical_offset) * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetHeight()),
|
||||
(((ds->m_valid.z + horizontal_offset) + (1.0f / ds->m_scale)) * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetWidth()),
|
||||
static_cast<float>((ds->m_valid.w + vertical_offset + (1.0f / ds->m_scale)) * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetHeight()));
|
||||
|
||||
GL_CACHE("HW: RT in RT Z copy back draw %d z_vert_offset %d z_offset %d", s_n, z_vertical_offset, vertical_offset);
|
||||
@ -5371,7 +5376,7 @@ __ri bool GSRendererHW::EmulateChannelShuffle(GSTextureCache::Target* src, bool
|
||||
// Page align test to limit false detections (there is a few).
|
||||
GSVector4i min_uv = GSVector4i(m_vt.m_min.t.upld(GSVector4::zero()));
|
||||
ChannelFetch channel = ChannelFetch_NONE;
|
||||
const GSLocalMemory::psm_t& t_psm = GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM];;
|
||||
const GSLocalMemory::psm_t& t_psm = GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM];
|
||||
const GSLocalMemory::psm_t& f_psm = GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM];
|
||||
GSVector4i block_offset = GSVector4i(min_uv.x / t_psm.bs.x, min_uv.y / t_psm.bs.y).xyxy();
|
||||
GSVector4i m_r_block_offset = GSVector4i((m_r.x & (f_psm.pgs.x - 1)) / f_psm.bs.x, (m_r.y & (f_psm.pgs.y - 1)) / f_psm.bs.y);
|
||||
@ -5444,7 +5449,7 @@ __ri bool GSRendererHW::EmulateChannelShuffle(GSTextureCache::Target* src, bool
|
||||
s[1].U = 16384;
|
||||
s[0].V = 0;
|
||||
s[1].V = 16384;
|
||||
|
||||
|
||||
m_r = GSVector4i(0, 0, 1024, 1024);
|
||||
|
||||
// We need to count the pages that get shuffled to, some games (like Hitman Blood Money dialogue blur effects) only do half the screen.
|
||||
@ -5476,7 +5481,7 @@ __ri bool GSRendererHW::EmulateChannelShuffle(GSTextureCache::Target* src, bool
|
||||
if (rt && rt->m_TEX0.TBP0 == m_cached_ctx.FRAME.Block())
|
||||
{
|
||||
const bool req_offset = (m_cached_ctx.CLAMP.WMS != 3 || (m_cached_ctx.CLAMP.MAXU & ~0xF) == 0) &&
|
||||
(m_cached_ctx.CLAMP.WMT != 3 || (m_cached_ctx.CLAMP.MAXV & ~0x3) == 0);
|
||||
(m_cached_ctx.CLAMP.WMT != 3 || (m_cached_ctx.CLAMP.MAXV & ~0x3) == 0);
|
||||
//DevCon.Warning("HW: Draw %d offset %d", s_n, frame_page_offset);
|
||||
// Offset the frame but clear the draw offset
|
||||
if (req_offset)
|
||||
@ -5514,7 +5519,7 @@ __ri bool GSRendererHW::EmulateChannelShuffle(GSTextureCache::Target* src, bool
|
||||
new_valid.w = std::max(new_valid.w, offset_height);
|
||||
rt->UpdateValidity(new_valid, true);
|
||||
}
|
||||
|
||||
|
||||
m_vertex.head = m_vertex.tail = m_vertex.next = 2;
|
||||
m_index.tail = 2;
|
||||
|
||||
@ -5568,7 +5573,7 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
|
||||
#endif
|
||||
|
||||
// If the colour is modulated to zero or we're not using a texture and the color is zero, we can replace any Cs with 0
|
||||
if ((!PRIM->TME || m_cached_ctx.TEX0.TFX != TFX_DECAL) && (!PRIM->FGE || m_draw_env->FOGCOL.U32[0] == 0) &&
|
||||
if ((!PRIM->TME || m_cached_ctx.TEX0.TFX != TFX_DECAL) && (!PRIM->FGE || m_draw_env->FOGCOL.U32[0] == 0) &&
|
||||
((m_vt.m_max.c == GSVector4i::zero()).mask() & 0xfff) == 0xfff)
|
||||
{
|
||||
// If using modulate or is HIGHLIGHT by the vertex alpha is zero, we should be safe to kill it.
|
||||
@ -5739,7 +5744,7 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
|
||||
// Condition 4: If it's tex in fb draw and there's no overlap prefer sw blend, fb is already being read.
|
||||
const bool prefer_sw_blend = (features.texture_barrier && m_conf.require_full_barrier) || (m_conf.require_one_barrier && (no_prim_overlap || m_channel_shuffle)) || m_conf.ps.shuffle || (no_prim_overlap && (m_conf.tex == m_conf.rt));
|
||||
const bool free_blend = blend_non_recursive // Free sw blending, doesn't require barriers or reading fb
|
||||
|| accumulation_blend; // Mix of hw/sw blending
|
||||
|| accumulation_blend; // Mix of hw/sw blending
|
||||
|
||||
// Warning no break on purpose
|
||||
// Note: the [[fallthrough]] attribute tell compilers not to complain about not having breaks.
|
||||
@ -5795,7 +5800,7 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
|
||||
else
|
||||
{
|
||||
const bool ad_second_pass = blend_multi_pass_support && alpha_c1_high_no_rta_correct && COLCLAMP.CLAMP &&
|
||||
(blend_flag & (BLEND_HW3 | BLEND_HW5 | BLEND_HW6 | BLEND_HW7 | BLEND_HW9));
|
||||
(blend_flag & (BLEND_HW3 | BLEND_HW5 | BLEND_HW6 | BLEND_HW7 | BLEND_HW9));
|
||||
|
||||
switch (GSConfig.AccurateBlendingUnit)
|
||||
{
|
||||
@ -6137,7 +6142,7 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
|
||||
|
||||
new_rt_alpha_scale = true;
|
||||
alpha_c1_high_no_rta_correct = false;
|
||||
|
||||
|
||||
m_conf.ps.rta_correction = rt->m_rt_alpha_scale;
|
||||
}
|
||||
|
||||
@ -6307,9 +6312,9 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
|
||||
|
||||
// Remove second color output when unused. Works around bugs in some drivers (e.g. Intel).
|
||||
m_conf.ps.no_color1 = !GSDevice::IsDualSourceBlendFactor(m_conf.blend.src_factor) &&
|
||||
!GSDevice::IsDualSourceBlendFactor(m_conf.blend.dst_factor) &&
|
||||
!GSDevice::IsDualSourceBlendFactor(m_conf.blend_multi_pass.blend.src_factor) &&
|
||||
!GSDevice::IsDualSourceBlendFactor(m_conf.blend_multi_pass.blend.dst_factor);
|
||||
!GSDevice::IsDualSourceBlendFactor(m_conf.blend.dst_factor) &&
|
||||
!GSDevice::IsDualSourceBlendFactor(m_conf.blend_multi_pass.blend.src_factor) &&
|
||||
!GSDevice::IsDualSourceBlendFactor(m_conf.blend_multi_pass.blend.dst_factor);
|
||||
}
|
||||
|
||||
// Notify the shader that it needs to invert rounding
|
||||
@ -6380,9 +6385,9 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
|
||||
// we keep the shader clamp. See #5851 on github, and the note in Draw().
|
||||
[[maybe_unused]] static constexpr const char* clamp_modes[] = {"REPEAT", "CLAMP", "REGION_CLAMP", "REGION_REPEAT"};
|
||||
const bool redundant_wms = IsRedundantClamp(m_cached_ctx.CLAMP.WMS, m_cached_ctx.CLAMP.MINU,
|
||||
m_cached_ctx.CLAMP.MAXU, m_cached_ctx.TEX0.TW);
|
||||
m_cached_ctx.CLAMP.MAXU, m_cached_ctx.TEX0.TW);
|
||||
const bool redundant_wmt = IsRedundantClamp(m_cached_ctx.CLAMP.WMT, m_cached_ctx.CLAMP.MINV,
|
||||
m_cached_ctx.CLAMP.MAXV, m_cached_ctx.TEX0.TH);
|
||||
m_cached_ctx.CLAMP.MAXV, m_cached_ctx.TEX0.TH);
|
||||
const u8 wms = EffectiveClamp(m_cached_ctx.CLAMP.WMS, !tex->m_target && (source_region.HasX() || redundant_wms));
|
||||
const u8 wmt = EffectiveClamp(m_cached_ctx.CLAMP.WMT, !tex->m_target && (source_region.HasY() || redundant_wmt));
|
||||
const bool complex_wms_wmt = !!((wms | wmt) & 2) || target_region;
|
||||
@ -6394,7 +6399,7 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
|
||||
|
||||
const bool need_mipmap = IsMipMapDraw();
|
||||
const bool shader_emulated_sampler = tex->m_palette || (tex->m_target && !m_conf.ps.shuffle && cpsm.fmt != 0) ||
|
||||
complex_wms_wmt || psm.depth || target_region;
|
||||
complex_wms_wmt || psm.depth || target_region;
|
||||
const bool can_trilinear = !tex->m_palette && !tex->m_target && !m_conf.ps.shuffle;
|
||||
const bool trilinear_manual = need_mipmap && GSConfig.HWMipmap;
|
||||
|
||||
@ -6667,7 +6672,7 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
|
||||
// This "fixes" a lot of the rainbow garbage in games when upscaling (and xenosaga shadows + VP2 forest seem quite happy).
|
||||
// Note that this is done on the original texture scale, during upscales it can mess up otherwise.
|
||||
const GSVector4 region_clamp_offset = GSVector4::cxpr(0.5f, 0.5f, 0.1f, 0.1f) + (GSVector4::cxpr(0.1f, 0.1f, 0.0f, 0.0f) * tex->GetScale());
|
||||
|
||||
|
||||
const GSVector4 region_clamp = (GSVector4(clamp) + region_clamp_offset) / WH.xyxy();
|
||||
if (wms >= CLAMP_REGION_CLAMP)
|
||||
{
|
||||
@ -6680,7 +6685,7 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
|
||||
m_conf.cb_ps.MinMax.w = (wmt == CLAMP_REGION_CLAMP && !m_conf.ps.depth_fmt) ? region_clamp.w : region_repeat.w;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (trilinear_manual)
|
||||
{
|
||||
m_conf.cb_ps.LODParams.x = static_cast<float>(m_context->TEX1.K) / 16.0f;
|
||||
@ -6711,8 +6716,8 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
|
||||
|
||||
// Remove linear from trilinear, since we're doing the bilinear in the shader, and we only want this for mip selection.
|
||||
m_conf.sampler.triln = (trilinear >= static_cast<u8>(GS_MIN_FILTER::Linear_Mipmap_Nearest)) ?
|
||||
(trilinear - static_cast<u8>(GS_MIN_FILTER::Nearest_Mipmap_Nearest)) :
|
||||
0;
|
||||
(trilinear - static_cast<u8>(GS_MIN_FILTER::Nearest_Mipmap_Nearest)) :
|
||||
0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -6933,8 +6938,8 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c
|
||||
static_cast<int>(std::ceil(static_cast<float>(copy_size.y) * scale)));
|
||||
|
||||
src_copy.reset(src_target->m_texture->IsDepthStencil() ?
|
||||
g_gs_device->CreateDepthStencil(scaled_copy_size.x, scaled_copy_size.y, src_target->m_texture->GetFormat(), false) :
|
||||
g_gs_device->CreateRenderTarget(scaled_copy_size.x, scaled_copy_size.y, src_target->m_texture->GetFormat(), true, true));
|
||||
g_gs_device->CreateDepthStencil(scaled_copy_size.x, scaled_copy_size.y, src_target->m_texture->GetFormat(), false) :
|
||||
g_gs_device->CreateRenderTarget(scaled_copy_size.x, scaled_copy_size.y, src_target->m_texture->GetFormat(), true, true));
|
||||
if (!src_copy) [[unlikely]]
|
||||
{
|
||||
Console.Error("HW: Failed to allocate %dx%d texture for hazard copy", scaled_copy_size.x, scaled_copy_size.y);
|
||||
@ -6961,8 +6966,8 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c
|
||||
// causing bleeding into the edges of the downsampled texture.
|
||||
const u32 downsample_factor = static_cast<u32>(src_target->GetScale());
|
||||
const GSVector2i clamp_min = (GSConfig.UserHacks_HalfPixelOffset < GSHalfPixelOffset::Native) ?
|
||||
GSVector2i(0, 0) :
|
||||
GSVector2i(downsample_factor, downsample_factor);
|
||||
GSVector2i(0, 0) :
|
||||
GSVector2i(downsample_factor, downsample_factor);
|
||||
GSVector4i copy_rect = tmm.coverage;
|
||||
if (target_region)
|
||||
{
|
||||
@ -7212,7 +7217,7 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
||||
m_conf.ps.scanmsk = env.SCANMSK.MSK;
|
||||
m_conf.rt = rt ? rt->m_texture : nullptr;
|
||||
m_conf.ds = ds ? (m_using_temp_z ? g_texture_cache->GetTemporaryZ() : ds->m_texture) : nullptr;
|
||||
|
||||
|
||||
pxAssert(!ds || !rt || (m_conf.ds->GetSize().x == m_conf.rt->GetSize().x && m_conf.ds->GetSize().y == m_conf.rt->GetSize().y));
|
||||
|
||||
// Z setup has to come before channel shuffle
|
||||
@ -7802,12 +7807,12 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
||||
const int unscaled_y = rt_or_ds ? rt_or_ds->GetUnscaledHeight() : 0;
|
||||
sx = 2.0f / (unscaled_x << 4);
|
||||
sy = 2.0f / (unscaled_y << 4);
|
||||
|
||||
|
||||
if (GSConfig.UserHacks_HalfPixelOffset == GSHalfPixelOffset::NativeWTexOffset)
|
||||
{
|
||||
ox2 = (-1.0f / (unscaled_x * rtscale));
|
||||
oy2 = (-1.0f / (unscaled_y * rtscale));
|
||||
|
||||
|
||||
// Having the vertex negatively offset is a common thing for copying sprites but this causes problems when upscaling, so we need to further adjust the offset.
|
||||
// This kinda screws things up when using ST, so let's not.
|
||||
if (m_vt.m_primclass == GS_SPRITE_CLASS && rtscale > 1.0f && (tex && PRIM->FST))
|
||||
@ -8127,7 +8132,7 @@ GSRendererHW::CLUTDrawTestResult GSRendererHW::PossibleCLUTDraw()
|
||||
const float draw_width = (m_vt.m_max.p.x - m_vt.m_min.p.x);
|
||||
const float draw_height = (m_vt.m_max.p.y - m_vt.m_min.p.y);
|
||||
const bool valid_size = ((draw_width >= min_clut_width || draw_height >= min_clut_height))
|
||||
&& (((draw_width < page_width && draw_height <= page_height) || (draw_width == page_width)) && draw_divder_match); // Make sure draw is multiples of 8 wide (AC5 midetection).
|
||||
&& (((draw_width < page_width && draw_height <= page_height) || (draw_width == page_width)) && draw_divder_match); // Make sure draw is multiples of 8 wide (AC5 midetection).
|
||||
|
||||
// Make sure the draw hits the next CLUT and it's marked as invalid (kind of a sanity check).
|
||||
// We can also allow draws which are of a sensible size within the page, as they could also be CLUT draws (or gradients for the CLUT).
|
||||
@ -8257,7 +8262,7 @@ bool GSRendererHW::CanUseSwPrimRender(bool no_rt, bool no_ds, bool draw_sprite_t
|
||||
{
|
||||
GSTextureCache::Target* dst_target = g_texture_cache->GetTargetWithSharedBits(m_cached_ctx.FRAME.Block(), m_cached_ctx.FRAME.PSM);
|
||||
|
||||
if (dst_target && dst_target->m_dirty.empty() && ((!(GSUtil::GetChannelMask(m_cached_ctx.FRAME.PSM) & 0x7)) || dst_target->m_valid_rgb) &&
|
||||
if (dst_target && dst_target->m_dirty.empty() && ((!(GSUtil::GetChannelMask(m_cached_ctx.FRAME.PSM) & 0x7)) || dst_target->m_valid_rgb) &&
|
||||
((!(GSUtil::GetChannelMask(m_cached_ctx.FRAME.PSM) & 0x8)) || (dst_target->m_valid_alpha_low && dst_target->m_valid_alpha_high)))
|
||||
return false;
|
||||
}
|
||||
@ -8355,12 +8360,11 @@ bool GSRendererHW::DetectStripedDoubleClear(bool& no_rt, bool& no_ds)
|
||||
{
|
||||
const bool single_page_offset =
|
||||
std::abs(static_cast<int>(m_cached_ctx.FRAME.FBP) - static_cast<int>(m_cached_ctx.ZBUF.ZBP)) == 1;
|
||||
const bool z_is_frame = (m_cached_ctx.FRAME.FBP == m_cached_ctx.ZBUF.ZBP ||
|
||||
(m_cached_ctx.FRAME.FBW > 1 && single_page_offset)) && // GT4O Public Beta
|
||||
!m_cached_ctx.ZBUF.ZMSK &&
|
||||
(m_cached_ctx.FRAME.PSM & 0x30) != (m_cached_ctx.ZBUF.PSM & 0x30) &&
|
||||
(m_cached_ctx.FRAME.PSM & 0xF) == (m_cached_ctx.ZBUF.PSM & 0xF) && m_vt.m_eq.z == 1 &&
|
||||
m_vertex.buff[1].XYZ.Z == m_vertex.buff[1].RGBAQ.U32[0];
|
||||
const bool z_is_frame = (m_cached_ctx.FRAME.FBP == m_cached_ctx.ZBUF.ZBP || (m_cached_ctx.FRAME.FBW > 1 && single_page_offset)) && // GT4O Public Beta
|
||||
!m_cached_ctx.ZBUF.ZMSK &&
|
||||
(m_cached_ctx.FRAME.PSM & 0x30) != (m_cached_ctx.ZBUF.PSM & 0x30) &&
|
||||
(m_cached_ctx.FRAME.PSM & 0xF) == (m_cached_ctx.ZBUF.PSM & 0xF) && m_vt.m_eq.z == 1 &&
|
||||
m_vertex.buff[1].XYZ.Z == m_vertex.buff[1].RGBAQ.U32[0];
|
||||
|
||||
// Z and color must be constant and the same and must be drawing strips.
|
||||
if (!z_is_frame || m_vt.m_eq.rgba != 0xFFFF)
|
||||
@ -8874,7 +8878,7 @@ void GSRendererHW::ClearGSLocalMemory(const GSOffset& off, const GSVector4i& r,
|
||||
else if (format == GSLocalMemory::PSM_FMT_16)
|
||||
{
|
||||
const u16 converted_color = ((vert_color >> 16) & 0x8000) | ((vert_color >> 9) & 0x7C00) |
|
||||
((vert_color >> 6) & 0x7E0) | ((vert_color >> 3) & 0x1F);
|
||||
((vert_color >> 6) & 0x7E0) | ((vert_color >> 3) & 0x1F);
|
||||
const GSVector4i vcolor = GSVector4i::broadcast16(converted_color);
|
||||
const u32 iterations_per_page = (pages_wide * pixels_per_page) / 8;
|
||||
pxAssert((off.bp() & (GS_BLOCKS_PER_PAGE - 1)) == 0);
|
||||
@ -8997,27 +9001,27 @@ bool GSRendererHW::OI_BlitFMV(GSTextureCache::Target* _rt, GSTextureCache::Sourc
|
||||
bool GSRendererHW::AreAnyPixelsDiscarded() const
|
||||
{
|
||||
return ((m_draw_env->SCANMSK.MSK & 2) || // skipping rows
|
||||
(m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.AFAIL != AFAIL_FB_ONLY) || // testing alpha (might discard some pixels)
|
||||
m_cached_ctx.TEST.DATE); // reading alpha
|
||||
(m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.AFAIL != AFAIL_FB_ONLY) || // testing alpha (might discard some pixels)
|
||||
m_cached_ctx.TEST.DATE); // reading alpha
|
||||
}
|
||||
|
||||
bool GSRendererHW::IsDiscardingDstColor()
|
||||
{
|
||||
return ((!PRIM->ABE || IsOpaque() || m_context->ALPHA.IsBlack()) && // no blending or writing black
|
||||
!AreAnyPixelsDiscarded() && (m_cached_ctx.FRAME.FBMSK & GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].fmsk) == 0); // no channels masked
|
||||
!AreAnyPixelsDiscarded() && (m_cached_ctx.FRAME.FBMSK & GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].fmsk) == 0); // no channels masked
|
||||
}
|
||||
|
||||
bool GSRendererHW::IsDiscardingDstRGB()
|
||||
{
|
||||
return ((!PRIM->ABE || IsOpaque() || m_context->ALPHA.IsBlack() || !m_context->ALPHA.IsCdInBlend()) && // no blending or writing black
|
||||
((m_cached_ctx.FRAME.FBMSK & GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].fmsk) & 0xFFFFFFu) == 0); // RGB isn't masked
|
||||
((m_cached_ctx.FRAME.FBMSK & GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].fmsk) & 0xFFFFFFu) == 0); // RGB isn't masked
|
||||
}
|
||||
|
||||
bool GSRendererHW::IsDiscardingDstAlpha() const
|
||||
{
|
||||
return ((!PRIM->ABE || m_context->ALPHA.C != 1) && // not using Ad
|
||||
((m_cached_ctx.FRAME.FBMSK & GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].fmsk) & 0xFF000000u) == 0) && // alpha isn't masked
|
||||
(!m_cached_ctx.TEST.ATE || !(m_cached_ctx.TEST.ATST == ATST_NEVER && m_cached_ctx.TEST.AFAIL == AFAIL_RGB_ONLY && m_cached_ctx.FRAME.PSM == PSMCT32)); // No alpha test or no rbg only
|
||||
((m_cached_ctx.FRAME.FBMSK & GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].fmsk) & 0xFF000000u) == 0) && // alpha isn't masked
|
||||
(!m_cached_ctx.TEST.ATE || !(m_cached_ctx.TEST.ATST == ATST_NEVER && m_cached_ctx.TEST.AFAIL == AFAIL_RGB_ONLY && m_cached_ctx.FRAME.PSM == PSMCT32)); // No alpha test or no rbg only
|
||||
}
|
||||
|
||||
// Like PrimitiveCoversWithoutGaps but with texture coordinates.
|
||||
@ -9068,12 +9072,12 @@ bool GSRendererHW::TextureCoversWithoutGapsNotEqual()
|
||||
const int this_start_U = v[i].U;
|
||||
const int last_start_U = v[i - 2].U;
|
||||
|
||||
const int dtU = v[i + 1].U - v[i].U;
|
||||
const int dtU = v[i + 1].U - v[i].U;
|
||||
|
||||
if (this_start_U < last_start_U)
|
||||
{
|
||||
if (std::abs(dtU - last_start_U) >= 16 || std::abs(this_start_U) >= 16)
|
||||
{;
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -9440,7 +9444,7 @@ void GSRendererHW::EndHLEHardwareDraw(bool force_copy_on_hazard /* = false */)
|
||||
return;
|
||||
}
|
||||
|
||||
const GSVector4i copy_rect = config.drawarea.rintersect(src->GetRect());
|
||||
const GSVector4i copy_rect = config.drawarea.rintersect(src->GetRect());
|
||||
g_gs_device->CopyRect(src, copy, copy_rect - copy_rect.xyxy(), copy_rect.x, copy_rect.y);
|
||||
config.tex = copy;
|
||||
}
|
||||
@ -9449,8 +9453,8 @@ void GSRendererHW::EndHLEHardwareDraw(bool force_copy_on_hazard /* = false */)
|
||||
// Drop color1 if dual-source is not being used.
|
||||
config.ps.no_color = !config.rt;
|
||||
config.ps.no_color1 = !config.rt || !config.blend.enable ||
|
||||
(!GSDevice::IsDualSourceBlendFactor(config.blend.src_factor) &&
|
||||
!GSDevice::IsDualSourceBlendFactor(config.blend.dst_factor));
|
||||
(!GSDevice::IsDualSourceBlendFactor(config.blend.src_factor) &&
|
||||
!GSDevice::IsDualSourceBlendFactor(config.blend.dst_factor));
|
||||
|
||||
g_gs_device->RenderHW(m_conf);
|
||||
|
||||
|
||||
@ -348,7 +348,7 @@ GSVector4i GSTextureCache::TranslateAlignedRectByPage(u32 tbp, u32 tebp, u32 tbw
|
||||
const int rect_pages = std::max(((in_rect.width() / t_psm.pgs.x) % src_pgw) + ((in_rect.height() / t_psm.pgs.y) * src_pgw), 1);
|
||||
page_offset += rect_offset;
|
||||
in_rect -= GSVector4i(horizontal_offset * t_psm.pgs.x, vertical_offset * t_psm.pgs.y).xyxy();
|
||||
|
||||
|
||||
if (sbw == 0) // Intentionally check this separately
|
||||
{
|
||||
// BW == 0 loops vertically on the first page. So just copy the whole page vertically.
|
||||
@ -391,7 +391,7 @@ GSVector4i GSTextureCache::TranslateAlignedRectByPage(u32 tbp, u32 tebp, u32 tbw
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
|
||||
// Fills full length, so count pages based on the width, adjust rect to fill original rect.
|
||||
// Battle Assault 3 does a move with BW 7 instead of 8 and does 448x512, instead of 512x448. Same result, but confusing for us.
|
||||
@ -1334,7 +1334,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
continue;
|
||||
|
||||
const bool width_match = (std::max(64U, bw * 64U) >> GSLocalMemory::m_psm[psm].info.pageShiftX()) ==
|
||||
(std::max(64U, t->m_TEX0.TBW * 64U) >> GSLocalMemory::m_psm[t->m_TEX0.PSM].info.pageShiftX());
|
||||
(std::max(64U, t->m_TEX0.TBW * 64U) >> GSLocalMemory::m_psm[t->m_TEX0.PSM].info.pageShiftX());
|
||||
|
||||
if (bp == t->m_TEX0.TBP0 && !t->m_dirty.empty() && GSUtil::GetChannelMask(psm) == GSUtil::GetChannelMask(t->m_TEX0.PSM) && GSRendererHW::GetInstance()->m_draw_transfers.size() > 0)
|
||||
{
|
||||
@ -1461,7 +1461,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
{
|
||||
rect_clean = false;
|
||||
|
||||
if(!dirty_rect.rintersect(t->m_valid).eq(t->m_valid) || GSUtil::GetChannelMask(t->m_TEX0.PSM) != t->m_dirty.GetDirtyChannels())
|
||||
if (!dirty_rect.rintersect(t->m_valid).eq(t->m_valid) || GSUtil::GetChannelMask(t->m_TEX0.PSM) != t->m_dirty.GetDirtyChannels())
|
||||
partial |= !new_rect.rintersect(dirty_rect).eq(new_rect) || dirty_rect.eq(new_rect);
|
||||
else // Nothing is valid anymore, kill it.
|
||||
{
|
||||
@ -1484,7 +1484,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
const u32 channels = t->m_dirty.GetDirtyChannels() & channel_mask;
|
||||
const bool dirty_overlap = !t->m_dirty.GetTotalRect(t->m_TEX0, t->m_unscaled_size).rintersect(new_rect).rempty();
|
||||
// If the source is reading the rt, make sure it's big enough.
|
||||
if (!possible_shuffle && t && GSUtil::HasCompatibleBits(psm, t->m_TEX0.PSM)&& real_fmt_match)
|
||||
if (!possible_shuffle && t && GSUtil::HasCompatibleBits(psm, t->m_TEX0.PSM) && real_fmt_match)
|
||||
{
|
||||
// Be careful if a new texture has been uploaded that expands the current one (Valkyrie Profile 2 does this)
|
||||
GSVector4i dirty_rect = (t->m_dirty.size() > 0 && bw == t->m_TEX0.TBW) ? t->m_dirty.GetTotalRect(t->m_TEX0, GSVector2i(new_rect.z, new_rect.w)) : GSVector4i(GSVector4(t->m_valid) * GSVector4(2));
|
||||
@ -1595,7 +1595,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
const u32 color_psm = ((psm & 0x30) == 0x30) ? (psm & ~0x30) : psm;
|
||||
const u32 tex_color_psm = ((t->m_TEX0.PSM & 0x30) == 0x30) ? (t->m_TEX0.PSM & ~0x30) : t->m_TEX0.PSM;
|
||||
const bool can_convert = (GSUtil::HasCompatibleBits(psm, t_psm) && ((bw == t->m_TEX0.TBW) || (bw <= 1 && req_rect.w < GSLocalMemory::m_psm[psm].pgs.y))) ||
|
||||
(possible_shuffle && ((bw == t->m_TEX0.TBW) || (bw == (t->m_TEX0.TBW * 2) || bw <= 2)) && GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp == 32);
|
||||
(possible_shuffle && ((bw == t->m_TEX0.TBW) || (bw == (t->m_TEX0.TBW * 2) || bw <= 2)) && GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp == 32);
|
||||
|
||||
if (t->m_was_dst_matched)
|
||||
{
|
||||
@ -1608,7 +1608,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
for (Target* dst_match : m_dst[DepthStencil])
|
||||
{
|
||||
// Be careful of dirty overlap on the targets, we don't really want dirty data.
|
||||
if (dst_match->m_TEX0.TBP0 != t->m_TEX0.TBP0 || !dst_match->m_valid_rgb ||(!dst_match->m_dirty.empty() && !dst_match->m_dirty.GetTotalRect(dst_match->m_TEX0, dst_match->m_unscaled_size).rintersect(block_boundary_rect).rempty()))
|
||||
if (dst_match->m_TEX0.TBP0 != t->m_TEX0.TBP0 || !dst_match->m_valid_rgb || (!dst_match->m_dirty.empty() && !dst_match->m_dirty.GetTotalRect(dst_match->m_TEX0, dst_match->m_unscaled_size).rintersect(block_boundary_rect).rempty()))
|
||||
continue;
|
||||
|
||||
if (!CopyRGBFromDepthToColor(t, dst_match))
|
||||
@ -1684,8 +1684,8 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
// Make sure the texture actually is INSIDE the RT, it's possibly not valid if it isn't.
|
||||
// Also check BP >= TBP, create source isn't equpped to expand it backwards and all data comes from the target. (GH3)
|
||||
else if (GSConfig.UserHacks_TextureInsideRt >= GSTextureInRtMode::InsideTargets &&
|
||||
(GSLocalMemory::m_psm[color_psm].bpp >= 16 || (/*possible_shuffle &&*/ GSLocalMemory::m_psm[color_psm].bpp == 8 && GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp >= 16)) && // Channel shuffles or non indexed lookups.
|
||||
t->m_age <= 1 && (!found_t || t->m_last_draw > dst->m_last_draw) /*&& CanTranslate(bp, bw, psm, block_boundary_rect, t->m_TEX0.TBP0, t->m_TEX0.PSM, t->m_TEX0.TBW)*/)
|
||||
(GSLocalMemory::m_psm[color_psm].bpp >= 16 || (/*possible_shuffle &&*/ GSLocalMemory::m_psm[color_psm].bpp == 8 && GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp >= 16)) && // Channel shuffles or non indexed lookups.
|
||||
t->m_age <= 1 && (!found_t || t->m_last_draw > dst->m_last_draw) /*&& CanTranslate(bp, bw, psm, block_boundary_rect, t->m_TEX0.TBP0, t->m_TEX0.PSM, t->m_TEX0.TBW)*/)
|
||||
{
|
||||
u32 rt_tbw = std::max(1U, t->m_TEX0.TBW);
|
||||
u32 horz_page_offset = ((bp - t->m_TEX0.TBP0) >> 5) % rt_tbw;
|
||||
@ -1694,18 +1694,20 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
continue;
|
||||
|
||||
if (GSLocalMemory::m_psm[color_psm].bpp == 16 && GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp == 32 && bw != 1 &&
|
||||
((t->m_TEX0.TBW < (horz_page_offset + ((block_boundary_rect.z + GSLocalMemory::m_psm[psm].pgs.x - 1) / GSLocalMemory::m_psm[psm].pgs.x)) ||
|
||||
(t->m_TEX0.TBW != bw && block_boundary_rect.w > GSLocalMemory::m_psm[psm].pgs.y))))
|
||||
((t->m_TEX0.TBW < (horz_page_offset + ((block_boundary_rect.z + GSLocalMemory::m_psm[psm].pgs.x - 1) / GSLocalMemory::m_psm[psm].pgs.x)) ||
|
||||
(t->m_TEX0.TBW != bw && block_boundary_rect.w > GSLocalMemory::m_psm[psm].pgs.y))))
|
||||
{
|
||||
DbgCon.Warning("BP %x - 16bit bad match for target bp %x bw %d src %d format %d", bp, t->m_TEX0.TBP0, t->m_TEX0.TBW, bw, t->m_TEX0.PSM);
|
||||
continue;
|
||||
}
|
||||
// Keep note that 2 bw is basically 1 normal page, as bw is in 64 pixels, and 8bit pages are 128 pixels wide, aka 2 bw.
|
||||
// Also check for 4HH/HL and 8H which use the alpha channel, if the page order is wrong this can cause problems as well (Jak X font).
|
||||
else if (!possible_shuffle && GSLocalMemory::m_psm[psm].trbpp <= 8 && (GSUtil::GetChannelMask(t->m_TEX0.PSM) != 0xF ||
|
||||
((GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp != 16 || GSLocalMemory::m_psm[psm].bpp < 16) && (!(block_boundary_rect.w <= GSLocalMemory::m_psm[psm].pgs.y &&
|
||||
((GSLocalMemory::m_psm[psm].bpp == 32) ? bw : ((bw + 1) / 2)) <= t->m_TEX0.TBW) &&
|
||||
!(((GSLocalMemory::m_psm[psm].bpp == 32) ? bw : ((bw + 1) / 2)) == rt_tbw)))))
|
||||
else if (!possible_shuffle && GSLocalMemory::m_psm[psm].trbpp <= 8 &&
|
||||
(GSUtil::GetChannelMask(t->m_TEX0.PSM) != 0xF ||
|
||||
((GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp != 16 || GSLocalMemory::m_psm[psm].bpp < 16) &&
|
||||
(!(block_boundary_rect.w <= GSLocalMemory::m_psm[psm].pgs.y &&
|
||||
((GSLocalMemory::m_psm[psm].bpp == 32) ? bw : ((bw + 1) / 2)) <= t->m_TEX0.TBW) &&
|
||||
!(((GSLocalMemory::m_psm[psm].bpp == 32) ? bw : ((bw + 1) / 2)) == rt_tbw)))))
|
||||
{
|
||||
DbgCon.Warning("BP %x - 8bit bad match for target bp %x bw %d src %d format %d", bp, t->m_TEX0.TBP0, t->m_TEX0.TBW, bw, t->m_TEX0.PSM);
|
||||
continue;
|
||||
@ -1870,9 +1872,9 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
const GSOffset offset(GSLocalMemory::m_psm[src_psm].info, bp, bw, psm);
|
||||
const u32 offset_bp = offset.bn(region.GetMinX(), region.GetMinY());
|
||||
if (bp < t->m_TEX0.TBP0 && region.HasX() && region.HasY() &&
|
||||
(region.GetMinX() & (page_size.x - 1)) == 0 && (region.GetMinY() & (page_size.y - 1)) == 0 &&
|
||||
(offset.bn(region.GetMinX(), region.GetMinY()) == t->m_TEX0.TBP0 ||
|
||||
((offset_bp >= t->m_TEX0.TBP0) && ((((offset_bp - t->m_TEX0.TBP0) >> 5) % bw) + (rect.width() / page_size.x)) <= bw)))
|
||||
(region.GetMinX() & (page_size.x - 1)) == 0 && (region.GetMinY() & (page_size.y - 1)) == 0 &&
|
||||
(offset.bn(region.GetMinX(), region.GetMinY()) == t->m_TEX0.TBP0 ||
|
||||
((offset_bp >= t->m_TEX0.TBP0) && ((((offset_bp - t->m_TEX0.TBP0) >> 5) % bw) + (rect.width() / page_size.x)) <= bw)))
|
||||
{
|
||||
GL_CACHE("TC: Target 0x%x detected in front of TBP 0x%x with %d,%d offset (%d pages)",
|
||||
t->m_TEX0.TBP0, TEX0.TBP0, region.GetMinX(), region.GetMinY(),
|
||||
@ -2292,7 +2294,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
||||
if (bp == t->m_TEX0.TBP0)
|
||||
{
|
||||
bool can_use = true;
|
||||
|
||||
|
||||
if (dst && ((GSState::s_n - dst->m_last_draw) < (GSState::s_n - t->m_last_draw) && dst->m_TEX0.TBP0 <= bp))
|
||||
{
|
||||
DevCon.Warning("Ignoring target at %x as one at %x is newer", t->m_TEX0.TBP0, dst->m_TEX0.TBP0);
|
||||
@ -2452,7 +2454,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
||||
const GSVector4i dirty_rect = t->m_dirty.empty() ? GSVector4i::zero() : t->m_dirty.GetTotalRect(t->m_TEX0, t->m_unscaled_size);
|
||||
const bool all_dirty = dirty_rect.eq(t->m_valid);
|
||||
|
||||
|
||||
|
||||
if (!is_shuffle && !dirty_rect.rempty() && (!preserve_alpha && !preserve_rgb) && (GSState::s_n - 3) > t->m_last_draw)
|
||||
{
|
||||
GL_INS("TC: Deleting RT BP 0x%x BW %d PSM %s due to dirty areas not preserved (Likely change in target)", t->m_TEX0.TBP0, t->m_TEX0.TBW, GSUtil::GetPSMName(t->m_TEX0.PSM));
|
||||
@ -2627,7 +2629,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
||||
{
|
||||
calcRescale(dst);
|
||||
GSTexture* tex = type == RenderTarget ? g_gs_device->CreateRenderTarget(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::Color, clear) :
|
||||
g_gs_device->CreateDepthStencil(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::DepthStencil, clear);
|
||||
g_gs_device->CreateDepthStencil(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::DepthStencil, clear);
|
||||
if (!tex)
|
||||
return nullptr;
|
||||
|
||||
@ -2680,8 +2682,11 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
||||
new_scaled_size = ScaleRenderTargetSize(dst->m_unscaled_size, dst->m_scale);
|
||||
|
||||
dRect = (GSVector4(dst->m_valid) * GSVector4(dst->m_scale)).ceil();
|
||||
GSVector4 source_rect = GSVector4(static_cast<float>(dst->m_valid.x) / static_cast<float>(dst->m_unscaled_size.x), static_cast<float>(dst->m_valid.y) / static_cast<float>(dst->m_unscaled_size.y),
|
||||
static_cast<float>(dst->m_valid.z) / static_cast<float>(dst->m_unscaled_size.x), static_cast<float>(dst->m_valid.w) / static_cast<float>(dst->m_unscaled_size.y));
|
||||
GSVector4 source_rect = GSVector4(
|
||||
static_cast<float>(dst->m_valid.x) / static_cast<float>(dst->m_unscaled_size.x),
|
||||
static_cast<float>(dst->m_valid.y) / static_cast<float>(dst->m_unscaled_size.y),
|
||||
static_cast<float>(dst->m_valid.z) / static_cast<float>(dst->m_unscaled_size.x),
|
||||
static_cast<float>(dst->m_valid.w) / static_cast<float>(dst->m_unscaled_size.y));
|
||||
if (!is_shuffle || GSLocalMemory::m_psm[dst->m_TEX0.PSM].bpp == 16)
|
||||
{
|
||||
if (scale_down)
|
||||
@ -2727,7 +2732,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
||||
else
|
||||
{
|
||||
GSTexture* tex = type == RenderTarget ? g_gs_device->CreateRenderTarget(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::Color, clear) :
|
||||
g_gs_device->CreateDepthStencil(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::DepthStencil, clear);
|
||||
g_gs_device->CreateDepthStencil(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::DepthStencil, clear);
|
||||
if (!tex)
|
||||
return nullptr;
|
||||
|
||||
@ -2748,7 +2753,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
||||
else
|
||||
{
|
||||
GSTexture* tex = type == RenderTarget ? g_gs_device->CreateRenderTarget(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::Color, clear) :
|
||||
g_gs_device->CreateDepthStencil(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::DepthStencil, clear);
|
||||
g_gs_device->CreateDepthStencil(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::DepthStencil, clear);
|
||||
if (!tex)
|
||||
return nullptr;
|
||||
|
||||
@ -2769,7 +2774,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
||||
}
|
||||
|
||||
// New format or doing a shuffle to a 32bit target that used to be 16bit
|
||||
if ((!is_shuffle && (GSLocalMemory::m_psm[dst->m_TEX0.PSM].bpp != GSLocalMemory::m_psm[TEX0.PSM].bpp || GSLocalMemory::m_psm[dst->m_TEX0.PSM].depth != GSLocalMemory::m_psm[TEX0.PSM].depth)) ||
|
||||
if ((!is_shuffle && (GSLocalMemory::m_psm[dst->m_TEX0.PSM].bpp != GSLocalMemory::m_psm[TEX0.PSM].bpp || GSLocalMemory::m_psm[dst->m_TEX0.PSM].depth != GSLocalMemory::m_psm[TEX0.PSM].depth)) ||
|
||||
(is_shuffle && GSLocalMemory::m_psm[dst->m_TEX0.PSM].bpp == 16))
|
||||
{
|
||||
if (GSLocalMemory::m_psm[dst->m_TEX0.PSM].depth != GSLocalMemory::m_psm[TEX0.PSM].depth || dst->m_TEX0.TBW != TEX0.TBW)
|
||||
@ -2835,8 +2840,8 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
||||
}
|
||||
|
||||
const ShaderConvert shader = (GSLocalMemory::m_psm[dst->m_TEX0.PSM].trbpp == 16) ? ShaderConvert::RGB5A1_TO_FLOAT16 :
|
||||
(GSLocalMemory::m_psm[dst->m_TEX0.PSM].trbpp == 32) ? ShaderConvert::RGBA8_TO_FLOAT32 :
|
||||
ShaderConvert::RGBA8_TO_FLOAT24;
|
||||
(GSLocalMemory::m_psm[dst->m_TEX0.PSM].trbpp == 32) ? ShaderConvert::RGBA8_TO_FLOAT32 :
|
||||
ShaderConvert::RGBA8_TO_FLOAT24;
|
||||
|
||||
g_gs_device->StretchRect(dst_match->m_texture, GSVector4(0, 0, 1, 1),
|
||||
dst->m_texture, GSVector4(dst->GetUnscaledRect()) * GSVector4(dst->GetScale()), shader, false);
|
||||
@ -2859,10 +2864,8 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
||||
// Unfortunately, we still have an alpha channel to preserve, and we can't clear RGB...
|
||||
// So, create a new target, clear/preload it, and copy RGB in.
|
||||
GSTexture* tex = (type == RenderTarget) ?
|
||||
g_gs_device->CreateRenderTarget(dst->m_texture->GetWidth(),
|
||||
dst->m_texture->GetHeight(), GSTexture::Format::Color, true) :
|
||||
g_gs_device->CreateDepthStencil(dst->m_texture->GetWidth(),
|
||||
dst->m_texture->GetHeight(), GSTexture::Format::DepthStencil, true);
|
||||
g_gs_device->CreateRenderTarget(dst->m_texture->GetWidth(), dst->m_texture->GetHeight(), GSTexture::Format::Color, true) :
|
||||
g_gs_device->CreateDepthStencil(dst->m_texture->GetWidth(), dst->m_texture->GetHeight(), GSTexture::Format::DepthStencil, true);
|
||||
if (!tex)
|
||||
return nullptr;
|
||||
|
||||
@ -2943,7 +2946,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
||||
}
|
||||
// If the format is completely different, but it's the same location, it's likely just overwriting it, so get rid.
|
||||
// Make sure it's not currently in use, that could be bad.
|
||||
if (!is_shuffle && (!ds || (ds != t)) &&
|
||||
if (!is_shuffle && (!ds || (ds != t)) &&
|
||||
t->m_TEX0.TBW != TEX0.TBW && TEX0.TBW != 1 && !preserve_rgb && min_rect.w > GSLocalMemory::m_psm[t->m_TEX0.PSM].pgs.y)
|
||||
{
|
||||
if (src && src->m_target && src->m_from_target == t && src->m_target_direct)
|
||||
@ -3017,7 +3020,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
||||
// If we don't need A, and the existing target doesn't have valid alpha, don't bother converting it.
|
||||
const bool has_alpha = dst_match->HasValidAlpha();
|
||||
const bool preserve_target = (preserve_rgb || (preserve_alpha && has_alpha)) ||
|
||||
!draw_rect.rintersect(dst_match->m_valid).eq(dst_match->m_valid);
|
||||
!draw_rect.rintersect(dst_match->m_valid).eq(dst_match->m_valid);
|
||||
|
||||
bool half_width = false;
|
||||
|
||||
@ -3069,7 +3072,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
||||
GL_CACHE("TC: Lookup Target(Depth) %dx%d, hit Color (0x%x, TBW %d, %s was %s)", new_size.x, new_size.y,
|
||||
bp, TEX0.TBW, GSUtil::GetPSMName(TEX0.PSM), GSUtil::GetPSMName(dst_match->m_TEX0.PSM));
|
||||
shader = (fmt_16_bits) ? ShaderConvert::RGB5A1_TO_FLOAT16 :
|
||||
(ShaderConvert)(static_cast<int>(ShaderConvert::RGBA8_TO_FLOAT32) + psm_s.fmt);
|
||||
(ShaderConvert)(static_cast<int>(ShaderConvert::RGBA8_TO_FLOAT32) + psm_s.fmt);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -3402,7 +3405,7 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const GSVector4i dst_valid = dst->m_valid.rempty() ? GSVector4i::loadh(valid_size) : dst->m_valid;
|
||||
u32 dst_end_block = GSLocalMemory::GetEndBlockAddress(dst->m_TEX0.TBP0, dst->m_TEX0.TBW, dst->m_TEX0.PSM, dst_valid);
|
||||
if (dst_end_block < dst->m_TEX0.TBP0)
|
||||
@ -3433,7 +3436,7 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
|
||||
// Probably best we don't poke the beast if it's being used as the current source.
|
||||
if (src && src->m_target_direct && src->m_from_target == t)
|
||||
continue;
|
||||
|
||||
|
||||
InvalidateSourcesFromTarget(t);
|
||||
i = list.erase(j);
|
||||
delete t;
|
||||
@ -3541,7 +3544,7 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
|
||||
|
||||
GL_INS("TC: RT double buffer copy from FBP 0x%x, %dx%d => %d,%d", t->m_TEX0.TBP0, copy_width, copy_height, 0, dst_offset_scaled_height);
|
||||
|
||||
|
||||
|
||||
// Clear the dirty first
|
||||
t->Update();
|
||||
dst->Update();
|
||||
@ -3621,11 +3624,12 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
|
||||
t->m_was_dst_matched = true;
|
||||
|
||||
dst->ResizeTexture(t->m_unscaled_size.x, t->m_unscaled_size.y);
|
||||
|
||||
const ShaderConvert shader = (GSLocalMemory::m_psm[dst->m_TEX0.PSM].trbpp == 16) ? ShaderConvert::RGB5A1_TO_FLOAT16 :
|
||||
(GSLocalMemory::m_psm[dst->m_TEX0.PSM].trbpp == 32) ? ShaderConvert::RGBA8_TO_FLOAT32 : ShaderConvert::RGBA8_TO_FLOAT24;
|
||||
|
||||
g_gs_device->StretchRect(t->m_texture, GSVector4(0,0,1,1),
|
||||
const ShaderConvert shader = (GSLocalMemory::m_psm[dst->m_TEX0.PSM].trbpp == 16) ? ShaderConvert::RGB5A1_TO_FLOAT16 :
|
||||
(GSLocalMemory::m_psm[dst->m_TEX0.PSM].trbpp == 32) ? ShaderConvert::RGBA8_TO_FLOAT32 :
|
||||
ShaderConvert::RGBA8_TO_FLOAT24;
|
||||
|
||||
g_gs_device->StretchRect(t->m_texture, GSVector4(0, 0, 1, 1),
|
||||
dst->m_texture, GSVector4(t->GetUnscaledRect()) * GSVector4(dst->GetScale()), shader, false);
|
||||
|
||||
break;
|
||||
@ -3658,10 +3662,8 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
|
||||
t->ResizeValidity(t->m_valid);
|
||||
|
||||
GSTexture* tex = (t->m_type == RenderTarget) ?
|
||||
g_gs_device->CreateRenderTarget(t->m_texture->GetWidth(),
|
||||
t->m_texture->GetHeight(), GSTexture::Format::Color, true) :
|
||||
g_gs_device->CreateDepthStencil(t->m_texture->GetWidth(),
|
||||
t->m_texture->GetHeight(), GSTexture::Format::DepthStencil, true);
|
||||
g_gs_device->CreateRenderTarget(t->m_texture->GetWidth(), t->m_texture->GetHeight(), GSTexture::Format::Color, true) :
|
||||
g_gs_device->CreateDepthStencil(t->m_texture->GetWidth(), t->m_texture->GetHeight(), GSTexture::Format::DepthStencil, true);
|
||||
if (tex)
|
||||
{
|
||||
g_gs_device->CopyRect(t->m_texture, tex, GSVector4i(0, height_adjust * t->m_scale, t->m_texture->GetWidth(), t->m_texture->GetHeight()), 0, 0);
|
||||
@ -3702,7 +3704,6 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
i++;
|
||||
}
|
||||
@ -3937,8 +3938,8 @@ float GSTextureCache::ConvertColorToDepth(u32 c, ShaderConvert convert)
|
||||
{
|
||||
case ShaderConvert::RGB5A1_TO_FLOAT16:
|
||||
return static_cast<float>(((c & 0xF8u) >> 3) | (((c >> 8) & 0xF8u) << 2) | (((c >> 16) & 0xF8u) << 7) |
|
||||
(((c >> 24) & 0x80u) << 8)) *
|
||||
mult;
|
||||
(((c >> 24) & 0x80u) << 8)) *
|
||||
mult;
|
||||
|
||||
case ShaderConvert::RGBA8_TO_FLOAT16:
|
||||
return static_cast<float>(c & 0x0000FFFF) * mult;
|
||||
@ -4185,7 +4186,7 @@ void GSTextureCache::InvalidateContainedTargets(u32 start_bp, u32 end_bp, u32 wr
|
||||
if (type == DepthStencil && t->m_TEX0.TBP0 < start_bp && t->m_end_block > start_bp)
|
||||
{
|
||||
const GSVector4i masked_valid = GSVector4i(t->m_valid.x, t->m_valid.y, t->m_valid.z & ~1, t->m_valid.w & ~1);
|
||||
const u32 reduced_endblock = GSLocalMemory::GetEndBlockAddress(t->m_TEX0.TBP0, t->m_TEX0.TBW, t->m_TEX0.PSM, masked_valid);
|
||||
const u32 reduced_endblock = GSLocalMemory::GetEndBlockAddress(t->m_TEX0.TBP0, t->m_TEX0.TBW, t->m_TEX0.PSM, masked_valid);
|
||||
|
||||
if (reduced_endblock <= start_bp)
|
||||
{
|
||||
@ -5040,8 +5041,8 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u
|
||||
if (SBP == DBP && (!(GSVector4i(sx, sy, sx + w, sy + h).rintersect(GSVector4i(dx, dy, dx + w, dy + h))).rempty() || renderer_is_directx))
|
||||
{
|
||||
GSTexture* tmp_texture = src->m_texture->IsDepthStencil() ?
|
||||
g_gs_device->CreateDepthStencil(src->m_texture->GetWidth(), src->m_texture->GetHeight(), src->m_texture->GetFormat(), false) :
|
||||
g_gs_device->CreateRenderTarget(src->m_texture->GetWidth(), src->m_texture->GetHeight(), src->m_texture->GetFormat(), false);
|
||||
g_gs_device->CreateDepthStencil(src->m_texture->GetWidth(), src->m_texture->GetHeight(), src->m_texture->GetFormat(), false) :
|
||||
g_gs_device->CreateRenderTarget(src->m_texture->GetWidth(), src->m_texture->GetHeight(), src->m_texture->GetFormat(), false);
|
||||
if (!tmp_texture)
|
||||
{
|
||||
Console.Error("(HW Move) Failed to allocate temporary %dx%d texture on HW move", w, h);
|
||||
@ -5109,7 +5110,6 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u
|
||||
}
|
||||
const GSVector4 src_rect = GSVector4(scaled_sx, scaled_sy, scaled_sx + scaled_w, scaled_sy + scaled_h) / (GSVector4(src->m_texture->GetSize()).xyxy());
|
||||
g_gs_device->StretchRect(src->m_texture, src_rect, dst->m_texture, GSVector4(scaled_sx, scaled_sy, scaled_sx + scaled_w, scaled_sy + scaled_h), shader, false);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -5725,8 +5725,8 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
|
||||
const bool outside_target = ((x + w) > dst->m_texture->GetWidth() || (y + h) > dst->m_texture->GetHeight());
|
||||
GSTexture* sTex = dst->m_texture;
|
||||
GSTexture* dTex = outside_target ?
|
||||
g_gs_device->CreateRenderTarget(w, h, GSTexture::Format::Color, true, PreferReusedLabelledTexture()) :
|
||||
g_gs_device->CreateTexture(w, h, tlevels, GSTexture::Format::Color, PreferReusedLabelledTexture());
|
||||
g_gs_device->CreateRenderTarget(w, h, GSTexture::Format::Color, true, PreferReusedLabelledTexture()) :
|
||||
g_gs_device->CreateTexture(w, h, tlevels, GSTexture::Format::Color, PreferReusedLabelledTexture());
|
||||
if (!dTex) [[unlikely]]
|
||||
{
|
||||
Console.Error("Failed to allocate %dx%d texture for offset source", w, h);
|
||||
@ -6037,10 +6037,8 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
|
||||
// 'src' is the new texture cache entry (hence the output)
|
||||
GSTexture* sTex = dst->m_texture;
|
||||
GSTexture* dTex = use_texture ?
|
||||
g_gs_device->CreateTexture(new_size.x, new_size.y, 1, GSTexture::Format::Color,
|
||||
PreferReusedLabelledTexture()) :
|
||||
g_gs_device->CreateRenderTarget(new_size.x, new_size.y, GSTexture::Format::Color,
|
||||
source_rect_empty || destX != 0 || destY != 0, PreferReusedLabelledTexture());
|
||||
g_gs_device->CreateTexture(new_size.x, new_size.y, 1, GSTexture::Format::Color, PreferReusedLabelledTexture()) :
|
||||
g_gs_device->CreateRenderTarget(new_size.x, new_size.y, GSTexture::Format::Color, source_rect_empty || destX != 0 || destY != 0, PreferReusedLabelledTexture());
|
||||
if (!dTex) [[unlikely]]
|
||||
{
|
||||
Console.Error("Failed to allocate %dx%d texture for target copy to source", new_size.x, new_size.y);
|
||||
@ -6090,7 +6088,7 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
|
||||
|
||||
// Adjust to match a PSMT8 texture (coordinates are double C32, we shouldn't be converting from anything else).
|
||||
x_offset *= 2;
|
||||
if (GSLocalMemory::m_psm[dst->m_TEX0.PSM].bpp == 32)
|
||||
if (GSLocalMemory::m_psm[dst->m_TEX0.PSM].bpp == 32)
|
||||
y_offset *= 2;
|
||||
|
||||
src->m_region.SetX(x_offset, x_offset + tw);
|
||||
@ -6552,7 +6550,7 @@ GSTextureCache::HashCacheEntry* GSTextureCache::LookupHashCache(const GIFRegTEX0
|
||||
{
|
||||
// don't bother hashing if we're not dumping or replacing.
|
||||
const bool dump = GSConfig.DumpReplaceableTextures && (!FMVstarted || GSConfig.DumpTexturesWithFMVActive) &&
|
||||
(clut ? GSConfig.DumpPaletteTextures : GSConfig.DumpDirectTextures);
|
||||
(clut ? GSConfig.DumpPaletteTextures : GSConfig.DumpDirectTextures);
|
||||
const bool replace = GSConfig.LoadTextureReplacements && GSTextureReplacements::HasAnyReplacementTextures();
|
||||
bool can_cache = (TEX0.PSM >= PSMT8H && TEX0.PSM <= PSMT4HH) ? CanPreloadTextureSize(TEX0.TW, TEX0.TH) : CanCacheTextureSize(TEX0.TW, TEX0.TH);
|
||||
if (!dump && !replace && !can_cache)
|
||||
@ -6773,8 +6771,8 @@ GSTextureCache::Target* GSTextureCache::Target::Create(GIFRegTEX0 TEX0, int w, i
|
||||
const int scaled_w = static_cast<int>(std::ceil(static_cast<float>(w) * scale));
|
||||
const int scaled_h = static_cast<int>(std::ceil(static_cast<float>(h) * scale));
|
||||
GSTexture* texture = (type == RenderTarget) ?
|
||||
g_gs_device->CreateRenderTarget(scaled_w, scaled_h, GSTexture::Format::Color, clear, PreferReusedLabelledTexture()) :
|
||||
g_gs_device->CreateDepthStencil(scaled_w, scaled_h, GSTexture::Format::DepthStencil, clear, PreferReusedLabelledTexture());
|
||||
g_gs_device->CreateRenderTarget(scaled_w, scaled_h, GSTexture::Format::Color, clear, PreferReusedLabelledTexture()) :
|
||||
g_gs_device->CreateDepthStencil(scaled_w, scaled_h, GSTexture::Format::DepthStencil, clear, PreferReusedLabelledTexture());
|
||||
if (!texture)
|
||||
return nullptr;
|
||||
|
||||
@ -7314,7 +7312,7 @@ void GSTextureCache::Source::Flush(u32 count, int layer, const GSOffset& off)
|
||||
|
||||
// need to offset if we're a region texture
|
||||
const u8* src = s_unswizzle_buffer + (pitch * static_cast<u32>(std::max(tex_r.top - r.top, 0))) +
|
||||
(static_cast<u32>(std::max(tex_r.left - r.left, 0)) << (m_palette ? 0 : 2));
|
||||
(static_cast<u32>(std::max(tex_r.left - r.left, 0)) << (m_palette ? 0 : 2));
|
||||
m_texture->Update(rint - tex_r.xyxy(), src, pitch, layer);
|
||||
}
|
||||
|
||||
@ -7410,8 +7408,8 @@ GSTextureCache::Target::~Target()
|
||||
if (src->m_from_target == this)
|
||||
{
|
||||
pxFail(fmt::format("Source at TBP {:x} for target at TBP {:x} on target invalidation",
|
||||
static_cast<u32>(src->m_TEX0.TBP0), static_cast<u32>(m_TEX0.TBP0))
|
||||
.c_str());
|
||||
static_cast<u32>(src->m_TEX0.TBP0), static_cast<u32>(m_TEX0.TBP0)
|
||||
).c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -7749,10 +7747,8 @@ bool GSTextureCache::Target::ResizeTexture(int new_unscaled_width, int new_unsca
|
||||
const bool clear = (new_size.x > size.x || new_size.y > size.y);
|
||||
|
||||
GSTexture* tex = m_texture->IsDepthStencil() ?
|
||||
g_gs_device->CreateDepthStencil(new_size.x, new_size.y, m_texture->GetFormat(), clear,
|
||||
PreferReusedLabelledTexture()) :
|
||||
g_gs_device->CreateRenderTarget(new_size.x, new_size.y, m_texture->GetFormat(), clear,
|
||||
PreferReusedLabelledTexture());
|
||||
g_gs_device->CreateDepthStencil(new_size.x, new_size.y, m_texture->GetFormat(), clear, PreferReusedLabelledTexture()) :
|
||||
g_gs_device->CreateRenderTarget(new_size.x, new_size.y, m_texture->GetFormat(), clear, PreferReusedLabelledTexture());
|
||||
if (!tex)
|
||||
{
|
||||
Console.Error("(ResizeTexture) Failed to allocate %dx%d texture from %dx%d texture", size.x, size.y, new_size.x, new_size.y);
|
||||
@ -8261,8 +8257,8 @@ u64 GSTextureCache::PaletteKeyHash::operator()(const PaletteKey& key) const
|
||||
{
|
||||
pxAssert(key.pal == 16 || key.pal == 256);
|
||||
return key.pal == 16 ?
|
||||
GSXXH3_64bits(key.clut, sizeof(key.clut[0]) * 16) :
|
||||
GSXXH3_64bits(key.clut, sizeof(key.clut[0]) * 256);
|
||||
GSXXH3_64bits(key.clut, sizeof(key.clut[0]) * 16) :
|
||||
GSXXH3_64bits(key.clut, sizeof(key.clut[0]) * 256);
|
||||
};
|
||||
|
||||
// GSTextureCache::PaletteKeyEqual
|
||||
@ -8571,7 +8567,7 @@ static void HashTextureLevel(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, GST
|
||||
|
||||
// Hash the expanded texture.
|
||||
u8* ptr = temp + (pitch * static_cast<u32>(rect.top - block_rect.top)) +
|
||||
static_cast<u32>(rect.left - block_rect.left);
|
||||
static_cast<u32>(rect.left - block_rect.left);
|
||||
if (pitch == row_size)
|
||||
{
|
||||
BlockHashAccumulate(hash_st, ptr, pitch * static_cast<u32>(th));
|
||||
@ -8649,7 +8645,7 @@ void GSTextureCache::PreloadTexture(const GIFRegTEX0& TEX0, const GIFRegTEXA& TE
|
||||
rtx(mem, off, block_rect, buff, pitch, TEXA);
|
||||
|
||||
const u8* ptr = buff + (pitch * static_cast<u32>(rect.top - block_rect.top)) +
|
||||
(static_cast<u32>(rect.left - block_rect.left) << (paltex ? 0 : 2));
|
||||
(static_cast<u32>(rect.left - block_rect.left) << (paltex ? 0 : 2));
|
||||
|
||||
if (alpha_minmax)
|
||||
*alpha_minmax = GSGetRGBA8AlphaMinMax(ptr, unoffset_rect.width(), unoffset_rect.height(), pitch);
|
||||
|
||||
@ -290,7 +290,7 @@ public:
|
||||
public:
|
||||
HashCacheEntry* m_from_hash_cache = nullptr;
|
||||
std::shared_ptr<Palette> m_palette_obj;
|
||||
std::unique_ptr<u32[]> m_valid;// each u32 bits map to the 32 blocks of that page
|
||||
std::unique_ptr<u32[]> m_valid; // each u32 bits map to the 32 blocks of that page
|
||||
GSTexture* m_palette = nullptr;
|
||||
GSVector4i m_valid_rect = {};
|
||||
GSVector2i m_lod = {};
|
||||
@ -398,13 +398,13 @@ public:
|
||||
|
||||
struct SurfaceOffsetKey
|
||||
{
|
||||
std::array<SurfaceOffsetKeyElem, 2> elems; // A and B elems.
|
||||
std::array<SurfaceOffsetKeyElem, 2> elems; // A and B elems.
|
||||
};
|
||||
|
||||
struct SurfaceOffset
|
||||
{
|
||||
bool is_valid;
|
||||
GSVector4i b2a_offset; // B to A offset in B coords.
|
||||
GSVector4i b2a_offset; // B to A offset in B coords.
|
||||
};
|
||||
|
||||
struct SurfaceOffsetKeyHash
|
||||
@ -504,9 +504,9 @@ public:
|
||||
Target* FindTargetOverlap(Target* target, int type, int psm);
|
||||
void CombineAlignedInsideTargets(Target* target, GSTextureCache::Source* src = nullptr);
|
||||
Target* LookupTarget(GIFRegTEX0 TEX0, const GSVector2i& size, float scale, int type, bool used = true, u32 fbmask = 0,
|
||||
bool is_frame = false, bool preload = GSConfig.PreloadFrameWithGSData, bool preserve_rgb = true, bool preserve_alpha = true,
|
||||
bool is_frame = false, bool preload = GSConfig.PreloadFrameWithGSData, bool preserve_rgb = true, bool preserve_alpha = true,
|
||||
const GSVector4i draw_rc = GSVector4i::zero(), bool is_shuffle = false, bool possible_clear = false, bool preserve_scale = false, GSTextureCache::Source* src = nullptr, GSTextureCache::Target* ds = nullptr, int offset = -1);
|
||||
Target* CreateTarget(GIFRegTEX0 TEX0, const GSVector2i& size, const GSVector2i& valid_size,float scale, int type, bool used = true, u32 fbmask = 0,
|
||||
Target* CreateTarget(GIFRegTEX0 TEX0, const GSVector2i& size, const GSVector2i& valid_size, float scale, int type, bool used = true, u32 fbmask = 0,
|
||||
bool is_frame = false, bool preload = GSConfig.PreloadFrameWithGSData, bool preserve_target = true,
|
||||
const GSVector4i draw_rc = GSVector4i::zero(), GSTextureCache::Source* src = nullptr);
|
||||
Target* LookupDisplayTarget(GIFRegTEX0 TEX0, const GSVector2i& size, float scale, bool is_feedback);
|
||||
|
||||
@ -380,10 +380,8 @@ constexpr DDS_PIXELFORMAT DDSPF_R8G8B8 = {
|
||||
|
||||
static bool DDSPixelFormatMatches(const DDS_PIXELFORMAT& pf1, const DDS_PIXELFORMAT& pf2)
|
||||
{
|
||||
return std::tie(pf1.dwSize, pf1.dwFlags, pf1.dwFourCC, pf1.dwRGBBitCount, pf1.dwRBitMask,
|
||||
pf1.dwGBitMask, pf1.dwGBitMask, pf1.dwBBitMask, pf1.dwABitMask) ==
|
||||
std::tie(pf2.dwSize, pf2.dwFlags, pf2.dwFourCC, pf2.dwRGBBitCount, pf2.dwRBitMask,
|
||||
pf2.dwGBitMask, pf2.dwGBitMask, pf2.dwBBitMask, pf2.dwABitMask);
|
||||
return std::tie(pf1.dwSize, pf1.dwFlags, pf1.dwFourCC, pf1.dwRGBBitCount, pf1.dwRBitMask, pf1.dwGBitMask, pf1.dwGBitMask, pf1.dwBBitMask, pf1.dwABitMask) ==
|
||||
std::tie(pf2.dwSize, pf2.dwFlags, pf2.dwFourCC, pf2.dwRGBBitCount, pf2.dwRBitMask, pf2.dwGBitMask, pf2.dwGBitMask, pf2.dwBBitMask, pf2.dwABitMask);
|
||||
}
|
||||
|
||||
struct DDSLoadInfo
|
||||
|
||||
@ -363,7 +363,7 @@ std::unique_ptr<GSDownloadTextureOGL> GSDownloadTextureOGL::Create(u32 width, u3
|
||||
const u32 buffer_size = GetBufferSize(width, height, format, TEXTURE_UPLOAD_PITCH_ALIGNMENT);
|
||||
|
||||
const bool use_buffer_storage = (GLAD_GL_VERSION_4_4 || GLAD_GL_ARB_buffer_storage || GLAD_GL_EXT_buffer_storage) &&
|
||||
!GSDeviceOGL::GetInstance()->IsDownloadPBODisabled();
|
||||
!GSDeviceOGL::GetInstance()->IsDownloadPBODisabled();
|
||||
if (use_buffer_storage)
|
||||
{
|
||||
GLuint buffer_id;
|
||||
|
||||
@ -658,8 +658,8 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer
|
||||
vkGetDeviceQueue(m_device, m_present_queue_family_index, 0, &m_present_queue);
|
||||
}
|
||||
m_spinning_supported = m_spin_queue_family_index != queue_family_count &&
|
||||
queue_family_properties[m_graphics_queue_family_index].timestampValidBits > 0 &&
|
||||
m_device_properties.limits.timestampPeriod > 0;
|
||||
queue_family_properties[m_graphics_queue_family_index].timestampValidBits > 0 &&
|
||||
m_device_properties.limits.timestampPeriod > 0;
|
||||
m_spin_queue_is_graphics_queue =
|
||||
m_spin_queue_family_index == m_graphics_queue_family_index && spin_queue_index == 0;
|
||||
|
||||
@ -1089,7 +1089,7 @@ bool GSDeviceVK::SetGPUTimingEnabled(bool enabled)
|
||||
void GSDeviceVK::ScanForCommandBufferCompletion()
|
||||
{
|
||||
for (u32 check_index = (m_current_frame + 1) % NUM_COMMAND_BUFFERS; check_index != m_current_frame;
|
||||
check_index = (check_index + 1) % NUM_COMMAND_BUFFERS)
|
||||
check_index = (check_index + 1) % NUM_COMMAND_BUFFERS)
|
||||
{
|
||||
FrameResources& resources = m_frame_resources[check_index];
|
||||
if (resources.fence_counter <= m_completed_fence_counter)
|
||||
@ -2719,8 +2719,8 @@ VkFormat GSDeviceVK::LookupNativeFormat(GSTexture::Format format) const
|
||||
}};
|
||||
|
||||
return (format != GSTexture::Format::DepthStencil || m_features.stencil_buffer) ?
|
||||
s_format_mapping[static_cast<int>(format)] :
|
||||
VK_FORMAT_D32_SFLOAT;
|
||||
s_format_mapping[static_cast<int>(format)] :
|
||||
VK_FORMAT_D32_SFLOAT;
|
||||
}
|
||||
|
||||
GSTexture* GSDeviceVK::CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format)
|
||||
@ -3197,12 +3197,10 @@ void GSDeviceVK::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
|
||||
EndRenderPass();
|
||||
|
||||
// transition everything before starting the new render pass
|
||||
const bool has_input_0 =
|
||||
(sTex[0] && (sTex[0]->GetState() == GSTexture::State::Dirty ||
|
||||
(sTex[0]->GetState() == GSTexture::State::Cleared || sTex[0]->GetClearColor() != 0)));
|
||||
const bool has_input_0 = (sTex[0] &&
|
||||
(sTex[0]->GetState() == GSTexture::State::Dirty || (sTex[0]->GetState() == GSTexture::State::Cleared || sTex[0]->GetClearColor() != 0)));
|
||||
const bool has_input_1 = (PMODE.SLBG == 0 || feedback_write_2_but_blend_bg) && sTex[1] &&
|
||||
(sTex[1]->GetState() == GSTexture::State::Dirty ||
|
||||
(sTex[1]->GetState() == GSTexture::State::Cleared || sTex[1]->GetClearColor() != 0));
|
||||
(sTex[1]->GetState() == GSTexture::State::Dirty || (sTex[1]->GetState() == GSTexture::State::Cleared || sTex[1]->GetClearColor() != 0));
|
||||
if (has_input_0)
|
||||
{
|
||||
static_cast<GSTextureVK*>(sTex[0])->CommitClear();
|
||||
@ -3825,15 +3823,14 @@ bool GSDeviceVK::CreateRenderPasses()
|
||||
{
|
||||
for (u32 opa = VK_ATTACHMENT_LOAD_OP_LOAD; opa <= VK_ATTACHMENT_LOAD_OP_DONT_CARE; opa++)
|
||||
{
|
||||
for (u32 opb = VK_ATTACHMENT_LOAD_OP_LOAD; opb <= VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
opb++)
|
||||
for (u32 opb = VK_ATTACHMENT_LOAD_OP_LOAD; opb <= VK_ATTACHMENT_LOAD_OP_DONT_CARE; opb++)
|
||||
{
|
||||
const VkFormat rp_rt_format =
|
||||
(rt != 0) ? ((colclip != 0) ? colclip_rt_format : rt_format) : VK_FORMAT_UNDEFINED;
|
||||
const VkFormat rp_depth_format = (ds != 0) ? depth_format : VK_FORMAT_UNDEFINED;
|
||||
const VkAttachmentLoadOp opc = (!stencil || !m_features.stencil_buffer) ?
|
||||
VK_ATTACHMENT_LOAD_OP_DONT_CARE :
|
||||
VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
VK_ATTACHMENT_LOAD_OP_DONT_CARE :
|
||||
VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
GET(m_tfx_render_pass[rt][ds][colclip][stencil][fbl][dsp][opa][opb], rp_rt_format,
|
||||
rp_depth_format, (fbl != 0), (dsp != 0), static_cast<VkAttachmentLoadOp>(opa),
|
||||
static_cast<VkAttachmentLoadOp>(opb), static_cast<VkAttachmentLoadOp>(opc));
|
||||
@ -3896,8 +3893,7 @@ bool GSDeviceVK::CompileConvertPipelines()
|
||||
gpb.SetNoBlendingState();
|
||||
gpb.SetVertexShader(vs);
|
||||
|
||||
for (ShaderConvert i = ShaderConvert::COPY; static_cast<int>(i) < static_cast<int>(ShaderConvert::Count);
|
||||
i = static_cast<ShaderConvert>(static_cast<int>(i) + 1))
|
||||
for (ShaderConvert i = ShaderConvert::COPY; i < ShaderConvert::Count; i = static_cast<ShaderConvert>(static_cast<int>(i) + 1))
|
||||
{
|
||||
const bool depth = HasDepthOutput(i);
|
||||
const int index = static_cast<int>(i);
|
||||
@ -4108,8 +4104,7 @@ bool GSDeviceVK::CompilePresentPipelines()
|
||||
gpb.SetNoStencilState();
|
||||
gpb.SetRenderPass(m_swap_chain_render_pass, 0);
|
||||
|
||||
for (PresentShader i = PresentShader::COPY; static_cast<int>(i) < static_cast<int>(PresentShader::Count);
|
||||
i = static_cast<PresentShader>(static_cast<int>(i) + 1))
|
||||
for (PresentShader i = PresentShader::COPY; i < PresentShader::Count; i = static_cast<PresentShader>(static_cast<int>(i) + 1))
|
||||
{
|
||||
const int index = static_cast<int>(i);
|
||||
|
||||
@ -5610,7 +5605,7 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
|
||||
// If we have a colclip in progress, we need to use the colclip texture, but we can't check this later as there's a chicken/egg problem with the pipe setup.
|
||||
GSTexture* backup_rt = config.rt;
|
||||
|
||||
if(colclip_rt)
|
||||
if (colclip_rt)
|
||||
config.rt = colclip_rt;
|
||||
|
||||
date_image = SetupPrimitiveTrackingDATE(config);
|
||||
@ -5838,8 +5833,9 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
|
||||
|
||||
// Only draw to the active area of the colclip hw target. Except when depth is cleared, we need to use the full
|
||||
// buffer size, otherwise it'll only clear the draw part of the depth buffer.
|
||||
const GSVector4i render_area = (pipe.ps.colclip_hw && (config.colclip_mode == GSHWDrawConfig::ColClipMode::ConvertAndResolve) && ds_op != VK_ATTACHMENT_LOAD_OP_CLEAR) ? config.drawarea :
|
||||
GSVector4i::loadh(rtsize);
|
||||
const GSVector4i render_area = (pipe.ps.colclip_hw && (config.colclip_mode == GSHWDrawConfig::ColClipMode::ConvertAndResolve) && ds_op != VK_ATTACHMENT_LOAD_OP_CLEAR)
|
||||
? config.drawarea
|
||||
: GSVector4i::loadh(rtsize);
|
||||
|
||||
if (is_clearing_rt)
|
||||
{
|
||||
@ -6053,7 +6049,7 @@ VkImageMemoryBarrier GSDeviceVK::GetColorBufferBarrier(GSTextureVK* rt) const
|
||||
VkDependencyFlags GSDeviceVK::GetColorBufferBarrierFlags() const
|
||||
{
|
||||
return UseFeedbackLoopLayout() ? (VK_DEPENDENCY_BY_REGION_BIT | VK_DEPENDENCY_FEEDBACK_LOOP_BIT_EXT) :
|
||||
VK_DEPENDENCY_BY_REGION_BIT;
|
||||
VK_DEPENDENCY_BY_REGION_BIT;
|
||||
}
|
||||
|
||||
void GSDeviceVK::SendHWDraw(const GSHWDrawConfig& config, GSTextureVK* draw_rt,
|
||||
|
||||
@ -640,10 +640,10 @@ private:
|
||||
DIRTY_FLAG_TFX_TEXTURE_PRIMID = (DIRTY_FLAG_TFX_TEXTURE_0 << 3),
|
||||
|
||||
DIRTY_FLAG_TFX_TEXTURES = DIRTY_FLAG_TFX_TEXTURE_TEX | DIRTY_FLAG_TFX_TEXTURE_PALETTE |
|
||||
DIRTY_FLAG_TFX_TEXTURE_RT | DIRTY_FLAG_TFX_TEXTURE_PRIMID,
|
||||
DIRTY_FLAG_TFX_TEXTURE_RT | DIRTY_FLAG_TFX_TEXTURE_PRIMID,
|
||||
|
||||
DIRTY_BASE_STATE = DIRTY_FLAG_INDEX_BUFFER | DIRTY_FLAG_PIPELINE | DIRTY_FLAG_VIEWPORT | DIRTY_FLAG_SCISSOR |
|
||||
DIRTY_FLAG_BLEND_CONSTANTS | DIRTY_FLAG_LINE_WIDTH,
|
||||
DIRTY_FLAG_BLEND_CONSTANTS | DIRTY_FLAG_LINE_WIDTH,
|
||||
DIRTY_TFX_STATE = DIRTY_BASE_STATE | DIRTY_FLAG_TFX_TEXTURES,
|
||||
DIRTY_UTILITY_STATE = DIRTY_BASE_STATE | DIRTY_FLAG_UTILITY_TEXTURE,
|
||||
DIRTY_CONSTANT_BUFFER_STATE = DIRTY_FLAG_VS_CONSTANT_BUFFER | DIRTY_FLAG_PS_CONSTANT_BUFFER,
|
||||
|
||||
@ -33,14 +33,14 @@ static VkImageLayout GetVkImageLayout(GSTextureVK::Layout layout)
|
||||
VK_IMAGE_LAYOUT_GENERAL, // General
|
||||
}};
|
||||
return (layout == GSTextureVK::Layout::FeedbackLoop && GSDeviceVK::GetInstance()->UseFeedbackLoopLayout()) ?
|
||||
VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT :
|
||||
s_vk_layout_mapping[static_cast<u32>(layout)];
|
||||
VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT :
|
||||
s_vk_layout_mapping[static_cast<u32>(layout)];
|
||||
}
|
||||
|
||||
static VkAccessFlagBits GetFeedbackLoopInputAccessBits()
|
||||
{
|
||||
return GSDeviceVK::GetInstance()->UseFeedbackLoopLayout() ? VK_ACCESS_SHADER_READ_BIT :
|
||||
VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
|
||||
VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
|
||||
}
|
||||
|
||||
GSTextureVK::GSTextureVK(Type type, Format format, int width, int height, int levels, VkImage image,
|
||||
@ -102,8 +102,8 @@ std::unique_ptr<GSTextureVK> GSTextureVK::Create(Type type, Format format, int w
|
||||
ici.usage =
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
|
||||
(GSDeviceVK::GetInstance()->UseFeedbackLoopLayout() ? VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT :
|
||||
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
|
||||
(GSDeviceVK::GetInstance()->UseFeedbackLoopLayout() ? VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT
|
||||
: VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -113,8 +113,8 @@ std::unique_ptr<GSTextureVK> GSTextureVK::Create(Type type, Format format, int w
|
||||
ici.usage =
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
|
||||
(GSDeviceVK::GetInstance()->UseFeedbackLoopLayout() ? VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT :
|
||||
0);
|
||||
(GSDeviceVK::GetInstance()->UseFeedbackLoopLayout() ? VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT
|
||||
: 0);
|
||||
vci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
}
|
||||
break;
|
||||
@ -123,7 +123,7 @@ std::unique_ptr<GSTextureVK> GSTextureVK::Create(Type type, Format format, int w
|
||||
{
|
||||
pxAssert(levels == 1);
|
||||
ici.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -202,8 +202,7 @@ void GSTextureVK::Destroy(bool defer)
|
||||
{
|
||||
if (other_tex)
|
||||
{
|
||||
for (auto other_it = other_tex->m_framebuffers.begin(); other_it != other_tex->m_framebuffers.end();
|
||||
++other_it)
|
||||
for (auto other_it = other_tex->m_framebuffers.begin(); other_it != other_tex->m_framebuffers.end(); ++other_it)
|
||||
{
|
||||
if (std::get<0>(*other_it) == this)
|
||||
{
|
||||
@ -566,7 +565,7 @@ void GSTextureVK::TransitionSubresourcesToLayout(
|
||||
if (m_type == Type::DepthStencil)
|
||||
{
|
||||
aspect = g_gs_device->Features().stencil_buffer ? (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT) :
|
||||
VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -638,15 +637,12 @@ void GSTextureVK::TransitionSubresourcesToLayout(
|
||||
break;
|
||||
|
||||
case Layout::FeedbackLoop:
|
||||
barrier.srcAccessMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) ?
|
||||
(VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
||||
GetFeedbackLoopInputAccessBits()) :
|
||||
(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT);
|
||||
srcStageMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) ?
|
||||
(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT) :
|
||||
(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
||||
barrier.srcAccessMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
? (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | GetFeedbackLoopInputAccessBits())
|
||||
: (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT);
|
||||
srcStageMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
? (VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT)
|
||||
: (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
||||
break;
|
||||
|
||||
case Layout::ReadWriteImage:
|
||||
@ -714,15 +710,12 @@ void GSTextureVK::TransitionSubresourcesToLayout(
|
||||
break;
|
||||
|
||||
case Layout::FeedbackLoop:
|
||||
barrier.dstAccessMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) ?
|
||||
(VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
||||
GetFeedbackLoopInputAccessBits()) :
|
||||
(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT);
|
||||
dstStageMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) ?
|
||||
(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT) :
|
||||
(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
||||
barrier.dstAccessMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
? (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | GetFeedbackLoopInputAccessBits())
|
||||
: (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT);
|
||||
dstStageMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
? (VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT)
|
||||
: (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
||||
break;
|
||||
|
||||
case Layout::ReadWriteImage:
|
||||
@ -946,4 +939,4 @@ void GSDownloadTextureVK::SetDebugName(std::string_view name)
|
||||
Vulkan::SetObjectName(GSDeviceVK::GetInstance()->GetDevice(), m_buffer, "%.*s", static_cast<int>(name.size()), name.data());
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -114,14 +114,14 @@ namespace Vulkan
|
||||
void AddBlendAttachment(bool blend_enable, VkBlendFactor src_factor, VkBlendFactor dst_factor, VkBlendOp op,
|
||||
VkBlendFactor alpha_src_factor, VkBlendFactor alpha_dst_factor, VkBlendOp alpha_op,
|
||||
VkColorComponentFlags write_mask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
|
||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
|
||||
void SetBlendAttachment(u32 attachment, bool blend_enable, VkBlendFactor src_factor, VkBlendFactor dst_factor,
|
||||
VkBlendOp op, VkBlendFactor alpha_src_factor, VkBlendFactor alpha_dst_factor, VkBlendOp alpha_op,
|
||||
VkColorComponentFlags write_mask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
|
||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
|
||||
void SetColorWriteMask(
|
||||
u32 attachment, VkColorComponentFlags write_mask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
|
||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
|
||||
void AddBlendFlags(u32 flags);
|
||||
void ClearBlendAttachments();
|
||||
|
||||
@ -407,4 +407,4 @@ namespace Vulkan
|
||||
va_end(ap);
|
||||
#endif
|
||||
}
|
||||
} // namespace Vulkan
|
||||
} // namespace Vulkan
|
||||
|
||||
Loading…
Reference in New Issue
Block a user