mirror of https://github.com/PCSX2/pcsx2.git
GS/HW: Reduce number of copies for HDR
This commit is contained in:
parent
cd98f72f10
commit
2d6a42ac06
|
@ -799,7 +799,8 @@ void ps_fbmask(inout float4 C, float2 pos_xy)
|
|||
{
|
||||
if (PS_FBMASK)
|
||||
{
|
||||
float4 RT = trunc(RtTexture.Load(int3(pos_xy, 0)) * 255.0f + 0.1f);
|
||||
float multi = PS_HDR ? 65535.0f : 255.0f;
|
||||
float4 RT = trunc(RtTexture.Load(int3(pos_xy, 0)) * multi + 0.1f);
|
||||
C = (float4)(((uint4)C & ~FbMask) | ((uint4)RT & FbMask));
|
||||
}
|
||||
}
|
||||
|
@ -895,7 +896,8 @@ void ps_blend(inout float4 Color, inout float4 As_rgba, float2 pos_xy)
|
|||
}
|
||||
|
||||
float Ad = PS_RTA_CORRECTION ? trunc(RT.a * 128.0f + 0.1f) / 128.0f : trunc(RT.a * 255.0f + 0.1f) / 128.0f;
|
||||
float3 Cd = trunc(RT.rgb * 255.0f + 0.1f);
|
||||
float color_multi = PS_HDR ? 65535.0f : 255.0f;
|
||||
float3 Cd = trunc(RT.rgb * color_multi + 0.1f);
|
||||
float3 Cs = Color.rgb;
|
||||
|
||||
float3 A = (PS_BLEND_A == 0) ? Cs : ((PS_BLEND_A == 1) ? Cd : (float3)0.0f);
|
||||
|
|
|
@ -708,7 +708,11 @@ void ps_fbmask(inout vec4 C)
|
|||
{
|
||||
// FIXME do I need special case for 16 bits
|
||||
#if PS_FBMASK
|
||||
vec4 RT = trunc(fetch_rt() * 255.0f + 0.1f);
|
||||
#if PS_HDR == 1
|
||||
vec4 RT = trunc(fetch_rt() * 65535.0f);
|
||||
#else
|
||||
vec4 RT = trunc(fetch_rt() * 255.0f + 0.1f);
|
||||
#endif
|
||||
C = vec4((uvec4(C) & ~FbMask) | (uvec4(RT) & FbMask));
|
||||
#endif
|
||||
}
|
||||
|
@ -823,7 +827,11 @@ float As = As_rgba.a;
|
|||
#endif
|
||||
|
||||
// Let the compiler do its jobs !
|
||||
vec3 Cd = trunc(RT.rgb * 255.0f + 0.1f);
|
||||
#if PS_HDR == 1
|
||||
vec3 Cd = trunc(RT.rgb * 65535.0f);
|
||||
#else
|
||||
vec3 Cd = trunc(RT.rgb * 255.0f + 0.1f);
|
||||
#endif
|
||||
vec3 Cs = Color.rgb;
|
||||
|
||||
#if PS_BLEND_A == 0
|
||||
|
|
|
@ -972,7 +972,12 @@ vec4 ps_color()
|
|||
void ps_fbmask(inout vec4 C)
|
||||
{
|
||||
#if PS_FBMASK
|
||||
vec4 RT = trunc(sample_from_rt() * 255.0f + 0.1f);
|
||||
|
||||
#if PS_HDR == 1
|
||||
vec4 RT = trunc(sample_from_rt() * 65535.0f);
|
||||
#else
|
||||
vec4 RT = trunc(sample_from_rt() * 255.0f + 0.1f);
|
||||
#endif
|
||||
C = vec4((uvec4(C) & ~FbMask) | (uvec4(RT) & FbMask));
|
||||
#endif
|
||||
}
|
||||
|
@ -1090,7 +1095,11 @@ void ps_blend(inout vec4 Color, inout vec4 As_rgba)
|
|||
#endif
|
||||
|
||||
// Let the compiler do its jobs !
|
||||
#if PS_HDR == 1
|
||||
vec3 Cd = trunc(RT.rgb * 65535.0f);
|
||||
#else
|
||||
vec3 Cd = trunc(RT.rgb * 255.0f + 0.1f);
|
||||
#endif
|
||||
vec3 Cs = Color.rgb;
|
||||
|
||||
#if PS_BLEND_A == 0
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "GS/GS.h"
|
||||
#include "GS/Renderers/Common/GSFastList.h"
|
||||
#include "GS/Renderers/Common/GSTexture.h"
|
||||
#include "GS/Renderers/Vulkan/GSTextureVK.h"
|
||||
#include "GS/Renderers/Common/GSVertex.h"
|
||||
#include "GS/GSAlignedClass.h"
|
||||
#include "GS/GSExtra.h"
|
||||
|
@ -674,6 +675,15 @@ struct alignas(16) GSHWDrawConfig
|
|||
Full, ///< Full emulation (using barriers / ROV)
|
||||
};
|
||||
|
||||
enum class HDRMode : u8
|
||||
{
|
||||
NoModify = 0,
|
||||
ConvertOnly = 1,
|
||||
ResolveOnly = 2,
|
||||
ConvertAndResolve = 3,
|
||||
EarlyResolve = 4
|
||||
};
|
||||
|
||||
GSTexture* rt; ///< Render target
|
||||
GSTexture* ds; ///< Depth stencil
|
||||
GSTexture* tex; ///< Source texture
|
||||
|
@ -730,6 +740,11 @@ struct alignas(16) GSHWDrawConfig
|
|||
|
||||
VSConstantBuffer cb_vs;
|
||||
PSConstantBuffer cb_ps;
|
||||
|
||||
// These are here as they need to be preserved between draws, and the state clear only does up to the constant buffers.
|
||||
HDRMode hdr_mode;
|
||||
GIFRegFRAME hdr_frame;
|
||||
GSVector4i hdr_update_area; ///< Area in the framebuffer which HDR will modify;
|
||||
};
|
||||
|
||||
class GSDevice : public GSAlignedClass<32>
|
||||
|
@ -850,6 +865,7 @@ protected:
|
|||
GSTexture* m_target_tmp = nullptr;
|
||||
GSTexture* m_current = nullptr;
|
||||
GSTexture* m_cas = nullptr;
|
||||
GSTexture* m_hdr_rt = nullptr; ///< Temp HDR texture
|
||||
|
||||
bool AcquireWindow(bool recreate_window);
|
||||
|
||||
|
@ -874,6 +890,10 @@ public:
|
|||
/// Returns a string containing current adapter in use.
|
||||
const std::string& GetName() const { return m_name; }
|
||||
|
||||
GSTexture* GetHDRTexture() const { return m_hdr_rt; }
|
||||
|
||||
void SetHDRTexture(GSTexture* tex) { m_hdr_rt = tex; }
|
||||
|
||||
/// Returns a string representing the specified API.
|
||||
static const char* RenderAPIToString(RenderAPI api);
|
||||
|
||||
|
|
|
@ -2521,6 +2521,47 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
|
|||
|
||||
GSVector2i rtsize = (config.rt ? config.rt : config.ds)->GetSize();
|
||||
|
||||
GSTexture* hdr_rt = g_gs_device->GetHDRTexture();
|
||||
|
||||
if (hdr_rt)
|
||||
{
|
||||
if (config.hdr_mode == GSHWDrawConfig::HDRMode::EarlyResolve)
|
||||
{
|
||||
const GSVector2i size = config.rt->GetSize();
|
||||
const GSVector4 dRect(config.hdr_update_area);
|
||||
const GSVector4 sRect = dRect / GSVector4(size.x, size.y).xyxy();
|
||||
StretchRect(hdr_rt, sRect, config.rt, dRect, ShaderConvert::HDR_RESOLVE, false);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
Recycle(hdr_rt);
|
||||
|
||||
g_gs_device->SetHDRTexture(nullptr);
|
||||
|
||||
hdr_rt = nullptr;
|
||||
}
|
||||
else
|
||||
config.ps.hdr = 1;
|
||||
}
|
||||
|
||||
if (config.ps.hdr)
|
||||
{
|
||||
if (!hdr_rt)
|
||||
{
|
||||
config.hdr_update_area = config.drawarea;
|
||||
|
||||
const GSVector4 dRect = GSVector4((config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertOnly) ? GSVector4i::loadh(rtsize) : config.drawarea);
|
||||
const GSVector4 sRect = dRect / GSVector4(rtsize.x, rtsize.y).xyxy();
|
||||
hdr_rt = CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::HDRColor);
|
||||
if (!hdr_rt)
|
||||
return;
|
||||
|
||||
g_gs_device->SetHDRTexture(hdr_rt);
|
||||
// Warning: StretchRect must be called before BeginScene otherwise
|
||||
// vertices will be overwritten. Trust me you don't want to do that.
|
||||
StretchRect(config.rt, sRect, hdr_rt, dRect, ShaderConvert::HDR_INIT, false);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
}
|
||||
}
|
||||
|
||||
GSTexture* primid_tex = nullptr;
|
||||
if (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::PrimIDTracking)
|
||||
{
|
||||
|
@ -2528,7 +2569,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
|
|||
if (!primid_tex)
|
||||
return;
|
||||
|
||||
StretchRect(config.rt, GSVector4(config.drawarea) / GSVector4(rtsize).xyxy(),
|
||||
StretchRect(hdr_rt ? hdr_rt : config.rt, GSVector4(config.drawarea) / GSVector4(rtsize).xyxy(),
|
||||
primid_tex, GSVector4(config.drawarea), m_date.primid_init_ps[static_cast<u8>(config.datm)].get(), nullptr, false);
|
||||
}
|
||||
else if (config.destination_alpha != GSHWDrawConfig::DestinationAlphaMode::Off)
|
||||
|
@ -2544,22 +2585,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
|
|||
{GSVector4(dst.z, -dst.w, 0.5f, 1.0f), GSVector2(src.z, src.w)},
|
||||
};
|
||||
|
||||
SetupDATE(config.rt, config.ds, vertices, config.datm);
|
||||
}
|
||||
|
||||
GSTexture* hdr_rt = nullptr;
|
||||
if (config.ps.hdr)
|
||||
{
|
||||
const GSVector4 dRect(config.drawarea);
|
||||
const GSVector4 sRect = dRect / GSVector4(rtsize.x, rtsize.y).xyxy();
|
||||
hdr_rt = CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::HDRColor);
|
||||
if (!hdr_rt)
|
||||
return;
|
||||
|
||||
// Warning: StretchRect must be called before BeginScene otherwise
|
||||
// vertices will be overwritten. Trust me you don't want to do that.
|
||||
StretchRect(config.rt, sRect, hdr_rt, dRect, ShaderConvert::HDR_INIT, false);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
SetupDATE(hdr_rt ? hdr_rt : config.rt, config.ds, vertices, config.datm);
|
||||
}
|
||||
|
||||
if (config.vs.expand != GSHWDrawConfig::VSExpand::None)
|
||||
|
@ -2623,7 +2649,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
|
|||
// Do not always bind the rt when it's not needed,
|
||||
// only bind it when effects use it such as fbmask emulation currently
|
||||
// because we copy the frame buffer and it is quite slow.
|
||||
CloneTexture(config.rt, &rt_copy, config.drawarea);
|
||||
CloneTexture(hdr_rt ? hdr_rt : config.rt, &rt_copy, config.drawarea);
|
||||
if (rt_copy)
|
||||
{
|
||||
if (config.require_one_barrier)
|
||||
|
@ -2690,11 +2716,18 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
|
|||
|
||||
if (hdr_rt)
|
||||
{
|
||||
const GSVector2i size = config.rt->GetSize();
|
||||
const GSVector4 dRect(config.drawarea);
|
||||
const GSVector4 sRect = dRect / GSVector4(size.x, size.y).xyxy();
|
||||
StretchRect(hdr_rt, sRect, config.rt, dRect, ShaderConvert::HDR_RESOLVE, false);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
Recycle(hdr_rt);
|
||||
config.hdr_update_area = config.hdr_update_area.runion(config.drawarea);
|
||||
|
||||
if (config.hdr_mode == GSHWDrawConfig::HDRMode::ResolveOnly || config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertAndResolve)
|
||||
{
|
||||
const GSVector2i size = config.rt->GetSize();
|
||||
const GSVector4 dRect(config.hdr_update_area);
|
||||
const GSVector4 sRect = dRect / GSVector4(size.x, size.y).xyxy();
|
||||
StretchRect(hdr_rt, sRect, config.rt, dRect, ShaderConvert::HDR_RESOLVE, false);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
Recycle(hdr_rt);
|
||||
|
||||
g_gs_device->SetHDRTexture(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3816,18 +3816,64 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
|||
// Destination Alpha Setup
|
||||
const bool stencil_DATE = (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::Stencil ||
|
||||
config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::StencilOne);
|
||||
|
||||
GSTexture12* hdr_rt = static_cast<GSTexture12*>(g_gs_device->GetHDRTexture());
|
||||
GSTexture12* draw_rt = static_cast<GSTexture12*>(config.rt);
|
||||
GSTexture12* draw_ds = static_cast<GSTexture12*>(config.ds);
|
||||
GSTexture12* draw_rt_clone = nullptr;
|
||||
|
||||
// Align the render area to 128x128, hopefully avoiding render pass restarts for small render area changes (e.g. Ratchet and Clank).
|
||||
const GSVector2i rtsize(config.rt ? config.rt->GetSize() : config.ds->GetSize());
|
||||
|
||||
PipelineSelector& pipe = m_pipeline_selector;
|
||||
|
||||
// figure out the pipeline
|
||||
UpdateHWPipelineSelector(config);
|
||||
|
||||
// now blit the hdr texture back to the original target
|
||||
if (hdr_rt)
|
||||
{
|
||||
if (config.hdr_mode == GSHWDrawConfig::HDRMode::EarlyResolve)
|
||||
{
|
||||
GL_PUSH("Blit HDR back to RT");
|
||||
|
||||
EndRenderPass();
|
||||
hdr_rt->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
|
||||
draw_rt = static_cast<GSTexture12*>(config.rt);
|
||||
OMSetRenderTargets(draw_rt, draw_ds, config.scissor);
|
||||
|
||||
// if this target was cleared and never drawn to, perform the clear as part of the resolve here.
|
||||
BeginRenderPass(GetLoadOpForTexture(draw_rt), D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE,
|
||||
GetLoadOpForTexture(draw_ds),
|
||||
draw_ds ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE : D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
|
||||
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
|
||||
draw_rt->GetUNormClearColor(), 0.0f, 0);
|
||||
|
||||
const GSVector4 sRect(GSVector4(config.hdr_update_area) / GSVector4(rtsize.x, rtsize.y).xyxy());
|
||||
SetPipeline(m_hdr_finish_pipelines[pipe.ds].get());
|
||||
SetUtilityTexture(hdr_rt, m_point_sampler_cpu);
|
||||
DrawStretchRect(sRect, GSVector4(config.hdr_update_area), rtsize);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
|
||||
Recycle(hdr_rt);
|
||||
g_gs_device->SetHDRTexture(nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
draw_rt = hdr_rt;
|
||||
pipe.ps.hdr = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (stencil_DATE)
|
||||
SetupDATE(config.rt, config.ds, config.datm, config.drawarea);
|
||||
SetupDATE(draw_rt, config.ds, config.datm, config.drawarea);
|
||||
|
||||
// stream buffer in first, in case we need to exec
|
||||
SetVSConstantBuffer(config.cb_vs);
|
||||
SetPSConstantBuffer(config.cb_ps);
|
||||
|
||||
// figure out the pipeline
|
||||
UpdateHWPipelineSelector(config);
|
||||
|
||||
// bind textures before checking the render pass, in case we need to transition them
|
||||
PipelineSelector& pipe = m_pipeline_selector;
|
||||
if (config.tex)
|
||||
{
|
||||
PSSetShaderResource(0, config.tex, config.tex != config.rt);
|
||||
|
@ -3843,7 +3889,10 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
|||
GSTexture12* date_image = nullptr;
|
||||
if (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::PrimIDTracking)
|
||||
{
|
||||
GSTexture* backup_rt = config.rt;
|
||||
config.rt = draw_rt;
|
||||
date_image = SetupPrimitiveTrackingDATE(config, pipe);
|
||||
config.rt = backup_rt;
|
||||
if (!date_image)
|
||||
{
|
||||
Console.WriteLn("D3D12: Failed to allocate DATE image, aborting draw.");
|
||||
|
@ -3851,57 +3900,10 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
|||
}
|
||||
}
|
||||
|
||||
// Align the render area to 128x128, hopefully avoiding render pass restarts for small render area changes (e.g. Ratchet and Clank).
|
||||
const int render_area_alignment = 128 * GSConfig.UpscaleMultiplier;
|
||||
const GSVector2i rtsize(config.rt ? config.rt->GetSize() : config.ds->GetSize());
|
||||
const GSVector4i render_area(
|
||||
config.ps.hdr ? config.drawarea :
|
||||
GSVector4i(Common::AlignDownPow2(config.scissor.left, render_area_alignment),
|
||||
Common::AlignDownPow2(config.scissor.top, render_area_alignment),
|
||||
std::min(Common::AlignUpPow2(config.scissor.right, render_area_alignment), rtsize.x),
|
||||
std::min(Common::AlignUpPow2(config.scissor.bottom, render_area_alignment), rtsize.y)));
|
||||
|
||||
GSTexture12* draw_rt = static_cast<GSTexture12*>(config.rt);
|
||||
GSTexture12* draw_ds = static_cast<GSTexture12*>(config.ds);
|
||||
GSTexture12* draw_rt_clone = nullptr;
|
||||
GSTexture12* hdr_rt = nullptr;
|
||||
|
||||
// Switch to hdr target for colclip rendering
|
||||
if (pipe.ps.hdr)
|
||||
{
|
||||
EndRenderPass();
|
||||
|
||||
hdr_rt = static_cast<GSTexture12*>(CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::HDRColor, false));
|
||||
if (!hdr_rt)
|
||||
{
|
||||
Console.WriteLn("D3D12: Failed to allocate HDR render target, aborting draw.");
|
||||
if (date_image)
|
||||
Recycle(date_image);
|
||||
return;
|
||||
}
|
||||
|
||||
// propagate clear value through if the hdr render is the first
|
||||
if (draw_rt->GetState() == GSTexture::State::Cleared)
|
||||
{
|
||||
hdr_rt->SetState(GSTexture::State::Cleared);
|
||||
hdr_rt->SetClearColor(draw_rt->GetClearColor());
|
||||
}
|
||||
else if (draw_rt->GetState() == GSTexture::State::Dirty)
|
||||
{
|
||||
GL_PUSH_("HDR Render Target Setup");
|
||||
draw_rt->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
}
|
||||
|
||||
// we're not drawing to the RT, so we can use it as a source
|
||||
if (config.require_one_barrier)
|
||||
PSSetShaderResource(2, draw_rt, true);
|
||||
|
||||
draw_rt = hdr_rt;
|
||||
}
|
||||
else if (config.require_one_barrier)
|
||||
if (config.require_one_barrier)
|
||||
{
|
||||
// requires a copy of the RT
|
||||
draw_rt_clone = static_cast<GSTexture12*>(CreateTexture(rtsize.x, rtsize.y, 1, GSTexture::Format::Color, true));
|
||||
draw_rt_clone = static_cast<GSTexture12*>(CreateTexture(rtsize.x, rtsize.y, 1, hdr_rt ? GSTexture::Format::HDRColor : GSTexture::Format::Color, true));
|
||||
if (draw_rt_clone)
|
||||
{
|
||||
EndRenderPass();
|
||||
|
@ -3915,8 +3917,50 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
|||
}
|
||||
}
|
||||
|
||||
// Switch to hdr target for colclip rendering
|
||||
if (pipe.ps.hdr)
|
||||
{
|
||||
if (!hdr_rt)
|
||||
{
|
||||
config.hdr_update_area = config.drawarea;
|
||||
|
||||
EndRenderPass();
|
||||
|
||||
hdr_rt = static_cast<GSTexture12*>(CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::HDRColor, false));
|
||||
if (!hdr_rt)
|
||||
{
|
||||
Console.WriteLn("D3D12: Failed to allocate HDR render target, aborting draw.");
|
||||
|
||||
if (date_image)
|
||||
Recycle(date_image);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
g_gs_device->SetHDRTexture(static_cast<GSTexture*>(hdr_rt));
|
||||
|
||||
// propagate clear value through if the hdr render is the first
|
||||
if (draw_rt->GetState() == GSTexture::State::Cleared)
|
||||
{
|
||||
hdr_rt->SetState(GSTexture::State::Cleared);
|
||||
hdr_rt->SetClearColor(draw_rt->GetClearColor());
|
||||
}
|
||||
else if (draw_rt->GetState() == GSTexture::State::Dirty)
|
||||
{
|
||||
GL_PUSH_("HDR Render Target Setup");
|
||||
draw_rt->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
}
|
||||
|
||||
// we're not drawing to the RT, so we can use it as a source
|
||||
if (config.require_one_barrier)
|
||||
PSSetShaderResource(2, draw_rt, true);
|
||||
}
|
||||
|
||||
draw_rt = hdr_rt;
|
||||
}
|
||||
|
||||
// clear texture binding when it's bound to RT or DS
|
||||
if (((config.rt && static_cast<GSTexture12*>(config.rt)->GetSRVDescriptor() == m_tfx_textures[0]) ||
|
||||
if (((draw_rt && static_cast<GSTexture12*>(draw_rt)->GetSRVDescriptor() == m_tfx_textures[0]) ||
|
||||
(config.ds && static_cast<GSTexture12*>(config.ds)->GetSRVDescriptor() == m_tfx_textures[0])))
|
||||
{
|
||||
PSSetShaderResource(0, nullptr, false);
|
||||
|
@ -3964,13 +4008,14 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
|||
}
|
||||
|
||||
// rt -> hdr blit if enabled
|
||||
if (hdr_rt && config.rt->GetState() == GSTexture::State::Dirty)
|
||||
if (hdr_rt && (config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertOnly || config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertAndResolve) && config.rt->GetState() == GSTexture::State::Dirty)
|
||||
{
|
||||
SetUtilityTexture(static_cast<GSTexture12*>(config.rt), m_point_sampler_cpu);
|
||||
SetPipeline(m_hdr_setup_pipelines[pipe.ds].get());
|
||||
|
||||
const GSVector4 sRect(GSVector4(render_area) / GSVector4(rtsize.x, rtsize.y).xyxy());
|
||||
DrawStretchRect(sRect, GSVector4(render_area), rtsize);
|
||||
const GSVector4 drawareaf = GSVector4((config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertOnly) ? GSVector4i::loadh(rtsize) : config.drawarea);
|
||||
const GSVector4 sRect(drawareaf / GSVector4(rtsize.x, rtsize.y).xyxy());
|
||||
DrawStretchRect(sRect, GSVector4(drawareaf), rtsize);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
|
||||
GL_POP();
|
||||
|
@ -4025,28 +4070,34 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
|||
// now blit the hdr texture back to the original target
|
||||
if (hdr_rt)
|
||||
{
|
||||
GL_PUSH("Blit HDR back to RT");
|
||||
config.hdr_update_area = config.hdr_update_area.runion(config.drawarea);
|
||||
|
||||
EndRenderPass();
|
||||
hdr_rt->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
if ((config.hdr_mode == GSHWDrawConfig::HDRMode::ResolveOnly || config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertAndResolve))
|
||||
{
|
||||
GL_PUSH("Blit HDR back to RT");
|
||||
|
||||
draw_rt = static_cast<GSTexture12*>(config.rt);
|
||||
OMSetRenderTargets(draw_rt, draw_ds, config.scissor);
|
||||
EndRenderPass();
|
||||
hdr_rt->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
|
||||
// if this target was cleared and never drawn to, perform the clear as part of the resolve here.
|
||||
BeginRenderPass(GetLoadOpForTexture(draw_rt), D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE,
|
||||
GetLoadOpForTexture(draw_ds),
|
||||
draw_ds ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE : D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
|
||||
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
|
||||
draw_rt->GetUNormClearColor(), 0.0f, 0);
|
||||
draw_rt = static_cast<GSTexture12*>(config.rt);
|
||||
OMSetRenderTargets(draw_rt, draw_ds, config.scissor);
|
||||
|
||||
const GSVector4 sRect(GSVector4(render_area) / GSVector4(rtsize.x, rtsize.y).xyxy());
|
||||
SetPipeline(m_hdr_finish_pipelines[pipe.ds].get());
|
||||
SetUtilityTexture(hdr_rt, m_point_sampler_cpu);
|
||||
DrawStretchRect(sRect, GSVector4(render_area), rtsize);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
// if this target was cleared and never drawn to, perform the clear as part of the resolve here.
|
||||
BeginRenderPass(GetLoadOpForTexture(draw_rt), D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE,
|
||||
GetLoadOpForTexture(draw_ds),
|
||||
draw_ds ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE : D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
|
||||
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
|
||||
draw_rt->GetUNormClearColor(), 0.0f, 0);
|
||||
|
||||
Recycle(hdr_rt);
|
||||
const GSVector4 sRect(GSVector4(config.hdr_update_area) / GSVector4(rtsize.x, rtsize.y).xyxy());
|
||||
SetPipeline(m_hdr_finish_pipelines[pipe.ds].get());
|
||||
SetUtilityTexture(hdr_rt, m_point_sampler_cpu);
|
||||
DrawStretchRect(sRect, GSVector4(config.hdr_update_area), rtsize);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
|
||||
Recycle(hdr_rt);
|
||||
g_gs_device->SetHDRTexture(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -970,6 +970,21 @@ GSVector2i GSRendererHW::GetTargetSize(const GSTextureCache::Source* tex, const
|
|||
return g_texture_cache->GetTargetSize(m_cached_ctx.FRAME.Block(), m_cached_ctx.FRAME.FBW, m_cached_ctx.FRAME.PSM, valid_size.x, valid_size.y, can_expand);
|
||||
}
|
||||
|
||||
bool GSRendererHW::NextDrawHDR() const
|
||||
{
|
||||
const int get_next_ctx = (m_state_flush_reason == CONTEXTCHANGE) ? m_env.PRIM.CTXT : m_backed_up_ctx;
|
||||
const GSDrawingContext& next_ctx = m_env.CTXT[get_next_ctx];
|
||||
|
||||
// If it wasn't a context change we can't guarantee the next draw is going to be set up
|
||||
if (m_state_flush_reason != GSFlushReason::CONTEXTCHANGE || m_env.COLCLAMP.CLAMP != 0 || m_env.PRIM.ABE == 0 ||
|
||||
(m_context->FRAME.U64 ^ next_ctx.FRAME.U64) != 0 || (m_env.PRIM.TME && next_ctx.TEX0.TBP0 == m_context->FRAME.Block()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSRendererHW::IsPossibleChannelShuffle() const
|
||||
{
|
||||
if (!PRIM->TME || m_cached_ctx.TEX0.PSM != PSMT8 || // 8-bit texture draw
|
||||
|
@ -2150,6 +2165,35 @@ void GSRendererHW::Draw()
|
|||
return;
|
||||
}
|
||||
|
||||
// I hate that I have to do this, but some games (like Pac-Man World Rally) troll us by causing a flush with degenerate triangles, so we don't have all available information about the next draw.
|
||||
// So we have to check when the next draw happens if our frame has changed or if it's become recursive.
|
||||
const bool has_HDR_texture = g_gs_device->GetHDRTexture() != nullptr;
|
||||
if (!no_rt && has_HDR_texture && (m_conf.hdr_frame.FBP != m_cached_ctx.FRAME.FBP || m_conf.hdr_frame.Block() == m_cached_ctx.TEX0.TBP0))
|
||||
{
|
||||
GIFRegTEX0 FRAME;
|
||||
FRAME.TBP0 = m_conf.hdr_frame.Block();
|
||||
FRAME.TBW = m_conf.hdr_frame.FBW;
|
||||
FRAME.PSM = m_conf.hdr_frame.PSM;
|
||||
|
||||
GSTextureCache::Target* old_rt = g_texture_cache->LookupTarget(FRAME, GSVector2i(1, 1), GetTextureScaleFactor(), GSTextureCache::RenderTarget, true,
|
||||
fm, false, false, true, true, GSVector4i(0, 0, 1, 1), true, false, false);
|
||||
|
||||
if (old_rt)
|
||||
{
|
||||
GL_CACHE("Pre-draw resolve of HDR! Address: %x", FRAME.TBP0);
|
||||
GSTexture* hdr_texture = g_gs_device->GetHDRTexture();
|
||||
g_gs_device->StretchRect(hdr_texture, GSVector4(m_conf.hdr_update_area) / GSVector4(GSVector4i(hdr_texture->GetSize()).xyxy()), old_rt->m_texture, GSVector4(m_conf.hdr_update_area),
|
||||
ShaderConvert::HDR_RESOLVE, false);
|
||||
|
||||
g_gs_device->Recycle(hdr_texture);
|
||||
|
||||
g_gs_device->SetHDRTexture(nullptr);
|
||||
|
||||
}
|
||||
else
|
||||
DevCon.Warning("Error resolving HDR texture for pre-draw resolve");
|
||||
}
|
||||
|
||||
const bool draw_sprite_tex = PRIM->TME && (m_vt.m_primclass == GS_SPRITE_CLASS);
|
||||
|
||||
// We trigger the sw prim render here super early, to avoid creating superfluous render targets.
|
||||
|
@ -3413,10 +3457,19 @@ void GSRendererHW::Draw()
|
|||
GSTextureCache::RenderTarget, m_cached_ctx.ZBUF.Block(), m_cached_ctx.ZBUF.PSM, zm);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
|
||||
if (GSConfig.DumpGSData)
|
||||
{
|
||||
const bool writeback_HDR_texture = g_gs_device->GetHDRTexture() != nullptr;
|
||||
if (writeback_HDR_texture)
|
||||
{
|
||||
GSTexture* hdr_texture = g_gs_device->GetHDRTexture();
|
||||
g_gs_device->StretchRect(hdr_texture, GSVector4(m_conf.hdr_update_area) / GSVector4(GSVector4i(hdr_texture->GetSize()).xyxy()), rt->m_texture, GSVector4(m_conf.hdr_update_area),
|
||||
ShaderConvert::HDR_RESOLVE, false);
|
||||
}
|
||||
|
||||
const u64 frame = g_perfmon.GetFrame();
|
||||
|
||||
std::string s;
|
||||
|
@ -4404,14 +4457,36 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
|
|||
// Color clip
|
||||
if (COLCLAMP.CLAMP == 0)
|
||||
{
|
||||
const bool free_colclip = features.framebuffer_fetch || no_prim_overlap || blend_non_recursive;
|
||||
bool has_HDR_texture = g_gs_device->GetHDRTexture() != nullptr;
|
||||
|
||||
// Don't know any game that resizes the RT mid HDR, but gotta be careful.
|
||||
if (has_HDR_texture)
|
||||
{
|
||||
GSTexture* hdr_texture = g_gs_device->GetHDRTexture();
|
||||
|
||||
if (hdr_texture->GetSize() != rt->m_texture->GetSize())
|
||||
{
|
||||
|
||||
GL_CACHE("Pre-Blend resolve of HDR due to size change! Address: %x", rt->m_TEX0.TBP0);
|
||||
g_gs_device->StretchRect(hdr_texture, GSVector4(m_conf.hdr_update_area) / GSVector4(GSVector4i(hdr_texture->GetSize()).xyxy()), rt->m_texture, GSVector4(m_conf.hdr_update_area),
|
||||
ShaderConvert::HDR_RESOLVE, false);
|
||||
|
||||
g_gs_device->Recycle(hdr_texture);
|
||||
|
||||
g_gs_device->SetHDRTexture(nullptr);
|
||||
|
||||
has_HDR_texture = false;
|
||||
}
|
||||
}
|
||||
|
||||
const bool free_colclip = !has_HDR_texture && (features.framebuffer_fetch || no_prim_overlap || blend_non_recursive);
|
||||
GL_DBG("COLCLIP Info (Blending: %u/%u/%u/%u, OVERLAP: %d)", m_conf.ps.blend_a, m_conf.ps.blend_b, m_conf.ps.blend_c, m_conf.ps.blend_d, m_prim_overlap);
|
||||
if (color_dest_blend || color_dest_blend2 || blend_zero_to_one_range)
|
||||
{
|
||||
// No overflow, disable colclip.
|
||||
GL_INS("COLCLIP mode DISABLED");
|
||||
sw_blending = false;
|
||||
m_conf.hdr_mode = (has_HDR_texture && !NextDrawHDR()) ? GSHWDrawConfig::HDRMode::ResolveOnly : GSHWDrawConfig::HDRMode::NoModify;
|
||||
}
|
||||
else if (free_colclip)
|
||||
{
|
||||
|
@ -4422,6 +4497,7 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
|
|||
// Disable the HDR algo
|
||||
accumulation_blend = false;
|
||||
blend_mix = false;
|
||||
m_conf.hdr_mode = (has_HDR_texture && !NextDrawHDR()) ? GSHWDrawConfig::HDRMode::ResolveOnly : GSHWDrawConfig::HDRMode::NoModify;
|
||||
}
|
||||
else if (accumulation_blend)
|
||||
{
|
||||
|
@ -4429,18 +4505,24 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
|
|||
GL_INS("COLCLIP Fast HDR mode ENABLED");
|
||||
m_conf.ps.hdr = 1;
|
||||
sw_blending = true; // Enable sw blending for the HDR algo
|
||||
|
||||
m_conf.hdr_mode = has_HDR_texture ? (NextDrawHDR() ? GSHWDrawConfig::HDRMode::NoModify : GSHWDrawConfig::HDRMode::ResolveOnly) : (NextDrawHDR() ? GSHWDrawConfig::HDRMode::ConvertOnly : GSHWDrawConfig::HDRMode::ConvertAndResolve);
|
||||
}
|
||||
else if (sw_blending)
|
||||
{
|
||||
// A slow algo that could requires several passes (barely used)
|
||||
GL_INS("COLCLIP SW mode ENABLED");
|
||||
m_conf.ps.colclip = 1;
|
||||
m_conf.hdr_mode = (has_HDR_texture && !NextDrawHDR()) ? GSHWDrawConfig::HDRMode::ResolveOnly : GSHWDrawConfig::HDRMode::NoModify;
|
||||
}
|
||||
else
|
||||
{
|
||||
GL_INS("COLCLIP HDR mode ENABLED");
|
||||
m_conf.ps.hdr = 1;
|
||||
m_conf.hdr_mode = has_HDR_texture ? (NextDrawHDR() ? GSHWDrawConfig::HDRMode::NoModify : GSHWDrawConfig::HDRMode::ResolveOnly) : (NextDrawHDR() ? GSHWDrawConfig::HDRMode::ConvertOnly : GSHWDrawConfig::HDRMode::ConvertAndResolve);
|
||||
}
|
||||
|
||||
m_conf.hdr_frame = m_cached_ctx.FRAME;
|
||||
}
|
||||
|
||||
// Per pixel alpha blending
|
||||
|
@ -4474,8 +4556,10 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
|
|||
// HDR mode should be disabled when doing sw blend, swap with sw colclip.
|
||||
if (m_conf.ps.hdr)
|
||||
{
|
||||
bool has_HDR_texture = g_gs_device->GetHDRTexture() != nullptr;
|
||||
m_conf.ps.hdr = 0;
|
||||
m_conf.ps.colclip = 1;
|
||||
m_conf.hdr_mode = has_HDR_texture ? GSHWDrawConfig::HDRMode::EarlyResolve : GSHWDrawConfig::HDRMode::NoModify;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -111,7 +111,7 @@ private:
|
|||
void EmulateATST(float& AREF, GSHWDrawConfig::PSSelector& ps, bool pass_2);
|
||||
|
||||
void SetTCOffset();
|
||||
|
||||
bool NextDrawHDR() const;
|
||||
bool IsPossibleChannelShuffle() const;
|
||||
bool NextDrawMatchesShuffle() const;
|
||||
bool IsSplitTextureShuffle(GSTextureCache::Target* rt);
|
||||
|
|
|
@ -2135,6 +2135,64 @@ void GSDeviceMTL::RenderHW(GSHWDrawConfig& config)
|
|||
GSTexture* stencil = nullptr;
|
||||
GSTexture* primid_tex = nullptr;
|
||||
GSTexture* rt = config.rt;
|
||||
GSTexture* hdr_rt = g_gs_device->GetHDRTexture();
|
||||
|
||||
if (hdr_rt)
|
||||
{
|
||||
if (config.hdr_mode == GSHWDrawConfig::HDRMode::EarlyResolve)
|
||||
{
|
||||
BeginRenderPass(@"HDR Resolve", config.rt, MTLLoadActionLoad, nullptr, MTLLoadActionDontCare);
|
||||
RenderCopy(hdr_rt, m_hdr_resolve_pipeline, config.hdr_update_area);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
|
||||
Recycle(hdr_rt);
|
||||
|
||||
g_gs_device->SetHDRTexture(nullptr);
|
||||
|
||||
hdr_rt = nullptr;
|
||||
}
|
||||
else
|
||||
config.ps.hdr = 1;
|
||||
}
|
||||
|
||||
if (config.ps.hdr)
|
||||
{
|
||||
if (!hdr_rt)
|
||||
{
|
||||
config.hdr_update_area = config.drawarea;
|
||||
|
||||
GSVector2i size = config.rt->GetSize();
|
||||
rt = hdr_rt = CreateRenderTarget(size.x, size.y, GSTexture::Format::HDRColor, false);
|
||||
|
||||
g_gs_device->SetHDRTexture(hdr_rt);
|
||||
|
||||
const GSVector4i copy_rect = (config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertOnly) ? GSVector4i::loadh(size) : config.drawarea;
|
||||
|
||||
switch (config.rt->GetState())
|
||||
{
|
||||
case GSTexture::State::Dirty:
|
||||
BeginRenderPass(@"HDR Init", hdr_rt, MTLLoadActionDontCare, nullptr, MTLLoadActionDontCare);
|
||||
RenderCopy(config.rt, m_hdr_init_pipeline, copy_rect);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
break;
|
||||
|
||||
case GSTexture::State::Cleared:
|
||||
{
|
||||
BeginRenderPass(@"HDR Clear", hdr_rt, MTLLoadActionDontCare, nullptr, MTLLoadActionDontCare);
|
||||
GSVector4 color = GSVector4::rgba32(config.rt->GetClearColor()) / GSVector4::cxpr(65535, 65535, 65535, 255);
|
||||
[m_current_render.encoder setFragmentBytes:&color length:sizeof(color) atIndex:GSMTLBufferIndexUniforms];
|
||||
RenderCopy(nullptr, m_hdr_clear_pipeline, copy_rect);
|
||||
break;
|
||||
}
|
||||
|
||||
case GSTexture::State::Invalidated:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rt = hdr_rt;
|
||||
}
|
||||
|
||||
switch (config.destination_alpha)
|
||||
{
|
||||
case GSHWDrawConfig::DestinationAlphaMode::Off:
|
||||
|
@ -2142,18 +2200,18 @@ void GSDeviceMTL::RenderHW(GSHWDrawConfig& config)
|
|||
break; // No setup
|
||||
case GSHWDrawConfig::DestinationAlphaMode::PrimIDTracking:
|
||||
{
|
||||
FlushClears(config.rt);
|
||||
GSVector2i size = config.rt->GetSize();
|
||||
FlushClears(rt);
|
||||
GSVector2i size = rt->GetSize();
|
||||
primid_tex = CreateRenderTarget(size.x, size.y, GSTexture::Format::PrimID);
|
||||
DepthStencilSelector dsel = config.depth;
|
||||
dsel.zwe = 0;
|
||||
GSTexture* depth = dsel.key == DepthStencilSelector::NoDepth().key ? nullptr : config.ds;
|
||||
BeginRenderPass(@"PrimID Destination Alpha Init", primid_tex, MTLLoadActionDontCare, depth, MTLLoadActionLoad);
|
||||
RenderCopy(config.rt, m_primid_init_pipeline[static_cast<bool>(depth)][static_cast<u8>(config.datm)], config.drawarea);
|
||||
RenderCopy(rt, m_primid_init_pipeline[static_cast<bool>(depth)][static_cast<u8>(config.datm)], config.drawarea);
|
||||
MRESetDSS(dsel);
|
||||
pxAssert(config.ps.date == 1 || config.ps.date == 2);
|
||||
if (config.ps.tex_is_fb)
|
||||
MRESetTexture(config.rt, GSMTLTextureIndexRenderTarget);
|
||||
MRESetTexture(rt, GSMTLTextureIndexRenderTarget);
|
||||
config.require_one_barrier = false; // Ending render pass is our barrier
|
||||
pxAssert(config.require_full_barrier == false && config.drawlist == nullptr);
|
||||
MRESetHWPipelineState(config.vs, config.ps, {}, {});
|
||||
|
@ -2170,38 +2228,11 @@ void GSDeviceMTL::RenderHW(GSHWDrawConfig& config)
|
|||
stencil = config.ds;
|
||||
break;
|
||||
case GSHWDrawConfig::DestinationAlphaMode::Stencil:
|
||||
SetupDestinationAlpha(config.rt, config.ds, config.drawarea, config.datm);
|
||||
SetupDestinationAlpha(rt, config.ds, config.drawarea, config.datm);
|
||||
stencil = config.ds;
|
||||
break;
|
||||
}
|
||||
|
||||
GSTexture* hdr_rt = nullptr;
|
||||
if (config.ps.hdr)
|
||||
{
|
||||
GSVector2i size = config.rt->GetSize();
|
||||
rt = hdr_rt = CreateRenderTarget(size.x, size.y, GSTexture::Format::HDRColor, false);
|
||||
switch (config.rt->GetState())
|
||||
{
|
||||
case GSTexture::State::Dirty:
|
||||
BeginRenderPass(@"HDR Init", hdr_rt, MTLLoadActionDontCare, nullptr, MTLLoadActionDontCare);
|
||||
RenderCopy(config.rt, m_hdr_init_pipeline, config.drawarea);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
break;
|
||||
|
||||
case GSTexture::State::Cleared:
|
||||
{
|
||||
BeginRenderPass(@"HDR Clear", hdr_rt, MTLLoadActionDontCare, nullptr, MTLLoadActionDontCare);
|
||||
GSVector4 color = GSVector4::rgba32(config.rt->GetClearColor()) / GSVector4::cxpr(65535, 65535, 65535, 255);
|
||||
[m_current_render.encoder setFragmentBytes:&color length:sizeof(color) atIndex:GSMTLBufferIndexUniforms];
|
||||
RenderCopy(nullptr, m_hdr_clear_pipeline, config.drawarea);
|
||||
break;
|
||||
}
|
||||
|
||||
case GSTexture::State::Invalidated:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to reduce render pass restarts
|
||||
if (!config.ds && m_current_render.color_target == rt && stencil == m_current_render.stencil_target && m_current_render.depth_target != config.tex)
|
||||
config.ds = m_current_render.depth_target;
|
||||
|
@ -2224,7 +2255,7 @@ void GSDeviceMTL::RenderHW(GSHWDrawConfig& config)
|
|||
[mtlenc setStencilReferenceValue:1];
|
||||
MREInitHWDraw(config, allocation);
|
||||
if (config.require_one_barrier || config.require_full_barrier)
|
||||
MRESetTexture(config.rt, GSMTLTextureIndexRenderTarget);
|
||||
MRESetTexture(rt, GSMTLTextureIndexRenderTarget);
|
||||
if (primid_tex)
|
||||
MRESetTexture(primid_tex, GSMTLTextureIndexPrimIDs);
|
||||
if (config.blend.constant_enable)
|
||||
|
@ -2248,11 +2279,18 @@ void GSDeviceMTL::RenderHW(GSHWDrawConfig& config)
|
|||
|
||||
if (hdr_rt)
|
||||
{
|
||||
BeginRenderPass(@"HDR Resolve", config.rt, MTLLoadActionLoad, nullptr, MTLLoadActionDontCare);
|
||||
RenderCopy(hdr_rt, m_hdr_resolve_pipeline, config.drawarea);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
config.hdr_update_area = config.hdr_update_area.runion(config.drawarea);
|
||||
|
||||
Recycle(hdr_rt);
|
||||
if ((config.hdr_mode == GSHWDrawConfig::HDRMode::ResolveOnly || config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertAndResolve))
|
||||
{
|
||||
BeginRenderPass(@"HDR Resolve", config.rt, MTLLoadActionLoad, nullptr, MTLLoadActionDontCare);
|
||||
RenderCopy(hdr_rt, m_hdr_resolve_pipeline, config.hdr_update_area);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
|
||||
Recycle(hdr_rt);
|
||||
|
||||
g_gs_device->SetHDRTexture(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
if (primid_tex)
|
||||
|
|
|
@ -856,7 +856,10 @@ struct PSMain
|
|||
void ps_fbmask(thread float4& C)
|
||||
{
|
||||
if (PS_FBMASK)
|
||||
C = float4((uint4(int4(C)) & (cb.fbmask ^ 0xff)) | (uint4(current_color * 255.5) & cb.fbmask));
|
||||
{
|
||||
float multi = PS_HDR ? 65535.0 : 255.5;
|
||||
C = float4((uint4(int4(C)) & (cb.fbmask ^ 0xff)) | (uint4(current_color * float4(multi, multi, multi, 255)) & cb.fbmask));
|
||||
}
|
||||
}
|
||||
|
||||
void ps_dither(thread float4& C, float As)
|
||||
|
@ -956,8 +959,8 @@ struct PSMain
|
|||
current_color.a = float(denorm_rt.g & 0x80);
|
||||
}
|
||||
}
|
||||
|
||||
float3 Cd = trunc(current_color.rgb * 255.5f);
|
||||
float multi = PS_HDR ? 65535.0 : 255.5;
|
||||
float3 Cd = trunc(current_color.rgb * multi);
|
||||
float3 Cs = Color.rgb;
|
||||
|
||||
float3 A = pick(PS_BLEND_A, Cs, Cd, float3(0.f));
|
||||
|
|
|
@ -2414,6 +2414,45 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
|
|||
GSVector2i rtsize = (config.rt ? config.rt : config.ds)->GetSize();
|
||||
|
||||
GSTexture* primid_texture = nullptr;
|
||||
GSTexture* hdr_rt = g_gs_device->GetHDRTexture();
|
||||
|
||||
if (hdr_rt)
|
||||
{
|
||||
if (config.hdr_mode == GSHWDrawConfig::HDRMode::EarlyResolve)
|
||||
{
|
||||
const GSVector2i size = config.rt->GetSize();
|
||||
const GSVector4 dRect(config.hdr_update_area);
|
||||
const GSVector4 sRect = dRect / GSVector4(size.x, size.y).xyxy();
|
||||
StretchRect(hdr_rt, sRect, config.rt, dRect, ShaderConvert::HDR_RESOLVE, false);
|
||||
|
||||
Recycle(hdr_rt);
|
||||
|
||||
g_gs_device->SetHDRTexture(nullptr);
|
||||
|
||||
hdr_rt = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
config.ps.hdr = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (config.ps.hdr)
|
||||
{
|
||||
if (!hdr_rt)
|
||||
{
|
||||
config.hdr_update_area = config.drawarea;
|
||||
|
||||
hdr_rt = CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::HDRColor, false);
|
||||
OMSetRenderTargets(hdr_rt, config.ds, nullptr);
|
||||
|
||||
g_gs_device->SetHDRTexture(hdr_rt);
|
||||
|
||||
const GSVector4 dRect = GSVector4((config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertOnly) ? GSVector4i::loadh(rtsize) : config.drawarea);
|
||||
const GSVector4 sRect = dRect / GSVector4(rtsize.x, rtsize.y).xyxy();
|
||||
StretchRect(config.rt, sRect, hdr_rt, dRect, ShaderConvert::HDR_INIT, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Destination Alpha Setup
|
||||
switch (config.destination_alpha)
|
||||
|
@ -2422,7 +2461,7 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
|
|||
case GSHWDrawConfig::DestinationAlphaMode::Full:
|
||||
break; // No setup
|
||||
case GSHWDrawConfig::DestinationAlphaMode::PrimIDTracking:
|
||||
primid_texture = InitPrimDateTexture(config.rt, config.drawarea, config.datm);
|
||||
primid_texture = InitPrimDateTexture(hdr_rt ? hdr_rt : config.rt, config.drawarea, config.datm);
|
||||
break;
|
||||
case GSHWDrawConfig::DestinationAlphaMode::StencilOne:
|
||||
if (m_features.texture_barrier)
|
||||
|
@ -2442,29 +2481,20 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
|
|||
{GSVector4(dst.x, dst.w, 0.0f, 0.0f), GSVector2(src.x, src.w)},
|
||||
{GSVector4(dst.z, dst.w, 0.0f, 0.0f), GSVector2(src.z, src.w)},
|
||||
};
|
||||
SetupDATE(config.rt, config.ds, vertices, config.datm);
|
||||
SetupDATE(hdr_rt ? hdr_rt : config.rt, config.ds, vertices, config.datm);
|
||||
}
|
||||
}
|
||||
|
||||
GSTexture* hdr_rt = nullptr;
|
||||
GSTexture* draw_rt_clone = nullptr;
|
||||
if (config.ps.hdr)
|
||||
{
|
||||
hdr_rt = CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::HDRColor, false);
|
||||
OMSetRenderTargets(hdr_rt, config.ds, &config.scissor);
|
||||
|
||||
GSVector4 dRect(config.drawarea);
|
||||
const GSVector4 sRect = dRect / GSVector4(rtsize.x, rtsize.y).xyxy();
|
||||
StretchRect(config.rt, sRect, hdr_rt, dRect, ShaderConvert::HDR_INIT, false);
|
||||
}
|
||||
else if (config.require_one_barrier && !m_features.texture_barrier)
|
||||
if (config.require_one_barrier && !m_features.texture_barrier)
|
||||
{
|
||||
// Requires a copy of the RT
|
||||
draw_rt_clone = CreateTexture(rtsize.x, rtsize.y, 1, GSTexture::Format::Color, true);
|
||||
draw_rt_clone = CreateTexture(rtsize.x, rtsize.y, 1, hdr_rt ? GSTexture::Format::HDRColor : GSTexture::Format::Color, true);
|
||||
GL_PUSH("Copy RT to temp texture for fbmask {%d,%d %dx%d}",
|
||||
config.drawarea.left, config.drawarea.top,
|
||||
config.drawarea.width(), config.drawarea.height());
|
||||
CopyRect(config.rt, draw_rt_clone, config.drawarea, config.drawarea.left, config.drawarea.top);
|
||||
CopyRect(hdr_rt ? hdr_rt : config.rt, draw_rt_clone, config.drawarea, config.drawarea.left, config.drawarea.top);
|
||||
}
|
||||
else if (config.tex && config.tex == config.ds)
|
||||
{
|
||||
|
@ -2510,7 +2540,7 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
|
|||
if (draw_rt_clone)
|
||||
PSSetShaderResource(2, draw_rt_clone);
|
||||
else if (config.require_one_barrier || config.require_full_barrier)
|
||||
PSSetShaderResource(2, config.rt);
|
||||
PSSetShaderResource(2, hdr_rt ? hdr_rt : config.rt);
|
||||
|
||||
SetupSampler(config.sampler);
|
||||
|
||||
|
@ -2669,12 +2699,19 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
|
|||
|
||||
if (hdr_rt)
|
||||
{
|
||||
GSVector2i size = config.rt->GetSize();
|
||||
GSVector4 dRect(config.drawarea);
|
||||
const GSVector4 sRect = dRect / GSVector4(size.x, size.y).xyxy();
|
||||
StretchRect(hdr_rt, sRect, config.rt, dRect, ShaderConvert::HDR_RESOLVE, false);
|
||||
config.hdr_update_area = config.hdr_update_area.runion(config.drawarea);
|
||||
|
||||
Recycle(hdr_rt);
|
||||
if ((config.hdr_mode == GSHWDrawConfig::HDRMode::ResolveOnly || config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertAndResolve))
|
||||
{
|
||||
const GSVector2i size = config.rt->GetSize();
|
||||
const GSVector4 dRect(config.hdr_update_area);
|
||||
const GSVector4 sRect = dRect / GSVector4(size.x, size.y).xyxy();
|
||||
StretchRect(hdr_rt, sRect, config.rt, dRect, ShaderConvert::HDR_RESOLVE, false);
|
||||
|
||||
Recycle(hdr_rt);
|
||||
|
||||
g_gs_device->SetHDRTexture(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "GS/Renderers/Vulkan/VKBuilders.h"
|
||||
#include "GS/Renderers/Vulkan/VKShaderCache.h"
|
||||
#include "GS/Renderers/Vulkan/VKSwapChain.h"
|
||||
#include "GS/Renderers/Common/GSDevice.h"
|
||||
|
||||
#include "BuildVersion.h"
|
||||
#include "Host.h"
|
||||
|
@ -5589,28 +5590,12 @@ GSTextureVK* GSDeviceVK::SetupPrimitiveTrackingDATE(GSHWDrawConfig& config)
|
|||
|
||||
void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
|
||||
{
|
||||
// Destination Alpha Setup
|
||||
switch (config.destination_alpha)
|
||||
{
|
||||
case GSHWDrawConfig::DestinationAlphaMode::Off: // No setup
|
||||
case GSHWDrawConfig::DestinationAlphaMode::Full: // No setup
|
||||
case GSHWDrawConfig::DestinationAlphaMode::PrimIDTracking: // Setup is done below
|
||||
break;
|
||||
case GSHWDrawConfig::DestinationAlphaMode::StencilOne: // setup is done below
|
||||
{
|
||||
// we only need to do the setup here if we don't have barriers, in which case do full DATE.
|
||||
if (!m_features.texture_barrier)
|
||||
{
|
||||
SetupDATE(config.rt, config.ds, config.datm, config.drawarea);
|
||||
config.destination_alpha = GSHWDrawConfig::DestinationAlphaMode::Stencil;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GSHWDrawConfig::DestinationAlphaMode::Stencil:
|
||||
SetupDATE(config.rt, config.ds, config.datm, config.drawarea);
|
||||
break;
|
||||
}
|
||||
const GSVector2i rtsize(config.rt ? config.rt->GetSize() : config.ds->GetSize());
|
||||
GSTextureVK* draw_rt = static_cast<GSTextureVK*>(config.rt);
|
||||
GSTextureVK* draw_ds = static_cast<GSTextureVK*>(config.ds);
|
||||
GSTextureVK* draw_rt_clone = nullptr;
|
||||
GSTextureVK* hdr_rt = static_cast<GSTextureVK*>(g_gs_device->GetHDRTexture());
|
||||
|
||||
// stream buffer in first, in case we need to exec
|
||||
SetVSConstantBuffer(config.cb_vs);
|
||||
|
@ -5632,68 +5617,112 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
|
|||
SetLineWidth(config.line_expand ? config.cb_ps.ScaleFactor.z : 1.0f);
|
||||
|
||||
// Primitive ID tracking DATE setup.
|
||||
// Needs to be done before
|
||||
GSTextureVK* date_image = nullptr;
|
||||
if (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::PrimIDTracking)
|
||||
{
|
||||
// If we have a HDR in progress, we need to use the HDR 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(hdr_rt)
|
||||
config.rt = hdr_rt;
|
||||
|
||||
date_image = SetupPrimitiveTrackingDATE(config);
|
||||
if (!date_image)
|
||||
{
|
||||
Console.WriteLn("Failed to allocate DATE image, aborting draw.");
|
||||
return;
|
||||
}
|
||||
|
||||
config.rt = backup_rt;
|
||||
}
|
||||
|
||||
// figure out the pipeline
|
||||
PipelineSelector& pipe = m_pipeline_selector;
|
||||
UpdateHWPipelineSelector(config, pipe);
|
||||
|
||||
const GSVector2i rtsize(config.rt ? config.rt->GetSize() : config.ds->GetSize());
|
||||
GSTextureVK* draw_rt = static_cast<GSTextureVK*>(config.rt);
|
||||
GSTextureVK* draw_ds = static_cast<GSTextureVK*>(config.ds);
|
||||
GSTextureVK* draw_rt_clone = nullptr;
|
||||
GSTextureVK* hdr_rt = nullptr;
|
||||
|
||||
// Switch to hdr target for colclip rendering
|
||||
if (pipe.ps.hdr)
|
||||
// now blit the hdr texture back to the original target
|
||||
if (hdr_rt)
|
||||
{
|
||||
EndRenderPass();
|
||||
|
||||
hdr_rt = static_cast<GSTextureVK*>(CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::HDRColor, false));
|
||||
if (!hdr_rt)
|
||||
if (config.hdr_mode == GSHWDrawConfig::HDRMode::EarlyResolve)
|
||||
{
|
||||
Console.WriteLn("Failed to allocate HDR render target, aborting draw.");
|
||||
if (date_image)
|
||||
Recycle(date_image);
|
||||
GL_POP();
|
||||
return;
|
||||
}
|
||||
GL_PUSH("Blit HDR back to RT");
|
||||
|
||||
// propagate clear value through if the hdr render is the first
|
||||
if (draw_rt->GetState() == GSTexture::State::Cleared)
|
||||
EndRenderPass();
|
||||
hdr_rt->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly);
|
||||
|
||||
draw_rt = static_cast<GSTextureVK*>(config.rt);
|
||||
OMSetRenderTargets(draw_rt, draw_ds, GSVector4i::loadh(rtsize), static_cast<FeedbackLoopFlag>(pipe.feedback_loop_flags));
|
||||
|
||||
// if this target was cleared and never drawn to, perform the clear as part of the resolve here.
|
||||
if (draw_rt->GetState() == GSTexture::State::Cleared)
|
||||
{
|
||||
alignas(16) VkClearValue cvs[2];
|
||||
u32 cv_count = 0;
|
||||
GSVector4::store<true>(&cvs[cv_count++].color, draw_rt->GetUNormClearColor());
|
||||
if (draw_ds)
|
||||
cvs[cv_count++].depthStencil = {draw_ds->GetClearDepth(), 1};
|
||||
|
||||
BeginClearRenderPass(GetTFXRenderPass(true, pipe.ds, false, false, pipe.IsRTFeedbackLoop(),
|
||||
pipe.IsTestingAndSamplingDepth(), VK_ATTACHMENT_LOAD_OP_CLEAR,
|
||||
pipe.ds ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE),
|
||||
draw_rt->GetRect(), cvs, cv_count);
|
||||
draw_rt->SetState(GSTexture::State::Dirty);
|
||||
}
|
||||
else
|
||||
{
|
||||
BeginRenderPass(GetTFXRenderPass(true, pipe.ds, false, false, pipe.IsRTFeedbackLoop(),
|
||||
pipe.IsTestingAndSamplingDepth(), VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||
pipe.ds ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE),
|
||||
draw_rt->GetRect());
|
||||
}
|
||||
|
||||
const GSVector4 drawareaf = GSVector4(config.hdr_update_area);
|
||||
const GSVector4 sRect(drawareaf / GSVector4(rtsize).xyxy());
|
||||
SetPipeline(m_hdr_finish_pipelines[pipe.ds][pipe.IsRTFeedbackLoop()]);
|
||||
SetUtilityTexture(hdr_rt, m_point_sampler);
|
||||
DrawStretchRect(sRect, drawareaf, rtsize);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
|
||||
Recycle(hdr_rt);
|
||||
g_gs_device->SetHDRTexture(nullptr);
|
||||
|
||||
hdr_rt = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
hdr_rt->SetState(GSTexture::State::Cleared);
|
||||
hdr_rt->SetClearColor(draw_rt->GetClearColor());
|
||||
|
||||
// If depth is cleared, we need to commit it, because we're only going to draw to the active part of the FB.
|
||||
if (draw_ds && draw_ds->GetState() == GSTexture::State::Cleared && !config.drawarea.eq(GSVector4i::loadh(rtsize)))
|
||||
draw_ds->CommitClear(m_current_command_buffer);
|
||||
pipe.ps.hdr = 1;
|
||||
draw_rt = hdr_rt;
|
||||
}
|
||||
else if (draw_rt->GetState() == GSTexture::State::Dirty)
|
||||
{
|
||||
GL_PUSH_("HDR Render Target Setup");
|
||||
draw_rt->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly);
|
||||
}
|
||||
|
||||
// we're not drawing to the RT, so we can use it as a source
|
||||
if (config.require_one_barrier && !m_features.texture_barrier)
|
||||
PSSetShaderResource(2, draw_rt, true);
|
||||
|
||||
draw_rt = hdr_rt;
|
||||
}
|
||||
else if (config.require_one_barrier && !m_features.texture_barrier)
|
||||
|
||||
// Destination Alpha Setup
|
||||
switch (config.destination_alpha)
|
||||
{
|
||||
case GSHWDrawConfig::DestinationAlphaMode::Off: // No setup
|
||||
case GSHWDrawConfig::DestinationAlphaMode::Full: // No setup
|
||||
case GSHWDrawConfig::DestinationAlphaMode::PrimIDTracking: // Setup is done below
|
||||
break;
|
||||
case GSHWDrawConfig::DestinationAlphaMode::StencilOne: // setup is done below
|
||||
{
|
||||
// we only need to do the setup here if we don't have barriers, in which case do full DATE.
|
||||
if (!m_features.texture_barrier)
|
||||
{
|
||||
SetupDATE(draw_rt, config.ds, config.datm, config.drawarea);
|
||||
config.destination_alpha = GSHWDrawConfig::DestinationAlphaMode::Stencil;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GSHWDrawConfig::DestinationAlphaMode::Stencil:
|
||||
SetupDATE(draw_rt, config.ds, config.datm, config.drawarea);
|
||||
break;
|
||||
}
|
||||
|
||||
if (config.require_one_barrier && !m_features.texture_barrier)
|
||||
{
|
||||
// requires a copy of the RT
|
||||
draw_rt_clone = static_cast<GSTextureVK*>(CreateTexture(rtsize.x, rtsize.y, 1, GSTexture::Format::Color, true));
|
||||
draw_rt_clone = static_cast<GSTextureVK*>(CreateTexture(rtsize.x, rtsize.y, 1, hdr_rt ? GSTexture::Format::HDRColor : GSTexture::Format::Color, true));
|
||||
if (draw_rt_clone)
|
||||
{
|
||||
EndRenderPass();
|
||||
|
@ -5706,6 +5735,49 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
|
|||
}
|
||||
}
|
||||
|
||||
// Switch to hdr target for colclip rendering
|
||||
if (pipe.ps.hdr)
|
||||
{
|
||||
if (!hdr_rt)
|
||||
{
|
||||
config.hdr_update_area = config.drawarea;
|
||||
EndRenderPass();
|
||||
hdr_rt = static_cast<GSTextureVK*>(CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::HDRColor, false));
|
||||
if (!hdr_rt)
|
||||
{
|
||||
Console.WriteLn("Failed to allocate HDR render target, aborting draw.");
|
||||
|
||||
if (date_image)
|
||||
Recycle(date_image);
|
||||
|
||||
GL_POP();
|
||||
return;
|
||||
}
|
||||
g_gs_device->SetHDRTexture(static_cast<GSTexture*>(hdr_rt));
|
||||
|
||||
// propagate clear value through if the hdr render is the first
|
||||
if (draw_rt->GetState() == GSTexture::State::Cleared)
|
||||
{
|
||||
hdr_rt->SetState(GSTexture::State::Cleared);
|
||||
hdr_rt->SetClearColor(draw_rt->GetClearColor());
|
||||
|
||||
// If depth is cleared, we need to commit it, because we're only going to draw to the active part of the FB.
|
||||
if (draw_ds && draw_ds->GetState() == GSTexture::State::Cleared && !config.drawarea.eq(GSVector4i::loadh(rtsize)))
|
||||
draw_ds->CommitClear(m_current_command_buffer);
|
||||
}
|
||||
else if (draw_rt->GetState() == GSTexture::State::Dirty)
|
||||
{
|
||||
GL_PUSH_("HDR Render Target Setup");
|
||||
draw_rt->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly);
|
||||
}
|
||||
|
||||
// we're not drawing to the RT, so we can use it as a source
|
||||
if (config.require_one_barrier && !m_features.texture_barrier)
|
||||
PSSetShaderResource(2, draw_rt, true);
|
||||
}
|
||||
draw_rt = hdr_rt;
|
||||
}
|
||||
|
||||
// clear texture binding when it's bound to RT or DS.
|
||||
if (!config.tex && ((config.rt && static_cast<GSTextureVK*>(config.rt) == m_tfx_textures[0]) ||
|
||||
(config.ds && static_cast<GSTextureVK*>(config.ds) == m_tfx_textures[0])))
|
||||
|
@ -5714,7 +5786,7 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
|
|||
}
|
||||
|
||||
// render pass restart optimizations
|
||||
if (hdr_rt)
|
||||
if (hdr_rt && (config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertAndResolve || config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertOnly))
|
||||
{
|
||||
// HDR requires blitting.
|
||||
EndRenderPass();
|
||||
|
@ -5774,7 +5846,7 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
|
|||
|
||||
// Only draw to the active area of the HDR 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.hdr && ds_op != VK_ATTACHMENT_LOAD_OP_CLEAR) ? config.drawarea :
|
||||
const GSVector4i render_area = (pipe.ps.hdr && (config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertAndResolve) && ds_op != VK_ATTACHMENT_LOAD_OP_CLEAR) ? config.drawarea :
|
||||
GSVector4i::loadh(rtsize);
|
||||
|
||||
if (is_clearing_rt)
|
||||
|
@ -5813,17 +5885,19 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
|
|||
}
|
||||
|
||||
// rt -> hdr blit if enabled
|
||||
if (hdr_rt && config.rt->GetState() == GSTexture::State::Dirty)
|
||||
if (hdr_rt && (config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertOnly || config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertAndResolve) && config.rt->GetState() == GSTexture::State::Dirty)
|
||||
{
|
||||
OMSetRenderTargets(draw_rt, draw_ds, GSVector4i::loadh(rtsize), static_cast<FeedbackLoopFlag>(pipe.feedback_loop_flags));
|
||||
SetUtilityTexture(static_cast<GSTextureVK*>(config.rt), m_point_sampler);
|
||||
SetPipeline(m_hdr_setup_pipelines[pipe.ds][pipe.IsRTFeedbackLoop()]);
|
||||
|
||||
const GSVector4 drawareaf = GSVector4(config.drawarea);
|
||||
const GSVector4 drawareaf = GSVector4((config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertOnly) ? GSVector4i::loadh(rtsize) : config.drawarea);
|
||||
const GSVector4 sRect(drawareaf / GSVector4(rtsize).xyxy());
|
||||
DrawStretchRect(sRect, drawareaf, rtsize);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
|
||||
GL_POP();
|
||||
OMSetRenderTargets(draw_rt, draw_ds, config.scissor, static_cast<FeedbackLoopFlag>(pipe.feedback_loop_flags));
|
||||
}
|
||||
|
||||
// VB/IB upload, if we did DATE setup and it's not HDR this has already been done
|
||||
|
@ -5880,46 +5954,55 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
|
|||
// now blit the hdr texture back to the original target
|
||||
if (hdr_rt)
|
||||
{
|
||||
GL_PUSH("Blit HDR back to RT");
|
||||
config.hdr_update_area = config.hdr_update_area.runion(config.drawarea);
|
||||
|
||||
EndRenderPass();
|
||||
hdr_rt->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly);
|
||||
|
||||
draw_rt = static_cast<GSTextureVK*>(config.rt);
|
||||
OMSetRenderTargets(draw_rt, draw_ds, config.scissor, static_cast<FeedbackLoopFlag>(pipe.feedback_loop_flags));
|
||||
|
||||
// if this target was cleared and never drawn to, perform the clear as part of the resolve here.
|
||||
if (draw_rt->GetState() == GSTexture::State::Cleared)
|
||||
if ((config.hdr_mode == GSHWDrawConfig::HDRMode::ResolveOnly || config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertAndResolve))
|
||||
{
|
||||
alignas(16) VkClearValue cvs[2];
|
||||
u32 cv_count = 0;
|
||||
GSVector4::store<true>(&cvs[cv_count++].color, draw_rt->GetUNormClearColor());
|
||||
if (draw_ds)
|
||||
cvs[cv_count++].depthStencil = {draw_ds->GetClearDepth(), 1};
|
||||
GL_PUSH("Blit HDR back to RT");
|
||||
|
||||
BeginClearRenderPass(GetTFXRenderPass(true, pipe.ds, false, false, pipe.IsRTFeedbackLoop(),
|
||||
pipe.IsTestingAndSamplingDepth(), VK_ATTACHMENT_LOAD_OP_CLEAR,
|
||||
pipe.ds ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE),
|
||||
draw_rt->GetRect(), cvs, cv_count);
|
||||
draw_rt->SetState(GSTexture::State::Dirty);
|
||||
EndRenderPass();
|
||||
|
||||
hdr_rt->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly);
|
||||
|
||||
draw_rt = static_cast<GSTextureVK*>(config.rt);
|
||||
OMSetRenderTargets(draw_rt, draw_ds, (config.hdr_mode == GSHWDrawConfig::HDRMode::ResolveOnly) ? GSVector4i::loadh(rtsize) : config.scissor, static_cast<FeedbackLoopFlag>(pipe.feedback_loop_flags));
|
||||
|
||||
// if this target was cleared and never drawn to, perform the clear as part of the resolve here.
|
||||
if (draw_rt->GetState() == GSTexture::State::Cleared)
|
||||
{
|
||||
alignas(16) VkClearValue cvs[2];
|
||||
u32 cv_count = 0;
|
||||
GSVector4::store<true>(&cvs[cv_count++].color, draw_rt->GetUNormClearColor());
|
||||
if (draw_ds)
|
||||
cvs[cv_count++].depthStencil = {draw_ds->GetClearDepth(), 1};
|
||||
|
||||
BeginClearRenderPass(GetTFXRenderPass(true, pipe.ds, false, false, pipe.IsRTFeedbackLoop(),
|
||||
pipe.IsTestingAndSamplingDepth(), VK_ATTACHMENT_LOAD_OP_CLEAR,
|
||||
pipe.ds ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE),
|
||||
draw_rt->GetRect(), cvs, cv_count);
|
||||
draw_rt->SetState(GSTexture::State::Dirty);
|
||||
}
|
||||
else
|
||||
{
|
||||
BeginRenderPass(GetTFXRenderPass(true, pipe.ds, false, false, pipe.IsRTFeedbackLoop(),
|
||||
pipe.IsTestingAndSamplingDepth(), VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||
pipe.ds ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE),
|
||||
draw_rt->GetRect());
|
||||
}
|
||||
|
||||
const GSVector4 drawareaf = GSVector4(config.hdr_update_area);
|
||||
const GSVector4 sRect(drawareaf / GSVector4(rtsize).xyxy());
|
||||
SetPipeline(m_hdr_finish_pipelines[pipe.ds][pipe.IsRTFeedbackLoop()]);
|
||||
SetUtilityTexture(hdr_rt, m_point_sampler);
|
||||
DrawStretchRect(sRect, drawareaf, rtsize);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
|
||||
Recycle(hdr_rt);
|
||||
g_gs_device->SetHDRTexture(nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
BeginRenderPass(GetTFXRenderPass(true, pipe.ds, false, false, pipe.IsRTFeedbackLoop(),
|
||||
pipe.IsTestingAndSamplingDepth(), VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||
pipe.ds ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE),
|
||||
draw_rt->GetRect());
|
||||
}
|
||||
|
||||
const GSVector4 drawareaf = GSVector4(config.drawarea);
|
||||
const GSVector4 sRect(drawareaf / GSVector4(rtsize).xyxy());
|
||||
SetPipeline(m_hdr_finish_pipelines[pipe.ds][pipe.IsRTFeedbackLoop()]);
|
||||
SetUtilityTexture(hdr_rt, m_point_sampler);
|
||||
DrawStretchRect(sRect, drawareaf, rtsize);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
|
||||
Recycle(hdr_rt);
|
||||
}
|
||||
|
||||
config.hdr_mode = GSHWDrawConfig::HDRMode::NoModify;
|
||||
}
|
||||
|
||||
void GSDeviceVK::UpdateHWPipelineSelector(GSHWDrawConfig& config, PipelineSelector& pipe)
|
||||
|
|
Loading…
Reference in New Issue