Compare commits

..
12 Commits
Author SHA1 Message Date
lightningterror 2f8c98dccf GS/DX11/GL: Fix barrier typo, should check alpha second pass barrier. 2026-05-16 11:48:53 +02:00
lightningterror 59e422c538 GS/GL: Depth isn't written so we can skip a barrier. 2026-05-16 11:48:53 +02:00
lightningterror 5ef5e41e69 GS/DX11: Also check for depth feedback on alpha second pass. 2026-05-16 11:48:53 +02:00
PCSX2 Botandlightningterror 58facc8ab1 [ci skip] Qt: Update Base Translation. 2026-05-15 10:13:36 +02:00
SternXDandlightningterror 3341514bb4 GS: Add shader compile indicator 2026-05-14 21:57:11 +02:00
PCSX2 Botandlightningterror 0434aba3a8 [ci skip] Qt: Update Base Translation. 2026-05-14 14:37:43 +02:00
TJnotJTandlightningterror c1cb214a03 GS/HW: Add debug blend setting.
Will enable SW blend and disable many optimizations.
2026-05-13 19:49:07 +02:00
Tyandsalas-dev-max 3233a3cf8f Achievements: Fix crash in WinHTTP timeout
Co-authored-by: salas-dev-max <dren@thePuter.localdomain>
2026-05-13 12:20:43 -04:00
Florin9doiandTy 469a3d60b2 USB: Additional commands for MSAC-US1 2026-05-13 12:17:55 -04:00
Sean BrarandTy bb35bed104 DEV9: Isolate raw PCAP packet IO 2026-05-13 12:17:27 -04:00
chaoticgdandTy 624acf5533 Qt: Fix crash when interacting with per-game achievement settings 2026-05-13 12:17:02 -04:00
SternXDandGovanifY f71f0b9cb0 GS/ImGui: Update ImGui when resizing the swap chain
This allows for the OSD and BPM to stay in sync when resizing heavily

