Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions bin/resources/shaders/dx11/convert.fx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,22 @@ VS_OUTPUT vs_main(VS_INPUT input)
return output;
}

VS_OUTPUT vs_blit_1to1(uint vID : SV_VertexID)
{
VS_OUTPUT output;

// Hard-coded positions for the Oversized Triangle.
static const float2 positions[3] = {
float2(-1.0f, 1.0f),
float2( 3.0f, 1.0f),
float2(-1.0f, -3.0f)
};

output.p = float4(positions[vID], 0.0f, 1.0f);

return output;
}

PS_OUTPUT ps_copy(PS_INPUT input)
{
PS_OUTPUT output;
Expand All @@ -70,6 +86,11 @@ PS_OUTPUT ps_copy(PS_INPUT input)
return output;
}

float4 ps_blit_1to1(float4 pos : SV_Position) : SV_Target
{
return Texture.Load(int3(pos.xy, 0));
}

float ps_depth_copy(PS_INPUT input) : SV_Depth
{
return sample_c(input.t).r;
Expand Down
131 changes: 105 additions & 26 deletions pcsx2/GS/Renderers/DX11/GSDevice11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,13 +222,23 @@ bool GSDevice11::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
return false;
}

if (!m_shader_cache.GetVertexShaderAndInputLayout(m_dev.get(), m_convert.vs_blit_1to1.put(), nullptr,
il_convert, std::size(il_convert), *convert_hlsl, nullptr, "vs_blit_1to1"))
{
return false;
}

for (size_t i = 0; i < std::size(m_convert.ps); i++)
{
m_convert.ps[i] = m_shader_cache.GetPixelShader(m_dev.get(), *convert_hlsl, nullptr, shaderName(static_cast<ShaderConvert>(i)));
if (!m_convert.ps[i])
return false;
}

m_convert.ps_ps_blit_1to1 = m_shader_cache.GetPixelShader(m_dev.get(), *convert_hlsl, nullptr, "ps_blit_1to1");
if (!m_convert.ps_ps_blit_1to1)
return false;

shader = ReadShaderSource("shaders/dx11/present.fx");
if (!shader.has_value())
return false;
Expand Down Expand Up @@ -1370,7 +1380,6 @@ void GSDevice11::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTextur
{GSVector4(right, bottom, 0.5f, 1.0f), GSVector2(sRect.z, sRect.w)},
};


IASetVertexBuffer(vertices, sizeof(vertices[0]), std::size(vertices));
IASetInputLayout(m_convert.il.get());
IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
Expand All @@ -1390,6 +1399,48 @@ void GSDevice11::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTextur
DrawPrimitive();
}

void GSDevice11::BlitOnetoOne(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r)
{
g_perfmon.Put(GSPerfMon::TextureCopies, 1);

CommitClear(sTex);

// preemptively bind srv if possible

if (m_state.cached_rt_view != sTex && m_state.cached_dsv != sTex)
PSSetShaderResource(0, sTex);

// ps unbind conflicting srvs

PSUnbindConflictingSRVs(dTex);

// om

OMSetRenderTargets(dTex, nullptr, &r);
OMSetDepthStencilState(m_convert.dss.get(), 0);
OMSetBlendState(nullptr, 0);

// ia

IASetInputLayout(nullptr);
IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

// vs

VSSetShader(m_convert.vs_blit_1to1.get(), nullptr);

// ps

PSSetShaderResource(0, sTex);
PSSetShader(m_convert.ps_ps_blit_1to1.get(), nullptr);
PSUpdateShaderState(true, false);

// draw

g_perfmon.Put(GSPerfMon::DrawCalls, 1);
m_ctx->Draw(3, 0);
}

void GSDevice11::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, PresentShader shader, float shaderTime, bool linear)
{
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
Expand Down Expand Up @@ -2416,6 +2467,21 @@ void GSDevice11::IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY topology)
}
}

D3D11_PRIMITIVE_TOPOLOGY GSDevice11::IAGetPrimitiveTopology(GSHWDrawConfig::Topology topology)
{
switch (topology)
{
case GSHWDrawConfig::Topology::Point:
return D3D11_PRIMITIVE_TOPOLOGY_POINTLIST;
case GSHWDrawConfig::Topology::Line:
return D3D11_PRIMITIVE_TOPOLOGY_LINELIST;
case GSHWDrawConfig::Topology::Triangle:
return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
default:
return D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED;
}
}

void GSDevice11::VSSetShader(ID3D11VertexShader* vs, ID3D11Buffer* vs_cb)
{
if (m_state.vs != vs)
Expand Down Expand Up @@ -2757,15 +2823,6 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
}
}

D3D11_PRIMITIVE_TOPOLOGY topology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED;
switch (config.topology)
{
case GSHWDrawConfig::Topology::Point: topology = D3D11_PRIMITIVE_TOPOLOGY_POINTLIST; break;
case GSHWDrawConfig::Topology::Line: topology = D3D11_PRIMITIVE_TOPOLOGY_LINELIST; break;
case GSHWDrawConfig::Topology::Triangle: topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; break;
}
IASetPrimitiveTopology(topology);

