diff --git a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp index 01bc772810..64e7b6ee56 100644 --- a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp +++ b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp @@ -1413,6 +1413,7 @@ void GSDevice11::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTextur { const u8 mask = shader.Mask(); shader = shader.SetMask(); // Mask is handled separately from program. + linear &= !shader.SupportsBilinear(); // Don't allow HW bilinear if SW bilinear is needed. DoStretchRect(sTex, sRect, dTex, dRect, GetConvertShader(shader), nullptr, m_convert.bs[mask].get(), linear); } diff --git a/pcsx2/GS/Renderers/DX12/GSDevice12.cpp b/pcsx2/GS/Renderers/DX12/GSDevice12.cpp index 30e0fec748..c85e994870 100644 --- a/pcsx2/GS/Renderers/DX12/GSDevice12.cpp +++ b/pcsx2/GS/Renderers/DX12/GSDevice12.cpp @@ -1672,6 +1672,7 @@ void GSDevice12::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTextur ShaderConvertSelector shader, bool linear) { pxAssert(dTex); + linear &= !shader.SupportsBilinear(); // Don't allow HW bilinear if SW bilinear is needed. const bool allow_discard = (shader.Mask() == 0xf); DoStretchRect(static_cast(sTex), sRect, static_cast(dTex), dRect, GetConvertPipeline(shader), linear, allow_discard); diff --git a/pcsx2/GS/Renderers/Metal/GSDeviceMTL.h b/pcsx2/GS/Renderers/Metal/GSDeviceMTL.h index e46f64d79b..200339f4f3 100644 --- a/pcsx2/GS/Renderers/Metal/GSDeviceMTL.h +++ b/pcsx2/GS/Renderers/Metal/GSDeviceMTL.h @@ -420,7 +420,7 @@ public: void CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, u32 destX, u32 destY) override; void BeginStretchRect(NSString* name, GSTexture* dTex, MTLLoadAction action); - void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, id pipeline, bool linear, LoadAction load_action, const void* frag_uniform, size_t frag_uniform_len); + void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, id pipeline, std::optional linear, LoadAction load_action, const void* frag_uniform, size_t frag_uniform_len); void DrawStretchRect(const GSVector4& sRect, const GSVector4& dRect, const GSVector2& ds); /// Copy from a position in sTex to the same position in the currently active render encoder using the given fs pipeline and rect void RenderCopy(GSTexture* sTex, id pipeline, const GSVector4i& rect); @@ -471,6 +471,7 @@ public: u32 FrameNo() const { return m_frame; } protected: + using GSDevice::DoStretchRect; // Suppress overloaded virtual function warning virtual void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderConvertSelector shader, bool linear) override; }; diff --git a/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm b/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm index 53e418da24..b11b4d4f18 100644 --- a/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm +++ b/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm @@ -1580,7 +1580,7 @@ void GSDeviceMTL::BeginStretchRect(NSString* name, GSTexture* dTex, MTLLoadActio MRESetDSS(dsel); } -void GSDeviceMTL::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, id pipeline, bool linear, LoadAction load_action, const void* frag_uniform, size_t frag_uniform_len) +void GSDeviceMTL::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, id pipeline, std::optional linear, LoadAction load_action, const void* frag_uniform, size_t frag_uniform_len) { FlushClears(sTex); @@ -1601,7 +1601,8 @@ void GSDeviceMTL::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTextu if (frag_uniform && frag_uniform_len) [m_current_render.encoder setFragmentBytes:frag_uniform length:frag_uniform_len atIndex:GSMTLBufferIndexUniforms]; - MRESetSampler(linear ? SamplerSelector::Linear() : SamplerSelector::Point()); + if (linear) + MRESetSampler(*linear ? SamplerSelector::Linear() : SamplerSelector::Point()); DrawStretchRect(sRect, dRect, GSVector2(static_cast(ds.x), static_cast(ds.y))); } @@ -1652,8 +1653,9 @@ void GSDeviceMTL::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTextu const LoadAction load_action = (shader.Mask() == 0xf) ? LoadAction::DontCareIfFull : LoadAction::Load; id pipeline = GetConvertPipeline(shader); pxAssertRel(pipeline, fmt::format("No pipeline for {}", ShaderEntryPoint(shader.Shader())).c_str()); + std::optional linear_if_needed = shader.SupportsBilinear() ? std::nullopt : std::make_optional(linear); - DoStretchRect(sTex, sRect, dTex, dRect, pipeline, linear, load_action, nullptr, 0); + DoStretchRect(sTex, sRect, dTex, dRect, pipeline, linear_if_needed, load_action, nullptr, 0); }} static_assert(sizeof(DisplayConstantBuffer) == sizeof(GSMTLPresentPSUniform)); diff --git a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp index a787677421..a4eababa9d 100644 --- a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp +++ b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp @@ -1677,6 +1677,7 @@ void GSDeviceOGL::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTextu { const u8 mask = shader.Mask(); shader = shader.SetMask(); // Mask is handled separately from program. + linear &= !shader.SupportsBilinear(); // Don't allow HW bilinear if SW bilinear is needed. DoStretchRect(sTex, sRect, dTex, dRect, GetConvertProgram(shader), false, OMColorMaskSelector(mask), linear); } diff --git a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp index 77349da889..19b23c7f08 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp +++ b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp @@ -2925,6 +2925,7 @@ void GSDeviceVK::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTextur ShaderConvertSelector shader, bool linear) { pxAssert(dTex); + linear &= !shader.SupportsBilinear(); // Don't allow HW bilinear if SW bilinear is needed. const bool allow_discard = (shader.Mask() == 0xf); DoStretchRect(static_cast(sTex), sRect, static_cast(dTex), dRect, GetConvertPipeline(shader), linear, allow_discard);