Co-authored-by: GovanifY <me@govanify.com>
2026-05-13 17:03:02 +02:00
27 changed files with 1828 additions and 1545 deletions
+11 -3
View File
@@ -56,6 +56,11 @@ bool HTTPDownloaderWinHttp::Initialize(std::string user_agent)
return false;
}
DWORD timeout_ms = 15000;
WinHttpSetOption(m_hSession, WINHTTP_OPTION_CONNECT_TIMEOUT, &timeout_ms, sizeof(timeout_ms));
WinHttpSetOption(m_hSession, WINHTTP_OPTION_SEND_TIMEOUT, &timeout_ms, sizeof(timeout_ms));
WinHttpSetOption(m_hSession, WINHTTP_OPTION_RECEIVE_TIMEOUT, &timeout_ms, sizeof(timeout_ms));
return true;
}
@@ -290,10 +295,13 @@ bool HTTPDownloaderWinHttp::StartRequest(HTTPDownloader::Request* request)
req->status_code = HTTP_STATUS_ERROR;
req->state.store(Request::State::Complete);
}
else
{
DevCon.WriteLn("Started HTTP request for '%s'", req->url.c_str());
req->state = Request::State::Started;
req->start_time = Common::Timer::GetCurrentValue();
}
DevCon.WriteLn("Started HTTP request for '%s'", req->url.c_str());
req->state = Request::State::Started;
req->start_time = Common::Timer::GetCurrentValue();
return true;
}
@@ -90,17 +90,15 @@ AchievementSettingsWidget::AchievementSettingsWidget(SettingsWindow* settings_di
}
else
{
// remove login and game info, not relevant for per-game
// hide login and game info, not relevant for per-game
m_ui.verticalLayout->removeWidget(m_ui.gameInfoBox);
m_ui.gameInfoBox->deleteLater();
m_ui.gameInfoBox = nullptr;
m_ui.gameInfoBox->hide();
m_ui.verticalLayout->removeWidget(m_ui.loginBox);
m_ui.loginBox->deleteLater();
m_ui.loginBox = nullptr;
m_ui.loginBox->hide();
// sound effects
m_ui.verticalLayout->removeWidget(m_ui.soundEffectsBox);
m_ui.soundEffectsBox->deleteLater();
m_ui.soundEffectsBox->hide();
m_ui.soundEffectsBox = nullptr;
}
@@ -121,9 +119,6 @@ void AchievementSettingsWidget::updateEnableState()
const bool unlock = enabled && sound && dialog()->getEffectiveBoolValue("Achievements", "UnlockSound", true);
const bool lbsound = enabled && sound && dialog()->getEffectiveBoolValue("Achievements", "LBSubmitSound", true);
m_ui.viewProfile->setEnabled(enabled);
m_ui.loginButton->setEnabled(enabled);
m_ui.hardcoreMode->setEnabled(enabled);
m_ui.achievementNotifications->setEnabled(enabled);
m_ui.leaderboardNotifications->setEnabled(enabled);
+55 -59
View File
@@ -11,6 +11,28 @@
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="rcheevosDisclaimer">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;justify&quot;&gt;PCSX2 uses RetroAchievements as an achievement database and for tracking progress. To use achievements, please sign up for an account at &lt;a href=&quot;https://retroachievements.org/&quot;&gt;retroachievements.org&lt;/a&gt;.&lt;/p&gt;&lt;p align=&quot;justify&quot;&gt;To view the achievement list in-game, press the hotkey for &lt;span style=&quot; font-weight:600;&quot;&gt;Open Pause Menu&lt;/span&gt; and select &lt;span style=&quot; font-weight:600;&quot;&gt;Achievements&lt;/span&gt; from the menu.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::TextFormat::RichText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="margin">
<number>8</number>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
<property name="buddy">
<cstring>enable</cstring>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="loginBox">
<property name="title">
@@ -18,32 +40,21 @@
</property>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0">
<item>
<layout class="QGridLayout" name="acccountLayout">
<item row="0" column="0">
<widget class="QCheckBox" name="enable">
<property name="text">
<string>Enable Achievements</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="loginStatus">
<property name="text">
<string>Username:
<widget class="QLabel" name="loginStatus">
<property name="text">
<string>Username:
Login token generated at:</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop</set>
</property>
<property name="textInteractionFlags">
<set>Qt::TextInteractionFlag::TextBrowserInteraction</set>
</property>
<property name="buddy">
<cstring>viewProfile</cstring>
</property>
</widget>
</item>
</layout>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop</set>
</property>
<property name="textInteractionFlags">
<set>Qt::TextInteractionFlag::TextBrowserInteraction</set>
</property>
<property name="buddy">
<cstring>viewProfile</cstring>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="achievementButtons">
@@ -94,62 +105,47 @@ Login token generated at:</string>
</layout>
</widget>
</item>
<item>
<widget class="QLabel" name="rcheevosDisclaimer">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;justify&quot;&gt;PCSX2 uses RetroAchievements as an achievement database and for tracking progress. To use achievements, please sign up for an account at &lt;a href=&quot;https://retroachievements.org/&quot;&gt;retroachievements.org&lt;/a&gt;.&lt;/p&gt;&lt;p align=&quot;justify&quot;&gt;To view the achievement list in-game, press the hotkey for &lt;span style=&quot; font-weight:600;&quot;&gt;Open Pause Menu&lt;/span&gt; and select &lt;span style=&quot; font-weight:600;&quot;&gt;Achievements&lt;/span&gt; from the menu.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::TextFormat::RichText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="margin">
<number>8</number>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
<property name="buddy">
<cstring>enable</cstring>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="settingsBox">
<property name="title">
<string>Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<item row="1" column="1">
<widget class="QCheckBox" name="unofficialAchievements">
<item row="0" column="0">
<widget class="QCheckBox" name="enable">
<property name="text">
<string>Test Unofficial Achievements</string>
<string>Enable Achievements</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="spectatorMode">
<property name="text">
<string>Enable Spectator Mode</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="hardcoreMode">
<property name="text">
<string>Enable Hardcore Mode</string>
</property>
</widget>
</item>
<item row="1" column="0">
<item row="2" column="0">
<widget class="QCheckBox" name="spectatorMode">
<property name="text">
<string>Enable Spectator Mode</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="encoreMode">
<property name="text">
<string>Enable Encore Mode</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="unofficialAchievements">
<property name="text">
<string>Test Unofficial Achievements</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@@ -537,9 +533,9 @@ Login token generated at:</string>
</layout>
</widget>
<tabstops>
<tabstop>enable</tabstop>
<tabstop>viewProfile</tabstop>
<tabstop>loginButton</tabstop>
<tabstop>enable</tabstop>
<tabstop>hardcoreMode</tabstop>
<tabstop>spectatorMode</tabstop>
<tabstop>encoreMode</tabstop>
@@ -321,6 +321,13 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="useDebugBlend">
<property name="text">
<string>Use Debug Blend</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
@@ -355,6 +362,7 @@
<tabstop>palFrameRate</tabstop>
<tabstop>overrideTextureBarriers</tabstop>
<tabstop>useDebugDevice</tabstop>
<tabstop>useDebugBlend</tabstop>
<tabstop>disableFramebufferFetch</tabstop>
<tabstop>disableShaderCache</tabstop>
<tabstop>disableVertexShaderExpand</tabstop>
@@ -225,6 +225,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
//////////////////////////////////////////////////////////////////////////
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_advanced.useBlitSwapChain, "EmuCore/GS", "UseBlitSwapChain", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_advanced.useDebugDevice, "EmuCore/GS", "UseDebugDevice", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_advanced.useDebugBlend, "EmuCore/GS", "UseDebugBlend", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_advanced.disableMailboxPresentation, "EmuCore/GS", "DisableMailboxPresentation", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_advanced.extendedUpscales, "EmuCore/GS", "ExtendedUpscalingMultipliers", false);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_advanced.exclusiveFullscreenControl, "EmuCore/GS", "ExclusiveFullscreenControl", -1, -1);
@@ -766,6 +767,9 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
dialog()->registerWidgetHelp(m_advanced.useDebugDevice, tr("Enable Debug Device"), tr("Unchecked"),
tr("Enables API-level validation of graphics commands."));
dialog()->registerWidgetHelp(m_advanced.useDebugBlend, tr("Enable Debug Blend"), tr("Unchecked"),
tr("Forces SW blending and disables several optimizations."));
dialog()->registerWidgetHelp(m_advanced.gsDownloadMode, tr("GS Download Mode"), tr("Accurate"),
tr("Skips synchronizing with the GS thread and host GPU for GS downloads. "
"Can result in a large speed boost on slower systems, at the cost of many broken graphical effects. "
File diff suppressed because it is too large Load Diff
+11 -4
View File
@@ -745,11 +745,18 @@ void Achievements::ClientServerCall(
{
HTTPDownloader::Request::Callback hd_callback = [callback, callback_data](s32 status_code, const std::string& content_type, HTTPDownloader::Request::Data data)
{
const bool is_error = (status_code <= 0);
const bool is_retryable =
is_error && (status_code == HTTPDownloader::HTTP_STATUS_TIMEOUT);
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;
rr.http_status_code =
is_error
? (is_retryable
? RC_API_SERVER_RESPONSE_RETRYABLE_CLIENT_ERROR
: RC_API_SERVER_RESPONSE_CLIENT_ERROR)
: status_code;
rr.body_length = data.size();
rr.body = reinterpret_cast<const char*>(data.data());
+2 -1
View File
@@ -760,6 +760,7 @@ struct Pcsx2Config
PCRTCOverscan : 1,
IntegerScaling : 1,
UseDebugDevice : 1,
UseDebugBlend : 1,
UseBlitSwapChain : 1,
DisableShaderCache : 1,
DisableFramebufferFetch : 1,
@@ -791,7 +792,7 @@ struct Pcsx2Config
PreloadFrameWithGSData : 1,
Mipmap : 1,
HWMipmap : 1,
HWAccurateAlphaTest: 1,
HWAccurateAlphaTest : 1,
HWAA1 : 1,
ManualUserHacks : 1,
UserHacks_AlignSpriteX : 1,
+34 -23
View File
@@ -118,30 +118,12 @@ bool PCAPAdapter::recv(NetPacket* pkt)
if (!blocking && NetAdapter::recv(pkt))
return true;
pcap_pkthdr* header;
const u_char* pkt_data;
// pcap bridged will pick up packets not intended for us, returning false on those packets will incur a 1ms wait.
// This delays getting packets we need, so instead loop untill a valid packet, or no packet, is returned from pcap_next_ex.
while (pcap_next_ex(hpcap, &header, &pkt_data) > 0)
while (RecvPCAPPacket(pkt))
{
// 1518 is the largest Ethernet frame we can get using an MTU of 1500 (assuming no VLAN tagging).
// This includes the FCS, which should be trimmed (PS2 SDK dosn't allow extra space for this).
if (header->len > 1518)
{
Console.Error("DEV9: Dropped jumbo frame of size: %u", header->len);
continue;
}
pxAssert(header->len == header->caplen);
memcpy(pkt->buffer, pkt_data, header->len);
pkt->size = static_cast<int>(header->len);
if (!switched)
SetMACBridgedRecv(pkt);
if (VerifyPkt(pkt, header->len))
if (VerifyPkt(pkt, pkt->size))
{
HandleFrameCheckSequence(pkt);
@@ -173,10 +155,39 @@ bool PCAPAdapter::send(NetPacket* pkt)
if (!switched)
SetMACBridgedSend(pkt);
if (pcap_sendpacket(hpcap, (u_char*)pkt->buffer, pkt->size))
return false;
else
return SendPCAPPacket(pkt);
}
bool PCAPAdapter::RecvPCAPPacket(NetPacket* pkt)
{
pcap_pkthdr* header;
const u_char* pkt_data;
// pcap bridged will pick up packets not intended for us, returning false on those packets will incur a 1ms wait.
// This delays getting packets we need, so instead loop untill a valid packet, or no packet, is returned from pcap_next_ex.
while (pcap_next_ex(hpcap, &header, &pkt_data) > 0)
{
// 1518 is the largest Ethernet frame we can get using an MTU of 1500 (assuming no VLAN tagging).
// This includes the FCS, which should be trimmed (PS2 SDK dosn't allow extra space for this).
if (header->len > 1518)
{
Console.Error("DEV9: Dropped jumbo frame of size: %u", header->len);
continue;
}
pxAssert(header->len == header->caplen);
memcpy(pkt->buffer, pkt_data, header->len);
pkt->size = static_cast<int>(header->len);
return true;
}
return false;
}
bool PCAPAdapter::SendPCAPPacket(const NetPacket* pkt)
{
return pcap_sendpacket(hpcap, reinterpret_cast<const u_char*>(pkt->buffer), pkt->size) == 0;
}
void PCAPAdapter::reloadSettings()
+3
View File
@@ -39,6 +39,9 @@ private:
bool InitPCAP(const std::string& adapter, bool promiscuous);
bool SetMACSwitchedFilter(PacketReader::MAC_Address mac);
bool RecvPCAPPacket(NetPacket* pkt);
bool SendPCAPPacket(const NetPacket* pkt);
void SetMACBridgedRecv(NetPacket* pkt);
void SetMACBridgedSend(NetPacket* pkt);
+89
View File
@@ -0,0 +1,89 @@
// SPDX-FileCopyrightText: 2002-2026 PCSX2 Dev Team
// SPDX-License-Identifier: GPL-3.0+
#pragma once
#include <atomic>
#include <chrono>
#include <cstdint>
namespace GSShaderCompileIndicator
{
inline constexpr std::uint64_t OSD_RECENT_COMPILE_NS = 500'000'000ULL;
inline std::atomic<std::uint32_t> s_active_compilations{0};
inline std::atomic<std::uint64_t> s_last_compile_activity_ns{0};
namespace detail
{
inline std::uint64_t steady_now_ns()
{
return static_cast<std::uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::steady_clock::now().time_since_epoch())
.count());
}
} // namespace detail
inline void TouchCompileActivity()
{
s_last_compile_activity_ns.store(detail::steady_now_ns(), std::memory_order_relaxed);
}
inline void BeginCompilation()
{
TouchCompileActivity();
s_active_compilations.fetch_add(1, std::memory_order_relaxed);
}
inline void EndCompilation()
{
s_active_compilations.fetch_sub(1, std::memory_order_relaxed);
TouchCompileActivity();
}
inline std::uint32_t GetActiveCompilationCount()
{
return s_active_compilations.load(std::memory_order_relaxed);
}
inline bool ShouldShowOnOSD(std::uint64_t hold_ns = OSD_RECENT_COMPILE_NS)
{
if (GetActiveCompilationCount() != 0)
return true;
const std::uint64_t last = s_last_compile_activity_ns.load(std::memory_order_relaxed);
if (last == 0)
return false;
const std::uint64_t now = detail::steady_now_ns();
return now > last && (now - last) < hold_ns;
}
inline float GetPostCompileFadeAlpha(std::uint64_t hold_ns = OSD_RECENT_COMPILE_NS)
{
if (GetActiveCompilationCount() != 0)
return 1.0f;
const std::uint64_t last = s_last_compile_activity_ns.load(std::memory_order_relaxed);
if (last == 0)
return 0.0f;
const std::uint64_t now = detail::steady_now_ns();
if (now <= last)
return 1.0f;
const std::uint64_t elapsed = now - last;
if (elapsed >= hold_ns)
return 0.0f;
return 1.0f - static_cast<float>(elapsed) / static_cast<float>(hold_ns);
}
struct ScopedCompilation
{
ScopedCompilation() { BeginCompilation(); }
~ScopedCompilation() { EndCompilation(); }
ScopedCompilation(const ScopedCompilation&) = delete;
ScopedCompilation& operator=(const ScopedCompilation&) = delete;
};
} // namespace GSShaderCompileIndicator
+2 -2
View File
@@ -4642,13 +4642,13 @@ GSState::PRIM_OVERLAP GSState::GetPrimitiveOverlapDrawlistImpl(bool save_drawlis
};
// First check: see if the triangles are part of a triangle strip.
if (!got_bbox && !using_aa1)
if (!got_bbox && !using_aa1 && !GSConfig.UseDebugBlend)
{
got_bbox = CheckTriangleStrips(j, skip, bbox, saved_tristrip);
}
// Second check: see if the triangles are part of triangle fan.
if (!got_bbox && !using_aa1)
if (!got_bbox && !using_aa1 && !GSConfig.UseDebugBlend)
{
got_bbox = CheckTriangleQuads.template operator()<1>(j, skip, bbox);
}
+3
View File
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-3.0+
#include "Config.h"
#include "GS/GSShaderCompileIndicator.h"
#include "GS/Renderers/Common/GSDevice.h"
#include "GS/Renderers/DX11/D3D.h"
#include "GS/GSExtra.h"
@@ -487,6 +488,8 @@ wil::com_ptr_nothrow<ID3DBlob> D3D::CompileShader(D3D::ShaderType type, D3D::Sha
const std::string_view code, const D3D_SHADER_MACRO* macros /* = nullptr */,
const char* entry_point /* = "main" */)
{
const GSShaderCompileIndicator::ScopedCompilation compiling;
const char* target;
switch (shader_model)
{
+2 -2
View File
@@ -2907,7 +2907,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
ID3D11DepthStencilView* read_only_dsv = nullptr;
if (config.tex && config.tex == config.ds)
{
if (m_features.test_and_sample_depth && !config.depth.zwe && !config.ps.IsFeedbackLoopDepth())
if (m_features.test_and_sample_depth && !config.depth.zwe && !config.ps.IsFeedbackLoopDepth() && !config.alpha_second_pass.ps.IsFeedbackLoopDepth())
read_only_dsv = static_cast<GSTexture11*>(config.ds)->ReadOnlyDepthStencilView();
else
config.tex = nullptr;
@@ -2955,7 +2955,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
(rt_feedbackloop_pass1 || rt_feedbackloop_pass2))))
{
config.require_one_barrier |= (tex_is_fb && !config.require_full_barrier);
config.alpha_second_pass.require_one_barrier |= (tex_is_fb && !config.require_full_barrier);
config.alpha_second_pass.require_one_barrier |= (tex_is_fb && !config.alpha_second_pass.require_full_barrier);
// Requires a copy of the RT.
draw_rt_clone = CreateTexture(rtsize.x, rtsize.y, 1, draw_rt->GetFormat(), true);
@@ -3,6 +3,7 @@
#include "GS/Renderers/DX12/D3D12ShaderCache.h"
#include "GS/GS.h"
#include "GS/GSShaderCompileIndicator.h"
#include "Config.h"
#include "ShaderCacheVersion.h"
@@ -540,6 +541,8 @@ D3D12ShaderCache::ComPtr<ID3DBlob> D3D12ShaderCache::CompileAndAddShaderBlob(
D3D12ShaderCache::ComPtr<ID3D12PipelineState> D3D12ShaderCache::CompileAndAddPipeline(
ID3D12Device* device, const CacheIndexKey& key, const D3D12_GRAPHICS_PIPELINE_STATE_DESC& gpdesc)
{
const GSShaderCompileIndicator::ScopedCompilation compiling;
ComPtr<ID3D12PipelineState> pso;
HRESULT hr = device->CreateGraphicsPipelineState(&gpdesc, IID_PPV_ARGS(pso.put()));
if (FAILED(hr))
@@ -555,6 +558,8 @@ D3D12ShaderCache::ComPtr<ID3D12PipelineState> D3D12ShaderCache::CompileAndAddPip
D3D12ShaderCache::ComPtr<ID3D12PipelineState> D3D12ShaderCache::CompileAndAddPipeline(
ID3D12Device* device, const CacheIndexKey& key, const D3D12_COMPUTE_PIPELINE_STATE_DESC& gpdesc)
{
const GSShaderCompileIndicator::ScopedCompilation compiling;
ComPtr<ID3D12PipelineState> pso;
HRESULT hr = device->CreateComputePipelineState(&gpdesc, IID_PPV_ARGS(pso.put()));
if (FAILED(hr))
+11 -12
View File
@@ -6955,27 +6955,26 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, DATEOptio
break;
}
if (features.framebuffer_fetch)
{
const bool force_sw_blending =
// If we have fbfetch, use software blending when we need the fb value for anything else.
// This saves outputting the second color when it's not needed.
if (one_barrier || m_conf.require_full_barrier)
{
sw_blending = true;
color_dest_blend = false;
accumulation_blend = false;
blend_mix = false;
}
}
(features.framebuffer_fetch && (one_barrier || m_conf.require_full_barrier)) ||
if (m_conf.ps.IsFeedbackLoopDepth() && !features.depth_feedback)
{
// If we are doing depth feedback with a second RT we must use SW blending to avoid
// mixing dual source blending with multiple render targets.
(m_conf.ps.IsFeedbackLoopDepth() && !features.depth_feedback) ||
// Force SW blending with barriers.
GSConfig.UseDebugBlend;
if (force_sw_blending)
{
sw_blending = true;
color_dest_blend = false;
accumulation_blend = false;
blend_mix = false;
color_dest_blend2 = false;
blend_zero_to_one_range = false;
}
// Color clip
+3
View File
@@ -7,6 +7,7 @@
#include "GS/Renderers/Metal/GSDeviceMTL.h"
#include "GS/Renderers/Metal/GSTextureMTL.h"
#include "GS/GSPerfMon.h"
#include "GS/GSShaderCompileIndicator.h"
#include "common/Console.h"
#include "common/HostSys.h"
@@ -712,6 +713,7 @@ MRCOwned<id<MTLFunction>> GSDeviceMTL::LoadShader(NSString* name)
MRCOwned<id<MTLRenderPipelineState>> GSDeviceMTL::MakePipeline(MTLRenderPipelineDescriptor* desc, id<MTLFunction> vertex, id<MTLFunction> fragment, NSString* name)
{
const GSShaderCompileIndicator::ScopedCompilation compiling;
[desc setLabel:name];
[desc setVertexFunction:vertex];
[desc setFragmentFunction:fragment];
@@ -728,6 +730,7 @@ MRCOwned<id<MTLRenderPipelineState>> GSDeviceMTL::MakePipeline(MTLRenderPipeline
MRCOwned<id<MTLComputePipelineState>> GSDeviceMTL::MakeComputePipeline(id<MTLFunction> compute, NSString* name)
{
const GSShaderCompileIndicator::ScopedCompilation compiling;
MRCOwned<MTLComputePipelineDescriptor*> desc = MRCTransfer([MTLComputePipelineDescriptor new]);
[desc setLabel:name];
[desc setComputeFunction:compute];
+10 -2
View File
@@ -3,6 +3,7 @@
#include "GSMTLDeviceInfo.h"
#include "GS/GS.h"
#include "GS/GSShaderCompileIndicator.h"
#include "common/Console.h"
#include "common/Path.h"
@@ -56,7 +57,10 @@ static bool detectPrimIDSupport(id<MTLDevice> dev, id<MTLLibrary> lib)
[desc setFragmentFunction:MRCTransfer([lib newFunctionWithName:@"primid_test"])];
[[desc colorAttachments][0] setPixelFormat:MTLPixelFormatR8Uint];
NSError* err;
[[dev newRenderPipelineStateWithDescriptor:desc error:&err] release];
{
const GSShaderCompileIndicator::ScopedCompilation compiling;
[[dev newRenderPipelineStateWithDescriptor:desc error:&err] release];
}
return !err;
}
@@ -88,7 +92,11 @@ static DetectionResult detectIntelGPU(id<MTLDevice> dev, id<MTLLibrary> lib)
[pdesc setVertexFunction:MRCTransfer([lib newFunctionWithName:@"fs_triangle"])];
[pdesc setFragmentFunction:MRCTransfer([lib newFunctionWithName:@"fbfetch_test"])];
[[pdesc colorAttachments][0] setPixelFormat:MTLPixelFormatRGBA8Unorm];
auto pipe = MRCTransfer([dev newRenderPipelineStateWithDescriptor:pdesc error:nil]);
MRCOwned<id<MTLRenderPipelineState>> pipe;
{
const GSShaderCompileIndicator::ScopedCompilation compiling;
pipe = MRCTransfer([dev newRenderPipelineStateWithDescriptor:pdesc error:nil]);
}
if (!pipe)
return DetectionResult::HaswellOrNotIntel;
auto buf = MRCTransfer([dev newBufferWithLength:4 options:MTLResourceStorageModeShared]);
@@ -3,6 +3,7 @@
#include "GS/Renderers/OpenGL/GLShaderCache.h"
#include "GS/GS.h"
#include "GS/GSShaderCompileIndicator.h"
#include "Config.h"
#include "ShaderCacheVersion.h"
@@ -366,6 +367,8 @@ bool GLShaderCache::WriteToBlobFile(const CacheIndexKey& key, const std::vector<
std::optional<GLProgram> GLShaderCache::CompileProgram(const std::string_view vertex_shader,
const std::string_view fragment_shader, const PreLinkCallback& callback, bool set_retrievable)
{
const GSShaderCompileIndicator::ScopedCompilation compiling;
GLProgram prog;
if (!prog.Compile(vertex_shader, fragment_shader))
return std::nullopt;
@@ -385,6 +388,8 @@ std::optional<GLProgram> GLShaderCache::CompileProgram(const std::string_view ve
std::optional<GLProgram> GLShaderCache::CompileComputeProgram(
const std::string_view glsl, const PreLinkCallback& callback, bool set_retrievable)
{
const GSShaderCompileIndicator::ScopedCompilation compiling;
GLProgram prog;
if (!prog.CompileCompute(glsl))
return std::nullopt;
+14 -2
View File
@@ -2821,7 +2821,19 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
SetupPipeline(psel);
bool rt_hazard_barrier = config.tex && (config.tex == config.ds || config.tex == config.rt);
bool rt_hazard_barrier = config.tex && config.tex == config.rt;
if (config.tex && config.tex == config.ds)
{
if (m_features.test_and_sample_depth && !config.depth.zwe && !config.ps.IsFeedbackLoopDepth() && !config.alpha_second_pass.ps.IsFeedbackLoopDepth())
{
// Do nothing.
}
else if (m_features.texture_barrier)
rt_hazard_barrier = true;
else
config.tex = nullptr;
}
// In Time Crisis:
// 1. Fullscreen sprite reads depth and writes alpha (rt_hazard_barrier true from config.ds == config.tex)
// 2. Fullscreen sprite writes gray, rta hw blend blends based on dst alpha.
@@ -2938,7 +2950,7 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
(rt_feedbackloop_pass1 || rt_feedbackloop_pass2))))
{
config.require_one_barrier |= (tex_is_fb && !config.require_full_barrier);
config.alpha_second_pass.require_one_barrier |= (tex_is_fb && !config.require_full_barrier);
config.alpha_second_pass.require_one_barrier |= (tex_is_fb && !config.alpha_second_pass.require_full_barrier);
// Requires a copy of the RT.
draw_rt_clone = CreateTexture(rtsize.x, rtsize.y, 1, draw_rt->GetFormat(), true);
+2
View File
@@ -13,6 +13,7 @@
#include "BuildVersion.h"
#include "Host.h"
#include "ImGui/ImGuiManager.h"
#include "common/Console.h"
#include "common/BitUtils.h"
@@ -2353,6 +2354,7 @@ GSDevice::PresentResult GSDeviceVK::BeginPresent(bool frame_skip)
if (res == VK_SUBOPTIMAL_KHR || res == VK_ERROR_OUT_OF_DATE_KHR)
{
ResizeWindow(0, 0, m_window_info.surface_scale);
ImGuiManager::WindowResized();
res = m_swap_chain->AcquireNextImage();
}
else if (res == VK_ERROR_SURFACE_LOST_KHR)
+5
View File
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-3.0+
#include "GS/Renderers/Vulkan/VKBuilders.h"
#include "GS/GSShaderCompileIndicator.h"
#include "common/Assertions.h"
#include "common/Console.h"
@@ -279,6 +280,8 @@ void Vulkan::GraphicsPipelineBuilder::Clear()
VkPipeline Vulkan::GraphicsPipelineBuilder::Create(
VkDevice device, VkPipelineCache pipeline_cache, bool clear /* = true */)
{
const GSShaderCompileIndicator::ScopedCompilation compiling;
VkPipeline pipeline;
VkResult res = vkCreateGraphicsPipelines(device, pipeline_cache, 1, &m_ci, nullptr, &pipeline);
if (res != VK_SUCCESS)
@@ -588,6 +591,8 @@ void Vulkan::ComputePipelineBuilder::Clear()
VkPipeline Vulkan::ComputePipelineBuilder::Create(
VkDevice device, VkPipelineCache pipeline_cache /*= VK_NULL_HANDLE*/, bool clear /*= true*/)
{
const GSShaderCompileIndicator::ScopedCompilation compiling;
VkPipeline pipeline;
VkResult res = vkCreateComputePipelines(device, pipeline_cache, 1, &m_ci, nullptr, &pipeline);
if (res != VK_SUCCESS)
@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: 2002-2026 PCSX2 Dev Team
// SPDX-License-Identifier: GPL-3.0+
#include "GS/GSShaderCompileIndicator.h"
#include "GS/GS.h"
#include "GS/Renderers/Vulkan/GSDeviceVK.h"
#include "GS/Renderers/Vulkan/VKBuilders.h"
@@ -230,6 +231,8 @@ std::optional<VKShaderCache::SPIRVCodeVector> VKShaderCache::CompileShaderToSPV(
if (!dyn_shaderc::Open())
return ret;
const GSShaderCompileIndicator::ScopedCompilation compiling;
shaderc_compile_options_t options = dyn_shaderc::shaderc_compile_options_initialize();
pxAssertRel(options, "shaderc_compile_options_initialize() failed");
+4
View File
@@ -4979,6 +4979,8 @@ void FullscreenUI::DrawAdvancedSettingsPage()
MenuHeading(FSUI_CSTR("Graphics"));
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_BUG, "Use Debug Device"), FSUI_CSTR("Enables API-level validation of graphics commands."), "EmuCore/GS",
"UseDebugDevice", false);
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_BUG, "Use Debug Blend"), FSUI_CSTR("Forces SW blending and disables several optimizations."), "EmuCore/GS", "UseDebugBlend", false);
}
EndMenuButtons();
@@ -5446,6 +5448,7 @@ TRANSLATE_NOOP("FullscreenUI", "Sets the compression algorithm for savestate.");
TRANSLATE_NOOP("FullscreenUI", "Sets the compression level for savestate.");
TRANSLATE_NOOP("FullscreenUI", "Graphics");
TRANSLATE_NOOP("FullscreenUI", "Enables API-level validation of graphics commands.");
TRANSLATE_NOOP("FullscreenUI", "Forces SW blending and disables several optimizations.");
TRANSLATE_NOOP("FullscreenUI", "Settings");
TRANSLATE_NOOP("FullscreenUI", "No cheats are available for this game.");
TRANSLATE_NOOP("FullscreenUI", "Cheat Codes");
@@ -5997,6 +6000,7 @@ TRANSLATE_NOOP("FullscreenUI", "Enable IOP Recompiler");
TRANSLATE_NOOP("FullscreenUI", "Compression Method");
TRANSLATE_NOOP("FullscreenUI", "Compression Level");
TRANSLATE_NOOP("FullscreenUI", "Use Debug Device");
TRANSLATE_NOOP("FullscreenUI", "Use Debug Blend");
TRANSLATE_NOOP("FullscreenUI", "FPU Multiply Hack");
TRANSLATE_NOOP("FullscreenUI", "Use Software Renderer For FMVs");
TRANSLATE_NOOP("FullscreenUI", "Skip MPEG Hack");
+69
View File
@@ -5,6 +5,7 @@
#include "Config.h"
#include "Counters.h"
#include "GS/GS.h"
#include "GS/GSShaderCompileIndicator.h"
#include "GS/GSCapture.h"
#include "GS/GSVector.h"
#include "GS/Renderers/Common/GSDevice.h"
@@ -143,6 +144,7 @@ namespace ImGuiManager
{
static void FormatProcessorStat(SmallStringBase& text, double usage, double time);
static void DrawPerformanceOverlay(float& position_y, float scale, float margin, float spacing);
static void DrawShaderCompileIndicator(float scale, float margin, float spacing);
static void DrawSettingsOverlay(float scale, float margin, float spacing);
static void DrawInputsOverlay(float scale, float margin, float spacing);
static void DrawInputRecordingOverlay(float& position_y, float scale, float margin, float spacing);
@@ -778,6 +780,72 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f
#undef DRAW_LINE
}
__ri void ImGuiManager::DrawShaderCompileIndicator(float scale, float margin, float spacing)
{
static bool s_indicator_was_visible = false;
static double s_indicator_fade_in_start = 0.0;
if (!GSConfig.OsdShowGPU || !GSShaderCompileIndicator::ShouldShowOnOSD())
{
s_indicator_was_visible = false;
return;
}
const double imgui_time = ImGui::GetTime();
if (!s_indicator_was_visible)
s_indicator_fade_in_start = imgui_time;
s_indicator_was_visible = true;
constexpr double fade_in_seconds = 0.12;
const float fade_in_alpha = static_cast<float>(
std::min(1.0, (imgui_time - s_indicator_fade_in_start) / fade_in_seconds));
const float fade_out_alpha = GSShaderCompileIndicator::GetPostCompileFadeAlpha();
const float indicator_alpha = std::clamp(fade_in_alpha * fade_out_alpha, 0.0f, 1.0f);
const ImU32 text_col = IM_COL32(255, 255, 255, static_cast<int>(std::lround(255.0f * indicator_alpha)));
const ImU32 shadow_col = IM_COL32(0, 0, 0, static_cast<int>(std::lround(100.0f * indicator_alpha)));
const ImU32 spinner_track_col =
IM_COL32(255, 255, 255, static_cast<int>(std::lround(45.0f * indicator_alpha)));
const std::string label = TRANSLATE_STR("ImGuiOverlays", "Compiling Shaders");
ImFont* const font = ImGuiManager::GetOSDFont();
const float font_size = ImGuiManager::GetFontSizeStandard();
const float baseline_y =
GetWindowHeight() - margin - (GSConfig.OsdShowSettings ? font_size : 0.0f);
const float radius = std::ceil(10.0f * scale);
const float cx = GetWindowWidth() - margin - radius;
const float cy = baseline_y - spacing - radius;
const ImVec2 center(cx, cy);
const ImVec2 text_size = font->CalcTextSizeA(
font_size, std::numeric_limits<float>::max(), -1.0f, label.c_str(), label.c_str() + label.length(), nullptr);
const float shadow_offset = std::ceil(scale);
const float text_gap = std::ceil(6.0f * scale);
const float text_x = cx - radius - text_gap - text_size.x;
const float text_y = cy - font_size * 0.5f;
ImDrawList* const dl = ImGui::GetBackgroundDrawList();
const float a0 = static_cast<float>(ImGui::GetTime()) * 10.0f;
const float a1 = a0 + IM_PI * 1.12f;
const float thickness = std::ceil(2.5f * scale);
dl->AddText(font, font_size, ImVec2(text_x + shadow_offset, text_y + shadow_offset), shadow_col,
label.c_str(), label.c_str() + label.length());
dl->AddText(font, font_size, ImVec2(text_x, text_y), text_col, label.c_str(), label.c_str() + label.length());
if (GSConfig.OsdBoldText)
{
dl->AddText(font, font_size, ImVec2(text_x + 0.6f, text_y), text_col, label.c_str(),
label.c_str() + label.length());
}
dl->PathClear();
dl->PathArcTo(center, radius, 0.0f, 2.0f * IM_PI, 32);
dl->PathStroke(spinner_track_col, false, std::max(1.0f, thickness * 0.65f));
dl->PathClear();
dl->PathArcTo(center, radius, a0, a1, 24);
dl->PathStroke(text_col, false, thickness);
}
__ri void ImGuiManager::DrawSettingsOverlay(float scale, float margin, float spacing)
{
if (!GSConfig.OsdShowSettings ||
@@ -1698,6 +1766,7 @@ void ImGuiManager::RenderOverlays()
if (GSConfig.OsdPerformancePos != OsdOverlayPos::None)
DrawPerformanceOverlay(position_y, scale, margin, spacing);
DrawSettingsOverlay(scale, margin, spacing);
DrawShaderCompileIndicator(scale, margin, spacing);
DrawInputsOverlay(scale, margin, spacing);
if (SaveStateSelectorUI::s_open)
SaveStateSelectorUI::Draw();
+2
View File
@@ -754,6 +754,7 @@ Pcsx2Config::GSOptions::GSOptions()
HWMipmap = true;
HWAccurateAlphaTest = false;
HWAA1 = false;
UseDebugBlend = false;
ManualUserHacks = false;
UserHacks_AlignSpriteX = false;
@@ -1041,6 +1042,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
SettingsWrapBitBoolEx(HWMipmap, "hw_mipmap");
SettingsWrapBitBool(HWAccurateAlphaTest);
SettingsWrapBitBool(HWAA1);
SettingsWrapBitBool(UseDebugBlend);
SettingsWrapIntEnumEx(AccurateBlendingUnit, "accurate_blending_unit");
SettingsWrapIntEnumEx(TextureFiltering, "filter");
SettingsWrapIntEnumEx(TexturePreloading, "texture_preloading");
+10
View File
@@ -1034,6 +1034,16 @@ namespace usb_msd
case ClassInterfaceOutRequest:
switch (data[0])
{
case TEST_UNIT_READY:
case START_STOP:
case SEND_DIAGNOSTIC:
break;
case MODE_SENSE_10:
s->f.mode = USB_MSDM_CBW;
s->f.data_len = 0x08;
memset(s->f.buf, 0, s->f.data_len);
s->f.buf[1] = 0x06;
break;
case REQUEST_SENSE:
{
s->f.mode = USB_MSDM_CBW;