// Depth testing and sampling, bind resource as dsv read only and srv at the same time without the need of a copy.
// TODO: On older feature levels read only depth is not supported, we can fallback to a copy but a better solution
// is to wait for Depth feedback loops, in this case we can use it always, unbind the dsv and do testing in shader
Expand Down Expand Up @@ -2800,22 +2857,21 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
if (config.pal)
PSSetShaderResource(1, config.pal);

SetupVS(config.vs, &config.cb_vs);
SetupPS(config.ps, &config.cb_ps, config.sampler);

if (primid_texture)
{
OMDepthStencilSelector dss = config.depth;
dss.zwe = 0;
const OMBlendSelector blend(GSHWDrawConfig::ColorMaskSelector(1),
GSHWDrawConfig::BlendState(true, CONST_ONE, CONST_ONE, 3 /* MIN */, CONST_ONE, CONST_ZERO, false, 0));
IASetPrimitiveTopology(IAGetPrimitiveTopology(config.topology));
SetupVS(config.vs, &config.cb_vs);
SetupPS(config.ps, &config.cb_ps, config.sampler);
SetupOM(dss, blend, 0);
OMSetRenderTargets(primid_texture, config.ds, &config.scissor, read_only_dsv);
DrawIndexedPrimitive();

config.ps.date = 3;
config.alpha_second_pass.ps.date = 3;
SetupPS(config.ps, nullptr, config.sampler);
PSSetShaderResource(3, primid_texture);
}

Expand All @@ -2842,20 +2898,24 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
{
// Requires a copy of the RT.
// Used as "bind rt" flag when texture barrier is unsupported for tex is fb.
draw_rt_clone = CreateTexture(rtsize.x, rtsize.y, 1, draw_rt->GetFormat(), true);

// Drawarea threshold, if the size exceeds 512 then prefer gpu copy, otherwise shader copy.
constexpr int area_size_x_y = 512 * 512;
const bool multipass = config.blend_multi_pass.enable || config.alpha_second_pass.enable;
if (multipass || (config.drawarea.width() * config.drawarea.height() > area_size_x_y))
draw_rt_clone = CreateTexture(rtsize.x, rtsize.y,1, draw_rt->GetFormat(), true);
else
draw_rt_clone = CreateRenderTarget(rtsize.x, rtsize.y, draw_rt->GetFormat(), false, true);

if (!draw_rt_clone)
Console.Warning("D3D11: Failed to allocate temp texture for RT copy.");
}

OMSetRenderTargets(draw_rt, draw_ds, &config.scissor, read_only_dsv);
SetupOM(config.depth, OMBlendSelector(config.colormask, config.blend), config.blend.constant);

// Clear stencil as close as possible to the RT bind, to avoid framebuffer swaps.
if (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::StencilOne && multidraw_fb_copy)
m_ctx->ClearDepthStencilView(*static_cast<GSTexture11*>(draw_ds), D3D11_CLEAR_STENCIL, 0.0f, 1);

SendHWDraw(config, draw_rt_clone, draw_rt, config.require_one_barrier, config.require_full_barrier, false);
SendHWDraw(config, draw_rt_clone, draw_rt, draw_ds, read_only_dsv, config.require_one_barrier, config.require_full_barrier, false);

if (config.blend_multi_pass.enable)
{
Expand All @@ -2881,7 +2941,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
}

SetupOM(config.alpha_second_pass.depth, OMBlendSelector(config.alpha_second_pass.colormask, config.blend), config.blend.constant);
SendHWDraw(config, draw_rt_clone, draw_rt, config.alpha_second_pass.require_one_barrier, config.alpha_second_pass.require_full_barrier, true);
SendHWDraw(config, draw_rt_clone, draw_rt, draw_ds, read_only_dsv, config.alpha_second_pass.require_one_barrier, config.alpha_second_pass.require_full_barrier, true);
}

if (draw_rt_clone)
Expand All @@ -2907,8 +2967,26 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
}
}

void GSDevice11::SendHWDraw(const GSHWDrawConfig& config, GSTexture* draw_rt_clone, GSTexture* draw_rt, const bool one_barrier, const bool full_barrier, const bool skip_first_barrier)
void GSDevice11::SendHWDraw(GSHWDrawConfig& config, GSTexture* draw_rt_clone, GSTexture* draw_rt, GSTexture* draw_ds, ID3D11DepthStencilView* read_only_dsv,
const bool one_barrier, const bool full_barrier, const bool skip_first_barrier)
{
auto SetupPipeline = [&]() {
IASetPrimitiveTopology(IAGetPrimitiveTopology(config.topology));
SetupVS(config.vs, &config.cb_vs);
SetupPS(config.ps, config.ps.date == 3 ? nullptr : &config.cb_ps, config.sampler);
SetupOM(config.depth, OMBlendSelector(config.colormask, config.blend), config.blend.constant);

PSUnbindConflictingSRVs(draw_rt);
OMSetRenderTargets(draw_rt, draw_ds, &config.scissor, read_only_dsv);

if (config.tex)
PSSetShaderResource(0, config.tex);
if (config.tex && config.tex == draw_rt)
PSSetShaderResource(0, draw_rt_clone);
if (one_barrier || full_barrier)
PSSetShaderResource(2, draw_rt_clone);
};

if (draw_rt_clone)
{
#ifdef PCSX2_DEVBUILD
Expand All @@ -2917,11 +2995,10 @@ void GSDevice11::SendHWDraw(const GSHWDrawConfig& config, GSTexture* draw_rt_clo
#endif

auto CopyAndBind = [&](GSVector4i drawarea) {
CopyRect(draw_rt, draw_rt_clone, drawarea, drawarea.left, drawarea.top);
if (one_barrier || full_barrier)
PSSetShaderResource(2, draw_rt_clone);
if (config.tex && config.tex == config.rt)
PSSetShaderResource(0, draw_rt_clone);
if (draw_rt_clone->GetType() == GSTexture::Type::Texture)
CopyRect(draw_rt, draw_rt_clone, drawarea, drawarea.left, drawarea.top);
else
BlitOnetoOne(draw_rt, draw_rt_clone, drawarea);
};

const GSVector4i rtsize(0, 0, draw_rt->GetWidth(), draw_rt->GetHeight());
Expand All @@ -2941,6 +3018,7 @@ void GSDevice11::SendHWDraw(const GSHWDrawConfig& config, GSTexture* draw_rt_clo
const GSVector4i original_bbox = (*config.drawlist_bbox)[n].rintersect(config.drawarea);
CopyAndBind(ProcessCopyArea(rtsize, original_bbox));

SetupPipeline();
DrawIndexedPrimitive(p, count);
p += count;
}
Expand All @@ -2953,5 +3031,6 @@ void GSDevice11::SendHWDraw(const GSHWDrawConfig& config, GSTexture* draw_rt_clo
CopyAndBind(ProcessCopyArea(rtsize, config.drawarea));
}

SetupPipeline();
DrawIndexedPrimitive();
}
7 changes: 6 additions & 1 deletion pcsx2/GS/Renderers/DX11/GSDevice11.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,9 @@ class GSDevice11 final : public GSDevice
{
wil::com_ptr_nothrow<ID3D11InputLayout> il;
wil::com_ptr_nothrow<ID3D11VertexShader> vs;
wil::com_ptr_nothrow<ID3D11VertexShader> vs_blit_1to1;
wil::com_ptr_nothrow<ID3D11PixelShader> ps[static_cast<int>(ShaderConvert::Count)];
wil::com_ptr_nothrow<ID3D11PixelShader> ps_ps_blit_1to1;
wil::com_ptr_nothrow<ID3D11SamplerState> ln;
wil::com_ptr_nothrow<ID3D11SamplerState> pt;
wil::com_ptr_nothrow<ID3D11DepthStencilState> dss;
Expand Down Expand Up @@ -308,6 +310,7 @@ class GSDevice11 final : public GSDevice
void CommitClear(GSTexture* t);

void CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, u32 destX, u32 destY) override;
void BlitOnetoOne(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r);

void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ID3D11PixelShader* ps, ID3D11Buffer* ps_cb, bool linear);
void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ID3D11PixelShader* ps, ID3D11Buffer* ps_cb, ID3D11BlendState* bs, bool linear);
Expand All @@ -332,6 +335,7 @@ class GSDevice11 final : public GSDevice

void IASetInputLayout(ID3D11InputLayout* layout);
void IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY topology);
D3D11_PRIMITIVE_TOPOLOGY IAGetPrimitiveTopology(GSHWDrawConfig::Topology topology);

void VSSetShader(ID3D11VertexShader* vs, ID3D11Buffer* vs_cb);

Expand All @@ -354,7 +358,8 @@ class GSDevice11 final : public GSDevice
void SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, u8 afix);

void RenderHW(GSHWDrawConfig& config) override;
void SendHWDraw(const GSHWDrawConfig& config, GSTexture* draw_rt_clone, GSTexture* draw_rt, const bool one_barrier, const bool full_barrier, const bool skip_first_barrier);
void SendHWDraw(GSHWDrawConfig& config, GSTexture* draw_rt_clone, GSTexture* draw_rt, GSTexture* draw_ds, ID3D11DepthStencilView* read_only_dsv,
const bool one_barrier, const bool full_barrier, const bool skip_first_barrier);

void ClearSamplerCache() override;

Expand Down
2 changes: 1 addition & 1 deletion pcsx2/ShaderCacheVersion.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@

/// Version number for GS and other shaders. Increment whenever any of the contents of the
/// shaders change, to invalidate the cache.
static constexpr u32 SHADER_CACHE_VERSION = 83;
static constexpr u32 SHADER_CACHE_VERSION = 84;
Loading