mirror of https://github.com/PCSX2/pcsx2.git
GS: Add Direct3D 12 renderer
This commit is contained in:
parent
3c18cdcb1f
commit
1993203d26
|
@ -18,9 +18,8 @@ struct VS_OUTPUT
|
||||||
float4 c : COLOR;
|
float4 c : COLOR;
|
||||||
};
|
};
|
||||||
|
|
||||||
cbuffer cb0
|
cbuffer cb0 : register(b0)
|
||||||
{
|
{
|
||||||
float4 BGColor;
|
|
||||||
int EMODA;
|
int EMODA;
|
||||||
int EMODC;
|
int EMODC;
|
||||||
};
|
};
|
||||||
|
@ -405,4 +404,24 @@ PS_OUTPUT ps_yuv(PS_INPUT input)
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float ps_stencil_image_init_0(PS_INPUT input) : SV_Target
|
||||||
|
{
|
||||||
|
float c;
|
||||||
|
if ((127.5f / 255.0f) < sample_c(input.t).a) // < 0x80 pass (== 0x80 should not pass)
|
||||||
|
c = float(-1);
|
||||||
|
else
|
||||||
|
c = float(0x7FFFFFFF);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ps_stencil_image_init_1(PS_INPUT input) : SV_Target
|
||||||
|
{
|
||||||
|
float c;
|
||||||
|
if (sample_c(input.t).a < (127.5f / 255.0f)) // >= 0x80 pass
|
||||||
|
c = float(-1);
|
||||||
|
else
|
||||||
|
c = float(0x7FFFFFFF);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -61,6 +61,7 @@
|
||||||
#define PS_NO_COLOR1 0
|
#define PS_NO_COLOR1 0
|
||||||
#define PS_NO_ABLEND 0
|
#define PS_NO_ABLEND 0
|
||||||
#define PS_ONLY_ALPHA 0
|
#define PS_ONLY_ALPHA 0
|
||||||
|
#define PS_DATE 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SW_BLEND (PS_BLEND_A || PS_BLEND_B || PS_BLEND_D)
|
#define SW_BLEND (PS_BLEND_A || PS_BLEND_B || PS_BLEND_D)
|
||||||
|
@ -99,16 +100,23 @@ struct PS_INPUT
|
||||||
#else
|
#else
|
||||||
nointerpolation float4 c : COLOR0;
|
nointerpolation float4 c : COLOR0;
|
||||||
#endif
|
#endif
|
||||||
|
#if PS_DATE > 10 || PS_DATE == 3
|
||||||
|
uint primid : SV_PrimitiveID;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PS_OUTPUT
|
struct PS_OUTPUT
|
||||||
{
|
{
|
||||||
#if !PS_NO_COLOR
|
#if !PS_NO_COLOR
|
||||||
|
#if PS_DATE > 10
|
||||||
|
float c : SV_Target;
|
||||||
|
#else
|
||||||
float4 c0 : SV_Target0;
|
float4 c0 : SV_Target0;
|
||||||
#if !PS_NO_COLOR1
|
#if !PS_NO_COLOR1
|
||||||
float4 c1 : SV_Target1;
|
float4 c1 : SV_Target1;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
#if PS_ZCLAMP
|
#if PS_ZCLAMP
|
||||||
float depth : SV_Depth;
|
float depth : SV_Depth;
|
||||||
#endif
|
#endif
|
||||||
|
@ -117,10 +125,15 @@ struct PS_OUTPUT
|
||||||
Texture2D<float4> Texture : register(t0);
|
Texture2D<float4> Texture : register(t0);
|
||||||
Texture2D<float4> Palette : register(t1);
|
Texture2D<float4> Palette : register(t1);
|
||||||
Texture2D<float4> RtTexture : register(t2);
|
Texture2D<float4> RtTexture : register(t2);
|
||||||
|
Texture2D<float> PrimMinTexture : register(t3);
|
||||||
SamplerState TextureSampler : register(s0);
|
SamplerState TextureSampler : register(s0);
|
||||||
SamplerState PaletteSampler : register(s1);
|
SamplerState PaletteSampler : register(s1);
|
||||||
|
|
||||||
|
#ifdef DX12
|
||||||
|
cbuffer cb0 : register(b0)
|
||||||
|
#else
|
||||||
cbuffer cb0
|
cbuffer cb0
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
float2 VertexScale;
|
float2 VertexScale;
|
||||||
float2 VertexOffset;
|
float2 VertexOffset;
|
||||||
|
@ -131,7 +144,11 @@ cbuffer cb0
|
||||||
uint pad_cb0;
|
uint pad_cb0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef DX12
|
||||||
|
cbuffer cb1 : register(b1)
|
||||||
|
#else
|
||||||
cbuffer cb1
|
cbuffer cb1
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
float3 FogColor;
|
float3 FogColor;
|
||||||
float AREF;
|
float AREF;
|
||||||
|
@ -853,6 +870,29 @@ PS_OUTPUT ps_main(PS_INPUT input)
|
||||||
if (C.a < A_one) C.a += A_one;
|
if (C.a < A_one) C.a += A_one;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if PS_DATE == 3
|
||||||
|
// Note gl_PrimitiveID == stencil_ceil will be the primitive that will update
|
||||||
|
// the bad alpha value so we must keep it.
|
||||||
|
int stencil_ceil = int(PrimMinTexture.Load(int3(input.p.xy, 0)));
|
||||||
|
if (int(input.primid) > stencil_ceil)
|
||||||
|
discard;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Get first primitive that will write a failling alpha value
|
||||||
|
#if PS_DATE == 11
|
||||||
|
// DATM == 0
|
||||||
|
// Pixel with alpha equal to 1 will failed (128-255)
|
||||||
|
output.c = (C.a > 127.5f) ? float(input.primid) : float(0x7FFFFFFF);
|
||||||
|
|
||||||
|
#elif PS_DATE == 12
|
||||||
|
|
||||||
|
// DATM == 1
|
||||||
|
// Pixel with alpha equal to 0 will failed (0-127)
|
||||||
|
output.c = (C.a < 127.5f) ? float(input.primid) : float(0x7FFFFFFF);
|
||||||
|
|
||||||
|
#else
|
||||||
|
// Not primid DATE setup
|
||||||
|
|
||||||
ps_blend(C, alpha_blend, input.p.xy);
|
ps_blend(C, alpha_blend, input.p.xy);
|
||||||
|
|
||||||
ps_dither(C.rgb, input.p.xy);
|
ps_dither(C.rgb, input.p.xy);
|
||||||
|
@ -878,6 +918,8 @@ PS_OUTPUT ps_main(PS_INPUT input)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#if PS_ZCLAMP
|
#if PS_ZCLAMP
|
||||||
output.depth = min(input.p.z, MaxDepthPS);
|
output.depth = min(input.p.z, MaxDepthPS);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -240,7 +240,7 @@ void MainWindow::connectVMThreadSignals(EmuThread* thread)
|
||||||
|
|
||||||
static constexpr GSRendererType renderers[] = {
|
static constexpr GSRendererType renderers[] = {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
GSRendererType::DX11,
|
GSRendererType::DX11, GSRendererType::DX12,
|
||||||
#endif
|
#endif
|
||||||
GSRendererType::OGL, GSRendererType::VK, GSRendererType::SW, GSRendererType::Null};
|
GSRendererType::OGL, GSRendererType::VK, GSRendererType::SW, GSRendererType::Null};
|
||||||
for (GSRendererType renderer : renderers)
|
for (GSRendererType renderer : renderers)
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include "Frontend/D3D11HostDisplay.h"
|
#include "Frontend/D3D11HostDisplay.h"
|
||||||
|
#include "Frontend/D3D12HostDisplay.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct RendererInfo
|
struct RendererInfo
|
||||||
|
@ -44,6 +45,8 @@ static constexpr RendererInfo s_renderer_info[] = {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "Direct3D 11"),
|
QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "Direct3D 11"),
|
||||||
GSRendererType::DX11,
|
GSRendererType::DX11,
|
||||||
|
QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "Direct3D 12"),
|
||||||
|
GSRendererType::DX12,
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_OPENGL
|
#ifdef ENABLE_OPENGL
|
||||||
QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "OpenGL"),
|
QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "OpenGL"),
|
||||||
|
@ -355,7 +358,7 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
|
||||||
const bool is_dx11 = false;
|
const bool is_dx11 = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const bool is_hardware = (type == GSRendererType::DX11 || type == GSRendererType::OGL || type == GSRendererType::VK);
|
const bool is_hardware = (type == GSRendererType::DX11 || type == GSRendererType::DX12 || type == GSRendererType::OGL || type == GSRendererType::VK);
|
||||||
const bool is_software = (type == GSRendererType::SW);
|
const bool is_software = (type == GSRendererType::SW);
|
||||||
const int current_tab = m_hardware_renderer_visible ? m_ui.hardwareRendererGroup->currentIndex() : m_ui.softwareRendererGroup->currentIndex();
|
const int current_tab = m_hardware_renderer_visible ? m_ui.hardwareRendererGroup->currentIndex() : m_ui.softwareRendererGroup->currentIndex();
|
||||||
|
|
||||||
|
@ -420,6 +423,9 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
|
||||||
case GSRendererType::DX11:
|
case GSRendererType::DX11:
|
||||||
modes = D3D11HostDisplay::StaticGetAdapterAndModeList();
|
modes = D3D11HostDisplay::StaticGetAdapterAndModeList();
|
||||||
break;
|
break;
|
||||||
|
case GSRendererType::DX12:
|
||||||
|
modes = D3D12HostDisplay::StaticGetAdapterAndModeList();
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_VULKAN
|
#ifdef ENABLE_VULKAN
|
||||||
|
|
|
@ -895,6 +895,8 @@ elseif(WIN32)
|
||||||
GS/Renderers/DX11/GSDevice11.cpp
|
GS/Renderers/DX11/GSDevice11.cpp
|
||||||
GS/Renderers/DX11/GSTexture11.cpp
|
GS/Renderers/DX11/GSTexture11.cpp
|
||||||
GS/Renderers/DX11/GSTextureFX11.cpp
|
GS/Renderers/DX11/GSTextureFX11.cpp
|
||||||
|
GS/Renderers/DX12/GSDevice12.cpp
|
||||||
|
GS/Renderers/DX12/GSTexture12.cpp
|
||||||
GS/Window/GSCaptureDlg.cpp
|
GS/Window/GSCaptureDlg.cpp
|
||||||
GS/Window/GSDialog.cpp
|
GS/Window/GSDialog.cpp
|
||||||
)
|
)
|
||||||
|
@ -902,6 +904,8 @@ elseif(WIN32)
|
||||||
GS/Renderers/DX11/D3D.h
|
GS/Renderers/DX11/D3D.h
|
||||||
GS/Renderers/DX11/GSDevice11.h
|
GS/Renderers/DX11/GSDevice11.h
|
||||||
GS/Renderers/DX11/GSTexture11.h
|
GS/Renderers/DX11/GSTexture11.h
|
||||||
|
GS/Renderers/DX12/GSDevice12.h
|
||||||
|
GS/Renderers/DX12/GSTexture12.h
|
||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
list(APPEND pcsx2SPU2Sources
|
list(APPEND pcsx2SPU2Sources
|
||||||
|
|
|
@ -124,6 +124,7 @@ enum class GSRendererType : s8
|
||||||
SW = 13,
|
SW = 13,
|
||||||
VK = 14,
|
VK = 14,
|
||||||
Metal = 17,
|
Metal = 17,
|
||||||
|
DX12 = 15,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class GSInterlaceMode : u8
|
enum class GSInterlaceMode : u8
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
#include "Renderers/DX11/GSDevice11.h"
|
#include "Renderers/DX11/GSDevice11.h"
|
||||||
|
#include "Renderers/DX12/GSDevice12.h"
|
||||||
#include "GS/Renderers/DX11/D3D.h"
|
#include "GS/Renderers/DX11/D3D.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -190,6 +191,9 @@ static HostDisplay::RenderAPI GetAPIForRenderer(GSRendererType renderer)
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
case GSRendererType::DX11:
|
case GSRendererType::DX11:
|
||||||
return HostDisplay::RenderAPI::D3D11;
|
return HostDisplay::RenderAPI::D3D11;
|
||||||
|
|
||||||
|
case GSRendererType::DX12:
|
||||||
|
return HostDisplay::RenderAPI::D3D12;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
|
@ -215,6 +219,9 @@ static bool DoGSOpen(GSRendererType renderer, u8* basemem)
|
||||||
case HostDisplay::RenderAPI::D3D11:
|
case HostDisplay::RenderAPI::D3D11:
|
||||||
g_gs_device = std::make_unique<GSDevice11>();
|
g_gs_device = std::make_unique<GSDevice11>();
|
||||||
break;
|
break;
|
||||||
|
case HostDisplay::RenderAPI::D3D12:
|
||||||
|
g_gs_device = std::make_unique<GSDevice12>();
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
case HostDisplay::RenderAPI::Metal:
|
case HostDisplay::RenderAPI::Metal:
|
||||||
|
@ -1226,6 +1233,7 @@ void GSApp::Init()
|
||||||
m_gs_renderers.push_back(GSSetting(static_cast<u32>(GSRendererType::Auto), "Automatic", ""));
|
m_gs_renderers.push_back(GSSetting(static_cast<u32>(GSRendererType::Auto), "Automatic", ""));
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
m_gs_renderers.push_back(GSSetting(static_cast<u32>(GSRendererType::DX11), "Direct3D 11", ""));
|
m_gs_renderers.push_back(GSSetting(static_cast<u32>(GSRendererType::DX11), "Direct3D 11", ""));
|
||||||
|
m_gs_renderers.push_back(GSSetting(static_cast<u32>(GSRendererType::DX12), "Direct3D 12", ""));
|
||||||
#endif
|
#endif
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
m_gs_renderers.push_back(GSSetting(static_cast<u32>(GSRendererType::Metal), "Metal", ""));
|
m_gs_renderers.push_back(GSSetting(static_cast<u32>(GSRendererType::Metal), "Metal", ""));
|
||||||
|
|
|
@ -75,7 +75,6 @@ enum ChannelFetch
|
||||||
class MergeConstantBuffer
|
class MergeConstantBuffer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GSVector4 BGColor;
|
|
||||||
u32 EMODA;
|
u32 EMODA;
|
||||||
u32 EMODC;
|
u32 EMODC;
|
||||||
u32 pad[2];
|
u32 pad[2];
|
||||||
|
|
|
@ -705,7 +705,6 @@ void GSDevice11::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
|
||||||
if (feedback_write_2 || feedback_write_1 || sTex[0])
|
if (feedback_write_2 || feedback_write_1 || sTex[0])
|
||||||
{
|
{
|
||||||
MergeConstantBuffer cb;
|
MergeConstantBuffer cb;
|
||||||
cb.BGColor = c;
|
|
||||||
cb.EMODA = EXTBUF.EMODA;
|
cb.EMODA = EXTBUF.EMODA;
|
||||||
cb.EMODC = EXTBUF.EMODC;
|
cb.EMODC = EXTBUF.EMODC;
|
||||||
m_ctx->UpdateSubresource(m_merge.cb.get(), 0, nullptr, &cb, 0, 0);
|
m_ctx->UpdateSubresource(m_merge.cb.get(), 0, nullptr, &cb, 0, 0);
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,416 @@
|
||||||
|
/* PCSX2 - PS2 Emulator for PCs
|
||||||
|
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||||
|
*
|
||||||
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||||
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "GSTexture12.h"
|
||||||
|
#include "GS/GSVector.h"
|
||||||
|
#include "GS/Renderers/Common/GSDevice.h"
|
||||||
|
#include "common/D3D12/ShaderCache.h"
|
||||||
|
#include "common/D3D12/StreamBuffer.h"
|
||||||
|
#include "common/HashCombine.h"
|
||||||
|
#include <array>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace D3D12MA
|
||||||
|
{
|
||||||
|
class Allocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
class GSDevice12 final : public GSDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template <typename T>
|
||||||
|
using ComPtr = wil::com_ptr_nothrow<T>;
|
||||||
|
|
||||||
|
struct alignas(8) PipelineSelector
|
||||||
|
{
|
||||||
|
GSHWDrawConfig::PSSelector ps;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
u32 topology : 2;
|
||||||
|
u32 rt : 1;
|
||||||
|
u32 ds : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
u32 key;
|
||||||
|
};
|
||||||
|
|
||||||
|
GSHWDrawConfig::VSSelector vs;
|
||||||
|
GSHWDrawConfig::GSSelector gs;
|
||||||
|
GSHWDrawConfig::DepthStencilSelector dss;
|
||||||
|
GSHWDrawConfig::ColorMaskSelector cms;
|
||||||
|
GSHWDrawConfig::BlendState bs;
|
||||||
|
|
||||||
|
__fi bool operator==(const PipelineSelector& p) const { return (memcmp(this, &p, sizeof(p)) == 0); }
|
||||||
|
__fi bool operator!=(const PipelineSelector& p) const { return (memcmp(this, &p, sizeof(p)) != 0); }
|
||||||
|
|
||||||
|
__fi PipelineSelector() { memset(this, 0, sizeof(*this)); }
|
||||||
|
};
|
||||||
|
static_assert(sizeof(PipelineSelector) == 24, "Pipeline selector is 24 bytes");
|
||||||
|
|
||||||
|
struct PipelineSelectorHash
|
||||||
|
{
|
||||||
|
std::size_t operator()(const PipelineSelector& e) const noexcept
|
||||||
|
{
|
||||||
|
std::size_t hash = 0;
|
||||||
|
HashCombine(hash, e.vs.key, e.gs.key, e.ps.key_hi, e.ps.key_lo, e.dss.key, e.cms.key, e.bs.key, e.key);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ShaderMacro
|
||||||
|
{
|
||||||
|
struct mcstr
|
||||||
|
{
|
||||||
|
const char *name, *def;
|
||||||
|
mcstr(const char* n, const char* d)
|
||||||
|
: name(n)
|
||||||
|
, def(d)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mstring
|
||||||
|
{
|
||||||
|
std::string name, def;
|
||||||
|
mstring(const char* n, std::string d)
|
||||||
|
: name(n)
|
||||||
|
, def(d)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<mstring> mlist;
|
||||||
|
std::vector<mcstr> mout;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ShaderMacro(D3D_FEATURE_LEVEL fl);
|
||||||
|
void AddMacro(const char* n, int d);
|
||||||
|
D3D_SHADER_MACRO* GetPtr(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
enum : u32
|
||||||
|
{
|
||||||
|
NUM_TFX_CONSTANT_BUFFERS = 2,
|
||||||
|
NUM_TFX_TEXTURES = 2,
|
||||||
|
NUM_TFX_RT_TEXTURES = 2,
|
||||||
|
NUM_TOTAL_TFX_TEXTURES = NUM_TFX_TEXTURES + NUM_TFX_RT_TEXTURES,
|
||||||
|
NUM_TFX_SAMPLERS = 2,
|
||||||
|
NUM_UTILITY_TEXTURES = 1,
|
||||||
|
NUM_UTILITY_SAMPLERS = 1,
|
||||||
|
CONVERT_PUSH_CONSTANTS_SIZE = 32,
|
||||||
|
|
||||||
|
VERTEX_BUFFER_SIZE = 32 * 1024 * 1024,
|
||||||
|
INDEX_BUFFER_SIZE = 16 * 1024 * 1024,
|
||||||
|
VERTEX_UNIFORM_BUFFER_SIZE = 8 * 1024 * 1024,
|
||||||
|
FRAGMENT_UNIFORM_BUFFER_SIZE = 8 * 1024 * 1024,
|
||||||
|
|
||||||
|
TFX_ROOT_SIGNATURE_PARAM_VS_CBV = 0,
|
||||||
|
TFX_ROOT_SIGNATURE_PARAM_PS_CBV = 1,
|
||||||
|
TFX_ROOT_SIGNATURE_PARAM_PS_TEXTURES = 2,
|
||||||
|
TFX_ROOT_SIGNATURE_PARAM_PS_SAMPLERS = 3,
|
||||||
|
TFX_ROOT_SIGNATURE_PARAM_PS_RT_TEXTURES = 4,
|
||||||
|
|
||||||
|
UTILITY_ROOT_SIGNATURE_PARAM_PUSH_CONSTANTS = 0,
|
||||||
|
UTILITY_ROOT_SIGNATURE_PARAM_PS_TEXTURES = 1,
|
||||||
|
UTILITY_ROOT_SIGNATURE_PARAM_PS_SAMPLERS = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr u32 SHADER_VERSION = 1;
|
||||||
|
|
||||||
|
ComPtr<ID3D12RootSignature> m_tfx_root_signature;
|
||||||
|
ComPtr<ID3D12RootSignature> m_utility_root_signature;
|
||||||
|
|
||||||
|
D3D12::StreamBuffer m_vertex_stream_buffer;
|
||||||
|
D3D12::StreamBuffer m_index_stream_buffer;
|
||||||
|
D3D12::StreamBuffer m_vertex_constant_buffer;
|
||||||
|
D3D12::StreamBuffer m_pixel_constant_buffer;
|
||||||
|
|
||||||
|
ComPtr<D3D12MA::Allocation> m_readback_staging_allocation;
|
||||||
|
ComPtr<ID3D12Resource> m_readback_staging_buffer;
|
||||||
|
void* m_readback_staging_buffer_map = nullptr;
|
||||||
|
u32 m_readback_staging_buffer_size = 0;
|
||||||
|
|
||||||
|
D3D12::DescriptorHandle m_point_sampler_cpu;
|
||||||
|
D3D12::DescriptorHandle m_linear_sampler_cpu;
|
||||||
|
|
||||||
|
std::unordered_map<u32, D3D12::DescriptorHandle> m_samplers;
|
||||||
|
|
||||||
|
std::array<ComPtr<ID3D12PipelineState>, static_cast<int>(ShaderConvert::Count)> m_convert{};
|
||||||
|
std::array<ComPtr<ID3D12PipelineState>, static_cast<int>(ShaderConvert::Count)> m_present{};
|
||||||
|
std::array<ComPtr<ID3D12PipelineState>, 16> m_color_copy{};
|
||||||
|
std::array<ComPtr<ID3D12PipelineState>, 2> m_merge{};
|
||||||
|
std::array<ComPtr<ID3D12PipelineState>, 4> m_interlace{};
|
||||||
|
std::array<ComPtr<ID3D12PipelineState>, 2> m_hdr_setup_pipelines{}; // [depth]
|
||||||
|
std::array<ComPtr<ID3D12PipelineState>, 2> m_hdr_finish_pipelines{}; // [depth]
|
||||||
|
std::array<std::array<ComPtr<ID3D12PipelineState>, 2>, 2> m_date_image_setup_pipelines{}; // [depth][datm]
|
||||||
|
ComPtr<ID3D12PipelineState> m_fxaa_pipeline;
|
||||||
|
ComPtr<ID3D12PipelineState> m_shadeboost_pipeline;
|
||||||
|
|
||||||
|
std::unordered_map<u32, ComPtr<ID3DBlob>> m_tfx_vertex_shaders;
|
||||||
|
std::unordered_map<u32, ComPtr<ID3DBlob>> m_tfx_geometry_shaders;
|
||||||
|
std::unordered_map<GSHWDrawConfig::PSSelector, ComPtr<ID3DBlob>, GSHWDrawConfig::PSSelectorHash> m_tfx_pixel_shaders;
|
||||||
|
std::unordered_map<PipelineSelector, ComPtr<ID3D12PipelineState>, PipelineSelectorHash> m_tfx_pipelines;
|
||||||
|
|
||||||
|
GSHWDrawConfig::VSConstantBuffer m_vs_cb_cache;
|
||||||
|
GSHWDrawConfig::PSConstantBuffer m_ps_cb_cache;
|
||||||
|
|
||||||
|
D3D12::ShaderCache m_shader_cache;
|
||||||
|
ComPtr<ID3DBlob> m_convert_vs;
|
||||||
|
std::string m_tfx_source;
|
||||||
|
|
||||||
|
void LookupNativeFormat(GSTexture::Format format, DXGI_FORMAT* d3d_format, DXGI_FORMAT* srv_format, DXGI_FORMAT* rtv_format, DXGI_FORMAT* dsv_format) const;
|
||||||
|
|
||||||
|
GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
|
||||||
|
|
||||||
|
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE,
|
||||||
|
const GSRegEXTBUF& EXTBUF, const GSVector4& c) final;
|
||||||
|
void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset = 0) final;
|
||||||
|
void DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4]) final;
|
||||||
|
void DoFXAA(GSTexture* sTex, GSTexture* dTex) final;
|
||||||
|
|
||||||
|
bool GetSampler(D3D12::DescriptorHandle* cpu_handle, GSHWDrawConfig::SamplerSelector ss);
|
||||||
|
void ClearSamplerCache() final;
|
||||||
|
bool GetTextureGroupDescriptors(D3D12::DescriptorHandle* gpu_handle, const D3D12::DescriptorHandle* cpu_handles, u32 count);
|
||||||
|
|
||||||
|
const ID3DBlob* GetTFXVertexShader(GSHWDrawConfig::VSSelector sel);
|
||||||
|
const ID3DBlob* GetTFXGeometryShader(GSHWDrawConfig::GSSelector sel);
|
||||||
|
const ID3DBlob* GetTFXPixelShader(const GSHWDrawConfig::PSSelector& sel);
|
||||||
|
ComPtr<ID3D12PipelineState> CreateTFXPipeline(const PipelineSelector& p);
|
||||||
|
const ID3D12PipelineState* GetTFXPipeline(const PipelineSelector& p);
|
||||||
|
|
||||||
|
ComPtr<ID3DBlob> GetUtilityVertexShader(const std::string& source, const char* entry_point);
|
||||||
|
ComPtr<ID3DBlob> GetUtilityPixelShader(const std::string& source, const char* entry_point);
|
||||||
|
|
||||||
|
bool CheckFeatures();
|
||||||
|
bool CreateNullTexture();
|
||||||
|
bool CreateBuffers();
|
||||||
|
bool CreateRootSignatures();
|
||||||
|
|
||||||
|
bool CompileConvertPipelines();
|
||||||
|
bool CompileInterlacePipelines();
|
||||||
|
bool CompileMergePipelines();
|
||||||
|
bool CompilePostProcessingPipelines();
|
||||||
|
|
||||||
|
bool CheckStagingBufferSize(u32 required_size);
|
||||||
|
bool MapStagingBuffer(u32 size_to_read);
|
||||||
|
void UnmapStagingBuffer();
|
||||||
|
void DestroyStagingBuffer();
|
||||||
|
|
||||||
|
void DestroyResources();
|
||||||
|
|
||||||
|
public:
|
||||||
|
GSDevice12();
|
||||||
|
~GSDevice12() override;
|
||||||
|
|
||||||
|
__fi static GSDevice12* GetInstance() { return static_cast<GSDevice12*>(g_gs_device.get()); }
|
||||||
|
|
||||||
|
bool Create(HostDisplay* display) override;
|
||||||
|
void Destroy() override;
|
||||||
|
|
||||||
|
void ResetAPIState() override;
|
||||||
|
void RestoreAPIState() override;
|
||||||
|
|
||||||
|
void PushDebugGroup(const char* fmt, ...) override;
|
||||||
|
void PopDebugGroup() override;
|
||||||
|
void InsertDebugMessage(DebugMessageCategory category, const char* fmt, ...) override;
|
||||||
|
|
||||||
|
void DrawPrimitive();
|
||||||
|
void DrawIndexedPrimitive();
|
||||||
|
void DrawIndexedPrimitive(int offset, int count);
|
||||||
|
|
||||||
|
void ClearRenderTarget(GSTexture* t, const GSVector4& c) override;
|
||||||
|
void ClearRenderTarget(GSTexture* t, u32 c) override;
|
||||||
|
void InvalidateRenderTarget(GSTexture* t) override;
|
||||||
|
void ClearDepth(GSTexture* t) override;
|
||||||
|
void ClearStencil(GSTexture* t, u8 c) override;
|
||||||
|
|
||||||
|
bool DownloadTexture(GSTexture* src, const GSVector4i& rect, GSTexture::GSMap& out_map) override;
|
||||||
|
void DownloadTextureComplete() override;
|
||||||
|
|
||||||
|
GSTexture* DrawForReadback(GSTexture* src, const GSVector4& sRect, int w, int h, int format = 0, int ps_shader = 0);
|
||||||
|
bool ReadbackTexture(GSTexture* src, const GSVector4i& rect, u32 level, GSTexture::GSMap* dst);
|
||||||
|
|
||||||
|
void CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r) override;
|
||||||
|
void DoCopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, const GSVector4i& dst_rc);
|
||||||
|
|
||||||
|
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
|
||||||
|
ShaderConvert shader = ShaderConvert::COPY, bool linear = true) override;
|
||||||
|
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, bool red,
|
||||||
|
bool green, bool blue, bool alpha) override;
|
||||||
|
|
||||||
|
void BeginRenderPassForStretchRect(GSTexture12* dTex, const GSVector4i& dtex_rc, const GSVector4i& dst_rc);
|
||||||
|
void DoStretchRect(GSTexture12* sTex, const GSVector4& sRect, GSTexture12* dTex, const GSVector4& dRect,
|
||||||
|
const ID3D12PipelineState* pipeline, bool linear);
|
||||||
|
void DrawStretchRect(const GSVector4& sRect, const GSVector4& dRect, const GSVector2i& ds);
|
||||||
|
|
||||||
|
void SetupDATE(GSTexture* rt, GSTexture* ds, bool datm, const GSVector4i& bbox);
|
||||||
|
GSTexture12* SetupPrimitiveTrackingDATE(GSHWDrawConfig& config, PipelineSelector& pipe);
|
||||||
|
|
||||||
|
void IASetVertexBuffer(const void* vertex, size_t stride, size_t count);
|
||||||
|
bool IAMapVertexBuffer(void** vertex, size_t stride, size_t count);
|
||||||
|
void IAUnmapVertexBuffer();
|
||||||
|
void IASetIndexBuffer(const void* index, size_t count);
|
||||||
|
|
||||||
|
void PSSetShaderResource(int i, GSTexture* sr, bool check_state);
|
||||||
|
void PSSetSampler(u32 index, GSHWDrawConfig::SamplerSelector sel);
|
||||||
|
|
||||||
|
void OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i& scissor);
|
||||||
|
|
||||||
|
void SetVSConstantBuffer(const GSHWDrawConfig::VSConstantBuffer& cb);
|
||||||
|
void SetPSConstantBuffer(const GSHWDrawConfig::PSConstantBuffer& cb);
|
||||||
|
bool BindDrawPipeline(const PipelineSelector& p);
|
||||||
|
|
||||||
|
void RenderHW(GSHWDrawConfig& config) override;
|
||||||
|
void UpdateHWPipelineSelector(GSHWDrawConfig& config);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// Ends any render pass, executes the command buffer, and invalidates cached state.
|
||||||
|
void ExecuteCommandList(bool wait_for_completion);
|
||||||
|
void ExecuteCommandList(bool wait_for_completion, const char* reason, ...);
|
||||||
|
void ExecuteCommandListAndRestartRenderPass(const char* reason);
|
||||||
|
|
||||||
|
/// Set dirty flags on everything to force re-bind at next draw time.
|
||||||
|
void InvalidateCachedState();
|
||||||
|
|
||||||
|
/// Binds all dirty state to the command buffer.
|
||||||
|
bool ApplyUtilityState(bool already_execed = false);
|
||||||
|
bool ApplyTFXState(bool already_execed = false);
|
||||||
|
|
||||||
|
void SetVertexBuffer(D3D12_GPU_VIRTUAL_ADDRESS buffer, size_t size, size_t stride);
|
||||||
|
void SetIndexBuffer(D3D12_GPU_VIRTUAL_ADDRESS buffer, size_t size, DXGI_FORMAT type);
|
||||||
|
void SetPrimitiveTopology(D3D12_PRIMITIVE_TOPOLOGY topology);
|
||||||
|
void SetBlendConstants(u8 color);
|
||||||
|
void SetStencilRef(u8 ref);
|
||||||
|
|
||||||
|
void SetUtilityRootSignature();
|
||||||
|
void SetUtilityTexture(GSTexture* tex, const D3D12::DescriptorHandle& sampler);
|
||||||
|
void SetUtilityPushConstants(const void* data, u32 size);
|
||||||
|
void UnbindTexture(GSTexture12* tex);
|
||||||
|
|
||||||
|
// Assumes that the previous level has been transitioned to PS resource,
|
||||||
|
// and the current level has been transitioned to RT.
|
||||||
|
void RenderTextureMipmap(const D3D12::Texture& texture,
|
||||||
|
u32 dst_level, u32 dst_width, u32 dst_height, u32 src_level, u32 src_width, u32 src_height);
|
||||||
|
|
||||||
|
// Ends a render pass if we're currently in one.
|
||||||
|
// When Bind() is next called, the pass will be restarted.
|
||||||
|
// Calling this function is allowed even if a pass has not begun.
|
||||||
|
bool InRenderPass();
|
||||||
|
void BeginRenderPass(
|
||||||
|
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE color_begin = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS,
|
||||||
|
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE color_end = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
|
||||||
|
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE depth_begin = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS,
|
||||||
|
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE depth_end = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
|
||||||
|
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE stencil_begin = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS,
|
||||||
|
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE stencil_end = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
|
||||||
|
const GSVector4& clear_color = GSVector4::zero(), float clear_depth = 0.0f, u8 clear_stencil = 0);
|
||||||
|
void EndRenderPass();
|
||||||
|
|
||||||
|
void SetViewport(const D3D12_VIEWPORT& viewport);
|
||||||
|
void SetScissor(const GSVector4i& scissor);
|
||||||
|
void SetPipeline(const ID3D12PipelineState* pipeline);
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum DIRTY_FLAG : u32
|
||||||
|
{
|
||||||
|
DIRTY_FLAG_VS_CONSTANT_BUFFER = (1 << 0),
|
||||||
|
DIRTY_FLAG_PS_CONSTANT_BUFFER = (1 << 1),
|
||||||
|
DIRTY_FLAG_TFX_TEXTURES = (1 << 2),
|
||||||
|
DIRTY_FLAG_TFX_SAMPLERS = (1 << 3),
|
||||||
|
DIRTY_FLAG_TFX_RT_TEXTURES = (1 << 4),
|
||||||
|
|
||||||
|
DIRTY_FLAG_VS_CONSTANT_BUFFER_BINDING = (1 << 5),
|
||||||
|
DIRTY_FLAG_PS_CONSTANT_BUFFER_BINDING = (1 << 6),
|
||||||
|
DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE = (1 << 7),
|
||||||
|
DIRTY_FLAG_SAMPLERS_DESCRIPTOR_TABLE = (1 << 8),
|
||||||
|
DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE_2 = (1 << 9),
|
||||||
|
|
||||||
|
DIRTY_FLAG_VERTEX_BUFFER = (1 << 10),
|
||||||
|
DIRTY_FLAG_INDEX_BUFFER = (1 << 11),
|
||||||
|
DIRTY_FLAG_PRIMITIVE_TOPOLOGY = (1 << 12),
|
||||||
|
DIRTY_FLAG_VIEWPORT = (1 << 13),
|
||||||
|
DIRTY_FLAG_SCISSOR = (1 << 14),
|
||||||
|
DIRTY_FLAG_RENDER_TARGET = (1 << 15),
|
||||||
|
DIRTY_FLAG_PIPELINE = (1 << 16),
|
||||||
|
DIRTY_FLAG_BLEND_CONSTANTS = (1 << 17),
|
||||||
|
DIRTY_FLAG_STENCIL_REF = (1 << 18),
|
||||||
|
|
||||||
|
DIRTY_BASE_STATE = DIRTY_FLAG_VS_CONSTANT_BUFFER_BINDING | DIRTY_FLAG_PS_CONSTANT_BUFFER_BINDING |
|
||||||
|
DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE | DIRTY_FLAG_SAMPLERS_DESCRIPTOR_TABLE | DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE_2 |
|
||||||
|
DIRTY_FLAG_VERTEX_BUFFER | DIRTY_FLAG_INDEX_BUFFER | DIRTY_FLAG_PRIMITIVE_TOPOLOGY |
|
||||||
|
DIRTY_FLAG_VIEWPORT | DIRTY_FLAG_SCISSOR | DIRTY_FLAG_RENDER_TARGET |
|
||||||
|
DIRTY_FLAG_PIPELINE | DIRTY_FLAG_BLEND_CONSTANTS | DIRTY_FLAG_STENCIL_REF,
|
||||||
|
|
||||||
|
DIRTY_TFX_STATE = DIRTY_BASE_STATE | DIRTY_FLAG_TFX_TEXTURES | DIRTY_FLAG_TFX_SAMPLERS | DIRTY_FLAG_TFX_RT_TEXTURES,
|
||||||
|
DIRTY_UTILITY_STATE = DIRTY_BASE_STATE,
|
||||||
|
DIRTY_CONSTANT_BUFFER_STATE = DIRTY_FLAG_VS_CONSTANT_BUFFER | DIRTY_FLAG_PS_CONSTANT_BUFFER,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class RootSignature
|
||||||
|
{
|
||||||
|
Undefined,
|
||||||
|
TFX,
|
||||||
|
Utility
|
||||||
|
};
|
||||||
|
|
||||||
|
void InitializeState();
|
||||||
|
void InitializeSamplers();
|
||||||
|
|
||||||
|
void ApplyBaseState(u32 flags, ID3D12GraphicsCommandList* cmdlist);
|
||||||
|
|
||||||
|
// Which bindings/state has to be updated before the next draw.
|
||||||
|
u32 m_dirty_flags = 0;
|
||||||
|
|
||||||
|
// input assembly
|
||||||
|
D3D12_VERTEX_BUFFER_VIEW m_vertex_buffer = {};
|
||||||
|
D3D12_INDEX_BUFFER_VIEW m_index_buffer = {};
|
||||||
|
D3D12_PRIMITIVE_TOPOLOGY m_primitive_topology = {};
|
||||||
|
|
||||||
|
GSTexture12* m_current_render_target = nullptr;
|
||||||
|
GSTexture12* m_current_depth_target = nullptr;
|
||||||
|
|
||||||
|
D3D12_VIEWPORT m_viewport = {0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f};
|
||||||
|
GSVector4i m_scissor = GSVector4i::zero();
|
||||||
|
u8 m_blend_constant_color = 0;
|
||||||
|
u8 m_stencil_ref = 0;
|
||||||
|
bool m_in_render_pass = false;
|
||||||
|
|
||||||
|
std::array<D3D12_GPU_VIRTUAL_ADDRESS, NUM_TFX_CONSTANT_BUFFERS> m_tfx_constant_buffers{};
|
||||||
|
std::array<D3D12::DescriptorHandle, NUM_TOTAL_TFX_TEXTURES> m_tfx_textures{};
|
||||||
|
std::array<D3D12::DescriptorHandle, NUM_TFX_SAMPLERS> m_tfx_samplers{};
|
||||||
|
std::array<u32, NUM_TFX_SAMPLERS> m_tfx_sampler_sel{};
|
||||||
|
D3D12::DescriptorHandle m_tfx_textures_handle_gpu;
|
||||||
|
D3D12::DescriptorHandle m_tfx_samplers_handle_gpu;
|
||||||
|
D3D12::DescriptorHandle m_tfx_rt_textures_handle_gpu;
|
||||||
|
|
||||||
|
D3D12::DescriptorHandle m_utility_texture_cpu;
|
||||||
|
D3D12::DescriptorHandle m_utility_texture_gpu;
|
||||||
|
D3D12::DescriptorHandle m_utility_sampler_cpu;
|
||||||
|
D3D12::DescriptorHandle m_utility_sampler_gpu;
|
||||||
|
|
||||||
|
RootSignature m_current_root_signature = RootSignature::Undefined;
|
||||||
|
const ID3D12PipelineState* m_current_pipeline = nullptr;
|
||||||
|
|
||||||
|
D3D12::Texture m_null_texture;
|
||||||
|
|
||||||
|
// current pipeline selector - we save this in the struct to avoid re-zeroing it every draw
|
||||||
|
PipelineSelector m_pipeline_selector = {};
|
||||||
|
};
|
|
@ -0,0 +1,393 @@
|
||||||
|
/* PCSX2 - PS2 Emulator for PCs
|
||||||
|
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||||
|
*
|
||||||
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||||
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "PrecompiledHeader.h"
|
||||||
|
#include "GSTexture12.h"
|
||||||
|
#include "GSDevice12.h"
|
||||||
|
#include "common/Assertions.h"
|
||||||
|
#include "common/Align.h"
|
||||||
|
#include "common/D3D12/Builders.h"
|
||||||
|
#include "common/D3D12/Context.h"
|
||||||
|
#include "common/D3D12/Util.h"
|
||||||
|
#include "common/StringUtil.h"
|
||||||
|
#include "D3D12MemAlloc.h"
|
||||||
|
#include "GS/GSPerfMon.h"
|
||||||
|
#include "GS/GSGL.h"
|
||||||
|
|
||||||
|
GSTexture12::GSTexture12(Type type, Format format, D3D12::Texture texture)
|
||||||
|
: m_texture(std::move(texture))
|
||||||
|
{
|
||||||
|
m_type = type;
|
||||||
|
m_format = format;
|
||||||
|
m_size.x = m_texture.GetWidth();
|
||||||
|
m_size.y = m_texture.GetHeight();
|
||||||
|
m_mipmap_levels = m_texture.GetLevels();
|
||||||
|
}
|
||||||
|
|
||||||
|
GSTexture12::~GSTexture12()
|
||||||
|
{
|
||||||
|
GSDevice12::GetInstance()->UnbindTexture(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, u32 width, u32 height, u32 levels, Format format,
|
||||||
|
DXGI_FORMAT d3d_format, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format, DXGI_FORMAT dsv_format)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case Type::Texture:
|
||||||
|
{
|
||||||
|
// this is a little annoying. basically, to do mipmap generation, we need to be a render target.
|
||||||
|
const D3D12_RESOURCE_FLAGS flags = (levels > 1) ? D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET : D3D12_RESOURCE_FLAG_NONE;
|
||||||
|
if (levels > 1 && d3d_format != DXGI_FORMAT_R8G8B8A8_UNORM)
|
||||||
|
{
|
||||||
|
Console.Warning("DX12: Refusing to create a %ux%u format %u mipmapped texture", width, height, format);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12::Texture texture;
|
||||||
|
if (!texture.Create(width, height, levels, d3d_format, srv_format,
|
||||||
|
DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, flags))
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12::SetObjectNameFormatted(texture.GetResource(), "%ux%u texture", width, height);
|
||||||
|
return std::make_unique<GSTexture12>(type, format, std::move(texture));
|
||||||
|
}
|
||||||
|
|
||||||
|
case Type::RenderTarget:
|
||||||
|
{
|
||||||
|
pxAssert(levels == 1);
|
||||||
|
|
||||||
|
// RT's tend to be larger, so we'll keep them committed for speed.
|
||||||
|
D3D12::Texture texture;
|
||||||
|
if (!texture.Create(width, height, levels, d3d_format, srv_format, rtv_format,
|
||||||
|
DXGI_FORMAT_UNKNOWN, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, D3D12MA::ALLOCATION_FLAG_COMMITTED))
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12::SetObjectNameFormatted(texture.GetResource(), "%ux%u render target", width, height);
|
||||||
|
return std::make_unique<GSTexture12>(type, format, std::move(texture));
|
||||||
|
}
|
||||||
|
|
||||||
|
case Type::DepthStencil:
|
||||||
|
{
|
||||||
|
pxAssert(levels == 1);
|
||||||
|
|
||||||
|
D3D12::Texture texture;
|
||||||
|
if (!texture.Create(width, height, levels, d3d_format, srv_format,
|
||||||
|
DXGI_FORMAT_UNKNOWN, dsv_format, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL,
|
||||||
|
D3D12MA::ALLOCATION_FLAG_COMMITTED))
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12::SetObjectNameFormatted(texture.GetResource(), "%ux%u depth stencil", width, height);
|
||||||
|
return std::make_unique<GSTexture12>(type, format, std::move(texture));
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* GSTexture12::GetNativeHandle() const { return const_cast<D3D12::Texture*>(&m_texture); }
|
||||||
|
|
||||||
|
ID3D12GraphicsCommandList* GSTexture12::GetCommandBufferForUpdate()
|
||||||
|
{
|
||||||
|
if (m_type != Type::Texture || m_use_fence_counter == g_d3d12_context->GetCurrentFenceValue())
|
||||||
|
{
|
||||||
|
// Console.WriteLn("Texture update within frame, can't use do beforehand");
|
||||||
|
GSDevice12::GetInstance()->EndRenderPass();
|
||||||
|
return g_d3d12_context->GetCommandList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_d3d12_context->GetInitCommandList();
|
||||||
|
}
|
||||||
|
|
||||||
|
ID3D12Resource* GSTexture12::AllocateUploadStagingBuffer(const void* data, u32 pitch, u32 upload_pitch, u32 height) const
|
||||||
|
{
|
||||||
|
const u32 buffer_size = CalcUploadSize(height, upload_pitch);
|
||||||
|
wil::com_ptr_nothrow<ID3D12Resource> resource;
|
||||||
|
wil::com_ptr_nothrow<D3D12MA::Allocation> allocation;
|
||||||
|
|
||||||
|
const D3D12MA::ALLOCATION_DESC allocation_desc = {D3D12MA::ALLOCATION_FLAG_NONE, D3D12_HEAP_TYPE_UPLOAD};
|
||||||
|
const D3D12_RESOURCE_DESC resource_desc = {
|
||||||
|
D3D12_RESOURCE_DIMENSION_BUFFER, 0, buffer_size, 1, 1, 1, DXGI_FORMAT_UNKNOWN, {1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
|
||||||
|
D3D12_RESOURCE_FLAG_NONE};
|
||||||
|
HRESULT hr = g_d3d12_context->GetAllocator()->CreateResource(&allocation_desc, &resource_desc, D3D12_RESOURCE_STATE_COPY_SOURCE,
|
||||||
|
nullptr, allocation.put(), IID_PPV_ARGS(resource.put()));
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
Console.WriteLn("(AllocateUploadStagingBuffer) CreateCommittedResource() failed with %08X", hr);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* map_ptr;
|
||||||
|
hr = resource->Map(0, nullptr, &map_ptr);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
Console.WriteLn("(AllocateUploadStagingBuffer) Map() failed with %08X", hr);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
CopyTextureDataForUpload(map_ptr, data, pitch, upload_pitch, height);
|
||||||
|
|
||||||
|
const D3D12_RANGE write_range = {0, buffer_size};
|
||||||
|
resource->Unmap(0, &write_range);
|
||||||
|
|
||||||
|
// Immediately queue it for freeing after the command buffer finishes, since it's only needed for the copy.
|
||||||
|
// This adds the reference needed to keep the buffer alive.
|
||||||
|
g_d3d12_context->DeferResourceDestruction(allocation.get(), resource.get());
|
||||||
|
return resource.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GSTexture12::CopyTextureDataForUpload(void* dst, const void* src, u32 pitch, u32 upload_pitch, u32 height) const
|
||||||
|
{
|
||||||
|
const u32 block_size = GetCompressedBlockSize();
|
||||||
|
const u32 count = (height + (block_size - 1)) / block_size;
|
||||||
|
StringUtil::StrideMemCpy(dst, upload_pitch, src, pitch, std::min(upload_pitch, pitch), count);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GSTexture12::Update(const GSVector4i& r, const void* data, int pitch, int layer)
|
||||||
|
{
|
||||||
|
if (layer >= m_mipmap_levels)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
g_perfmon.Put(GSPerfMon::TextureUploads, 1);
|
||||||
|
|
||||||
|
const u32 width = r.width();
|
||||||
|
const u32 height = r.height();
|
||||||
|
const u32 upload_pitch = Common::AlignUpPow2<u32>(pitch, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
|
||||||
|
const u32 required_size = CalcUploadSize(height, upload_pitch);
|
||||||
|
|
||||||
|
D3D12_TEXTURE_COPY_LOCATION srcloc;
|
||||||
|
srcloc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
||||||
|
srcloc.PlacedFootprint.Footprint.Width = width;
|
||||||
|
srcloc.PlacedFootprint.Footprint.Height = height;
|
||||||
|
srcloc.PlacedFootprint.Footprint.Depth = 1;
|
||||||
|
srcloc.PlacedFootprint.Footprint.Format = m_texture.GetFormat();
|
||||||
|
srcloc.PlacedFootprint.Footprint.RowPitch = upload_pitch;
|
||||||
|
|
||||||
|
// If the texture is larger than half our streaming buffer size, use a separate buffer.
|
||||||
|
// Otherwise allocation will either fail, or require lots of cmdbuffer submissions.
|
||||||
|
if (required_size > (g_d3d12_context->GetTextureStreamBuffer().GetSize() / 2))
|
||||||
|
{
|
||||||
|
srcloc.pResource = AllocateUploadStagingBuffer(data, pitch, upload_pitch, height);
|
||||||
|
if (!srcloc.pResource)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
srcloc.PlacedFootprint.Offset = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
D3D12::StreamBuffer& sbuffer = g_d3d12_context->GetTextureStreamBuffer();
|
||||||
|
if (!sbuffer.ReserveMemory(required_size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT))
|
||||||
|
{
|
||||||
|
GSDevice12::GetInstance()->ExecuteCommandList(
|
||||||
|
false, "While waiting for %u bytes in texture upload buffer", required_size);
|
||||||
|
if (!sbuffer.ReserveMemory(required_size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT))
|
||||||
|
{
|
||||||
|
Console.Error("Failed to reserve texture upload memory (%u bytes).", required_size);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
srcloc.pResource = sbuffer.GetBuffer();
|
||||||
|
srcloc.PlacedFootprint.Offset = sbuffer.GetCurrentOffset();
|
||||||
|
CopyTextureDataForUpload(sbuffer.GetCurrentHostPointer(), data, pitch, upload_pitch, height);
|
||||||
|
sbuffer.CommitMemory(required_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
ID3D12GraphicsCommandList* cmdlist = GetCommandBufferForUpdate();
|
||||||
|
GL_PUSH("GSTexture12::Update({%d,%d} %dx%d Lvl:%u", r.x, r.y, r.width(), r.height(), layer);
|
||||||
|
|
||||||
|
// first time the texture is used? don't leave it undefined
|
||||||
|
if (m_texture.GetState() == D3D12_RESOURCE_STATE_COMMON)
|
||||||
|
m_texture.TransitionToState(cmdlist, D3D12_RESOURCE_STATE_COPY_DEST);
|
||||||
|
else if (m_texture.GetState() != D3D12_RESOURCE_STATE_COPY_DEST)
|
||||||
|
m_texture.TransitionSubresourceToState(cmdlist, layer, m_texture.GetState(), D3D12_RESOURCE_STATE_COPY_DEST);
|
||||||
|
|
||||||
|
// if we're an rt and have been cleared, and the full rect isn't being uploaded, do the clear
|
||||||
|
if (m_type == Type::RenderTarget)
|
||||||
|
{
|
||||||
|
if (!r.eq(GSVector4i(0, 0, m_size.x, m_size.y)))
|
||||||
|
CommitClear(cmdlist);
|
||||||
|
else
|
||||||
|
m_state = State::Dirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12_TEXTURE_COPY_LOCATION dstloc;
|
||||||
|
dstloc.pResource = m_texture.GetResource();
|
||||||
|
dstloc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||||
|
dstloc.SubresourceIndex = layer;
|
||||||
|
|
||||||
|
const D3D12_BOX srcbox{0u, 0u, 0u, static_cast<UINT>(r.width()), static_cast<UINT>(r.height()), 1u};
|
||||||
|
cmdlist->CopyTextureRegion(&dstloc, r.x, r.y, 0, &srcloc, &srcbox);
|
||||||
|
|
||||||
|
if (m_texture.GetState() != D3D12_RESOURCE_STATE_COPY_DEST)
|
||||||
|
m_texture.TransitionSubresourceToState(cmdlist, layer, D3D12_RESOURCE_STATE_COPY_DEST, m_texture.GetState());
|
||||||
|
|
||||||
|
if (m_type == Type::Texture)
|
||||||
|
m_needs_mipmaps_generated |= (layer == 0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GSTexture12::Map(GSMap& m, const GSVector4i* r, int layer)
|
||||||
|
{
|
||||||
|
if (layer >= m_mipmap_levels || IsCompressedFormat())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// map for writing
|
||||||
|
m_map_area = r ? *r : GSVector4i(0, 0, m_texture.GetWidth(), m_texture.GetHeight());
|
||||||
|
m_map_level = layer;
|
||||||
|
|
||||||
|
m.pitch = Common::AlignUpPow2(m_map_area.width() * D3D12::GetTexelSize(m_texture.GetFormat()), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
|
||||||
|
|
||||||
|
// see note in Update() for the reason why.
|
||||||
|
const u32 required_size = CalcUploadSize(m_map_area.height(), m.pitch);
|
||||||
|
D3D12::StreamBuffer& buffer = g_d3d12_context->GetTextureStreamBuffer();
|
||||||
|
if (required_size >= (buffer.GetSize() / 2))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!buffer.ReserveMemory(required_size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT))
|
||||||
|
{
|
||||||
|
GSDevice12::GetInstance()->ExecuteCommandList(
|
||||||
|
false, "While waiting for %u bytes in texture upload buffer", required_size);
|
||||||
|
if (!buffer.ReserveMemory(required_size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT))
|
||||||
|
pxFailRel("Failed to reserve texture upload memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
m.bits = static_cast<u8*>(buffer.GetCurrentHostPointer());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GSTexture12::Unmap()
|
||||||
|
{
|
||||||
|
pxAssert(m_map_level < m_texture.GetLevels());
|
||||||
|
g_perfmon.Put(GSPerfMon::TextureUploads, 1);
|
||||||
|
|
||||||
|
// TODO: non-tightly-packed formats
|
||||||
|
const u32 width = static_cast<u32>(m_map_area.width());
|
||||||
|
const u32 height = static_cast<u32>(m_map_area.height());
|
||||||
|
const u32 pitch = Common::AlignUpPow2(m_map_area.width() * D3D12::GetTexelSize(m_texture.GetFormat()), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
|
||||||
|
const u32 required_size = CalcUploadSize(height, pitch);
|
||||||
|
D3D12::StreamBuffer& buffer = g_d3d12_context->GetTextureStreamBuffer();
|
||||||
|
const u32 buffer_offset = buffer.GetCurrentOffset();
|
||||||
|
buffer.CommitMemory(required_size);
|
||||||
|
|
||||||
|
ID3D12GraphicsCommandList* cmdlist = GetCommandBufferForUpdate();
|
||||||
|
GL_PUSH("GSTexture12::Update({%d,%d} %dx%d Lvl:%u", m_map_area.x, m_map_area.y, m_map_area.width(),
|
||||||
|
m_map_area.height(), m_map_level);
|
||||||
|
|
||||||
|
// first time the texture is used? don't leave it undefined
|
||||||
|
if (m_texture.GetState() == D3D12_RESOURCE_STATE_COMMON)
|
||||||
|
m_texture.TransitionToState(cmdlist, D3D12_RESOURCE_STATE_COPY_DEST);
|
||||||
|
else if (m_texture.GetState() != D3D12_RESOURCE_STATE_COPY_DEST)
|
||||||
|
m_texture.TransitionSubresourceToState(cmdlist, m_map_level, m_texture.GetState(), D3D12_RESOURCE_STATE_COPY_DEST);
|
||||||
|
|
||||||
|
// if we're an rt and have been cleared, and the full rect isn't being uploaded, do the clear
|
||||||
|
if (m_type == Type::RenderTarget)
|
||||||
|
{
|
||||||
|
if (!m_map_area.eq(GSVector4i(0, 0, m_size.x, m_size.y)))
|
||||||
|
CommitClear(cmdlist);
|
||||||
|
else
|
||||||
|
m_state = State::Dirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12_TEXTURE_COPY_LOCATION srcloc;
|
||||||
|
srcloc.pResource = buffer.GetBuffer();
|
||||||
|
srcloc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
||||||
|
srcloc.PlacedFootprint.Offset = buffer_offset;
|
||||||
|
srcloc.PlacedFootprint.Footprint.Width = width;
|
||||||
|
srcloc.PlacedFootprint.Footprint.Height = height;
|
||||||
|
srcloc.PlacedFootprint.Footprint.Depth = 1;
|
||||||
|
srcloc.PlacedFootprint.Footprint.Format = m_texture.GetFormat();
|
||||||
|
srcloc.PlacedFootprint.Footprint.RowPitch = pitch;
|
||||||
|
|
||||||
|
D3D12_TEXTURE_COPY_LOCATION dstloc;
|
||||||
|
dstloc.pResource = m_texture.GetResource();
|
||||||
|
dstloc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||||
|
dstloc.SubresourceIndex = m_map_level;
|
||||||
|
|
||||||
|
const D3D12_BOX srcbox{0u, 0u, 0u, width, height, 1};
|
||||||
|
cmdlist->CopyTextureRegion(&dstloc, m_map_area.x, m_map_area.y, 0, &srcloc, &srcbox);
|
||||||
|
|
||||||
|
if (m_texture.GetState() != D3D12_RESOURCE_STATE_COPY_DEST)
|
||||||
|
m_texture.TransitionSubresourceToState(cmdlist, m_map_level, D3D12_RESOURCE_STATE_COPY_DEST, m_texture.GetState());
|
||||||
|
|
||||||
|
if (m_type == Type::Texture)
|
||||||
|
m_needs_mipmaps_generated |= (m_map_level == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GSTexture12::GenerateMipmap()
|
||||||
|
{
|
||||||
|
for (int dst_level = 1; dst_level < m_mipmap_levels; dst_level++)
|
||||||
|
{
|
||||||
|
const int src_level = dst_level - 1;
|
||||||
|
const int src_width = std::max<int>(m_size.x >> src_level, 1);
|
||||||
|
const int src_height = std::max<int>(m_size.y >> src_level, 1);
|
||||||
|
const int dst_width = std::max<int>(m_size.x >> dst_level, 1);
|
||||||
|
const int dst_height = std::max<int>(m_size.y >> dst_level, 1);
|
||||||
|
|
||||||
|
GSDevice12::GetInstance()->RenderTextureMipmap(m_texture,
|
||||||
|
dst_level, dst_width, dst_height, src_level, src_width, src_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetUsedThisCommandBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GSTexture12::Swap(GSTexture* tex)
|
||||||
|
{
|
||||||
|
GSTexture::Swap(tex);
|
||||||
|
std::swap(m_texture, static_cast<GSTexture12*>(tex)->m_texture);
|
||||||
|
std::swap(m_use_fence_counter, static_cast<GSTexture12*>(tex)->m_use_fence_counter);
|
||||||
|
std::swap(m_clear_value, static_cast<GSTexture12*>(tex)->m_clear_value);
|
||||||
|
std::swap(m_map_area, static_cast<GSTexture12*>(tex)->m_map_area);
|
||||||
|
std::swap(m_map_level, static_cast<GSTexture12*>(tex)->m_map_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GSTexture12::TransitionToState(D3D12_RESOURCE_STATES state)
|
||||||
|
{
|
||||||
|
m_texture.TransitionToState(g_d3d12_context->GetCommandList(), state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GSTexture12::CommitClear()
|
||||||
|
{
|
||||||
|
if (m_state != GSTexture::State::Cleared)
|
||||||
|
return;
|
||||||
|
|
||||||
|
GSDevice12::GetInstance()->EndRenderPass();
|
||||||
|
|
||||||
|
CommitClear(g_d3d12_context->GetCommandList());
|
||||||
|
}
|
||||||
|
|
||||||
|
void GSTexture12::CommitClear(ID3D12GraphicsCommandList* cmdlist)
|
||||||
|
{
|
||||||
|
if (IsDepthStencil())
|
||||||
|
{
|
||||||
|
m_texture.TransitionToState(cmdlist, D3D12_RESOURCE_STATE_DEPTH_WRITE);
|
||||||
|
cmdlist->ClearDepthStencilView(m_texture.GetRTVOrDSVDescriptor(), D3D12_CLEAR_FLAG_DEPTH, m_clear_value.depth, 0, 0, nullptr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_texture.TransitionToState(cmdlist, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||||
|
cmdlist->ClearRenderTargetView(m_texture.GetRTVOrDSVDescriptor(), m_clear_value.color, 0, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetState(GSTexture::State::Dirty);
|
||||||
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
/* PCSX2 - PS2 Emulator for PCs
|
||||||
|
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||||
|
*
|
||||||
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||||
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "GS.h"
|
||||||
|
#include "GS/Renderers/Common/GSTexture.h"
|
||||||
|
#include "common/D3D12/Context.h"
|
||||||
|
#include "common/D3D12/Texture.h"
|
||||||
|
|
||||||
|
class GSTexture12 final : public GSTexture
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
union alignas(16) ClearValue
|
||||||
|
{
|
||||||
|
float color[4];
|
||||||
|
float depth;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
GSTexture12(Type type, Format format, D3D12::Texture texture);
|
||||||
|
~GSTexture12() override;
|
||||||
|
|
||||||
|
static std::unique_ptr<GSTexture12> Create(Type type, u32 width, u32 height, u32 levels, Format format,
|
||||||
|
DXGI_FORMAT d3d_format, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format, DXGI_FORMAT dsv_format);
|
||||||
|
|
||||||
|
__fi D3D12::Texture& GetTexture() { return m_texture; }
|
||||||
|
__fi const D3D12::DescriptorHandle& GetSRVDescriptor() const { return m_texture.GetSRVDescriptor(); }
|
||||||
|
__fi const D3D12::DescriptorHandle& GetRTVOrDSVHandle() const { return m_texture.GetRTVOrDSVDescriptor(); }
|
||||||
|
__fi D3D12_RESOURCE_STATES GetResourceState() const { return m_texture.GetState(); }
|
||||||
|
__fi DXGI_FORMAT GetNativeFormat() const { return m_texture.GetFormat(); }
|
||||||
|
__fi ID3D12Resource* GetResource() const { return m_texture.GetResource(); }
|
||||||
|
__fi GSVector4 GetClearColor() const { return GSVector4::load<true>(m_clear_value.color); }
|
||||||
|
__fi float GetClearDepth() const { return m_clear_value.depth; }
|
||||||
|
|
||||||
|
void* GetNativeHandle() const override;
|
||||||
|
|
||||||
|
bool Update(const GSVector4i& r, const void* data, int pitch, int layer = 0) override;
|
||||||
|
bool Map(GSMap& m, const GSVector4i* r = NULL, int layer = 0) override;
|
||||||
|
void Unmap() override;
|
||||||
|
void GenerateMipmap() override;
|
||||||
|
void Swap(GSTexture* tex) override;
|
||||||
|
|
||||||
|
void TransitionToState(D3D12_RESOURCE_STATES state);
|
||||||
|
void CommitClear();
|
||||||
|
void CommitClear(ID3D12GraphicsCommandList* cmdlist);
|
||||||
|
|
||||||
|
__fi void SetClearColor(const GSVector4& color)
|
||||||
|
{
|
||||||
|
m_state = State::Cleared;
|
||||||
|
GSVector4::store<true>(m_clear_value.color, color);
|
||||||
|
}
|
||||||
|
__fi void SetClearDepth(float depth)
|
||||||
|
{
|
||||||
|
m_state = State::Cleared;
|
||||||
|
m_clear_value.depth = depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call when the texture is bound to the pipeline, or read from in a copy.
|
||||||
|
__fi void SetUsedThisCommandBuffer()
|
||||||
|
{
|
||||||
|
m_use_fence_counter = g_d3d12_context->GetCurrentFenceValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ID3D12GraphicsCommandList* GetCommandBufferForUpdate();
|
||||||
|
ID3D12Resource* AllocateUploadStagingBuffer(const void* data, u32 pitch, u32 upload_pitch, u32 height) const;
|
||||||
|
void CopyTextureDataForUpload(void* dst, const void* src, u32 pitch, u32 upload_pitch, u32 height) const;
|
||||||
|
|
||||||
|
D3D12::Texture m_texture;
|
||||||
|
|
||||||
|
// Contains the fence counter when the texture was last used.
|
||||||
|
// When this matches the current fence counter, the texture was used this command buffer.
|
||||||
|
u64 m_use_fence_counter = 0;
|
||||||
|
|
||||||
|
ClearValue m_clear_value = {};
|
||||||
|
|
||||||
|
GSVector4i m_map_area = GSVector4i::zero();
|
||||||
|
u32 m_map_level = UINT32_MAX;
|
||||||
|
};
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include "Frontend/D3D11HostDisplay.h"
|
#include "Frontend/D3D11HostDisplay.h"
|
||||||
|
#include "Frontend/D3D12HostDisplay.h"
|
||||||
#endif
|
#endif
|
||||||
#include "GS/Renderers/Metal/GSMetalCPPAccessible.h"
|
#include "GS/Renderers/Metal/GSMetalCPPAccessible.h"
|
||||||
|
|
||||||
|
@ -699,6 +700,9 @@ void Dialog::RendererChange()
|
||||||
case GSRendererType::DX11:
|
case GSRendererType::DX11:
|
||||||
list = D3D11HostDisplay::StaticGetAdapterAndModeList();
|
list = D3D11HostDisplay::StaticGetAdapterAndModeList();
|
||||||
break;
|
break;
|
||||||
|
case GSRendererType::DX12:
|
||||||
|
list = D3D12HostDisplay::StaticGetAdapterAndModeList();
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_VULKAN
|
#ifdef ENABLE_VULKAN
|
||||||
case GSRendererType::VK:
|
case GSRendererType::VK:
|
||||||
|
@ -789,7 +793,7 @@ void Dialog::Update()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// cross-tab dependencies yay
|
// cross-tab dependencies yay
|
||||||
const bool is_hw = renderer == GSRendererType::OGL || renderer == GSRendererType::DX11 || renderer == GSRendererType::VK || renderer == GSRendererType::Metal;
|
const bool is_hw = renderer == GSRendererType::OGL || renderer == GSRendererType::DX11 || renderer == GSRendererType::VK || renderer == GSRendererType::Metal || renderer == GSRendererType::DX12;
|
||||||
const bool is_upscale = m_renderer_panel->m_internal_resolution->GetSelection() != 0;
|
const bool is_upscale = m_renderer_panel->m_internal_resolution->GetSelection() != 0;
|
||||||
m_hacks_panel->m_is_native_res = !is_hw || !is_upscale;
|
m_hacks_panel->m_is_native_res = !is_hw || !is_upscale;
|
||||||
m_hacks_panel->m_is_hardware = is_hw;
|
m_hacks_panel->m_is_hardware = is_hw;
|
||||||
|
|
|
@ -281,6 +281,7 @@ const char* Pcsx2Config::GSOptions::GetRendererName(GSRendererType type)
|
||||||
{
|
{
|
||||||
case GSRendererType::Auto: return "Auto";
|
case GSRendererType::Auto: return "Auto";
|
||||||
case GSRendererType::DX11: return "Direct3D 11";
|
case GSRendererType::DX11: return "Direct3D 11";
|
||||||
|
case GSRendererType::DX12: return "Direct3D 12";
|
||||||
case GSRendererType::Metal: return "Metal";
|
case GSRendererType::Metal: return "Metal";
|
||||||
case GSRendererType::OGL: return "OpenGL";
|
case GSRendererType::OGL: return "OpenGL";
|
||||||
case GSRendererType::VK: return "Vulkan";
|
case GSRendererType::VK: return "Vulkan";
|
||||||
|
@ -652,7 +653,9 @@ void Pcsx2Config::GSOptions::MaskUpscalingHacks()
|
||||||
|
|
||||||
bool Pcsx2Config::GSOptions::UseHardwareRenderer() const
|
bool Pcsx2Config::GSOptions::UseHardwareRenderer() const
|
||||||
{
|
{
|
||||||
return (Renderer == GSRendererType::DX11 || Renderer == GSRendererType::OGL || Renderer == GSRendererType::VK || Renderer == GSRendererType::Metal);
|
return (Renderer == GSRendererType::DX11 || Renderer == GSRendererType::DX12 ||
|
||||||
|
Renderer == GSRendererType::OGL || Renderer == GSRendererType::VK ||
|
||||||
|
Renderer == GSRendererType::Metal);
|
||||||
}
|
}
|
||||||
|
|
||||||
VsyncMode Pcsx2Config::GetEffectiveVsyncMode() const
|
VsyncMode Pcsx2Config::GetEffectiveVsyncMode() const
|
||||||
|
|
|
@ -129,6 +129,7 @@ Dialogs::GSDumpDialog::GSDumpDialog(wxWindow* parent)
|
||||||
#endif
|
#endif
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
rdoverrides.Add(Pcsx2Config::GSOptions::GetRendererName(GSRendererType::DX11));
|
rdoverrides.Add(Pcsx2Config::GSOptions::GetRendererName(GSRendererType::DX11));
|
||||||
|
rdoverrides.Add(Pcsx2Config::GSOptions::GetRendererName(GSRendererType::DX12));
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
rdoverrides.Add(Pcsx2Config::GSOptions::GetRendererName(GSRendererType::Metal));
|
rdoverrides.Add(Pcsx2Config::GSOptions::GetRendererName(GSRendererType::Metal));
|
||||||
#endif
|
#endif
|
||||||
|
@ -846,6 +847,11 @@ void Dialogs::GSDumpDialog::GSThread::ExecuteTaskInThread()
|
||||||
renderer = GSRendererType::Metal;
|
renderer = GSRendererType::Metal;
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
#ifdef _WIN32
|
||||||
|
case 5:
|
||||||
|
renderer = GSRendererType::DX12;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -331,6 +331,8 @@
|
||||||
<ClCompile Include="Gif_Logger.cpp" />
|
<ClCompile Include="Gif_Logger.cpp" />
|
||||||
<ClCompile Include="Gif_Unit.cpp" />
|
<ClCompile Include="Gif_Unit.cpp" />
|
||||||
<ClCompile Include="GS\Renderers\DX11\D3D.cpp" />
|
<ClCompile Include="GS\Renderers\DX11\D3D.cpp" />
|
||||||
|
<ClCompile Include="GS\Renderers\DX12\GSDevice12.cpp" />
|
||||||
|
<ClCompile Include="GS\Renderers\DX12\GSTexture12.cpp" />
|
||||||
<ClCompile Include="GS\Renderers\HW\GSTextureReplacementLoaders.cpp" />
|
<ClCompile Include="GS\Renderers\HW\GSTextureReplacementLoaders.cpp" />
|
||||||
<ClCompile Include="GS\Renderers\HW\GSTextureReplacements.cpp" />
|
<ClCompile Include="GS\Renderers\HW\GSTextureReplacements.cpp" />
|
||||||
<ClCompile Include="GS\Window\GSwxDialog.cpp" />
|
<ClCompile Include="GS\Window\GSwxDialog.cpp" />
|
||||||
|
@ -792,6 +794,8 @@
|
||||||
<ClInclude Include="GameDatabase.h" />
|
<ClInclude Include="GameDatabase.h" />
|
||||||
<ClInclude Include="Gif_Unit.h" />
|
<ClInclude Include="Gif_Unit.h" />
|
||||||
<ClInclude Include="GS\Renderers\DX11\D3D.h" />
|
<ClInclude Include="GS\Renderers\DX11\D3D.h" />
|
||||||
|
<ClInclude Include="GS\Renderers\DX12\GSDevice12.h" />
|
||||||
|
<ClInclude Include="GS\Renderers\DX12\GSTexture12.h" />
|
||||||
<ClInclude Include="GS\Renderers\HW\GSTextureReplacements.h" />
|
<ClInclude Include="GS\Renderers\HW\GSTextureReplacements.h" />
|
||||||
<ClInclude Include="GS\Window\GSwxDialog.h" />
|
<ClInclude Include="GS\Window\GSwxDialog.h" />
|
||||||
<ClInclude Include="GS\Renderers\Vulkan\GSDeviceVK.h" />
|
<ClInclude Include="GS\Renderers\Vulkan\GSDeviceVK.h" />
|
||||||
|
|
|
@ -313,6 +313,9 @@
|
||||||
<Filter Include="System\Ps2\GS\Shaders\Direct3D11">
|
<Filter Include="System\Ps2\GS\Shaders\Direct3D11">
|
||||||
<UniqueIdentifier>{eb697f5b-85f5-424a-a7e4-8d8b73d3426e}</UniqueIdentifier>
|
<UniqueIdentifier>{eb697f5b-85f5-424a-a7e4-8d8b73d3426e}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="System\Ps2\GS\Renderers\Direct3D12">
|
||||||
|
<UniqueIdentifier>{9cb1aa40-043d-47f7-86fd-837e10012e75}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="Utilities\folderdesc.txt">
|
<None Include="Utilities\folderdesc.txt">
|
||||||
|
@ -1769,6 +1772,12 @@
|
||||||
<ClCompile Include="Frontend\D3D12HostDisplay.cpp">
|
<ClCompile Include="Frontend\D3D12HostDisplay.cpp">
|
||||||
<Filter>Host</Filter>
|
<Filter>Host</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="GS\Renderers\DX12\GSTexture12.cpp">
|
||||||
|
<Filter>System\Ps2\GS\Renderers\Direct3D12</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="GS\Renderers\DX12\GSDevice12.cpp">
|
||||||
|
<Filter>System\Ps2\GS\Renderers\Direct3D12</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="Patch.h">
|
<ClInclude Include="Patch.h">
|
||||||
|
@ -2942,6 +2951,12 @@
|
||||||
<ClInclude Include="Frontend\D3D12HostDisplay.h">
|
<ClInclude Include="Frontend\D3D12HostDisplay.h">
|
||||||
<Filter>Host</Filter>
|
<Filter>Host</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="GS\Renderers\DX12\GSDevice12.h">
|
||||||
|
<Filter>System\Ps2\GS\Renderers\Direct3D12</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="GS\Renderers\DX12\GSTexture12.h">
|
||||||
|
<Filter>System\Ps2\GS\Renderers\Direct3D12</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="windows\wxResources.rc">
|
<ResourceCompile Include="windows\wxResources.rc">
|
||||||
|
|
|
@ -202,6 +202,8 @@
|
||||||
<ClCompile Include="Gif_Unit.cpp" />
|
<ClCompile Include="Gif_Unit.cpp" />
|
||||||
<ClCompile Include="GSDumpReplayer.cpp" />
|
<ClCompile Include="GSDumpReplayer.cpp" />
|
||||||
<ClCompile Include="GS\Renderers\DX11\D3D.cpp" />
|
<ClCompile Include="GS\Renderers\DX11\D3D.cpp" />
|
||||||
|
<ClCompile Include="GS\Renderers\DX12\GSDevice12.cpp" />
|
||||||
|
<ClCompile Include="GS\Renderers\DX12\GSTexture12.cpp" />
|
||||||
<ClCompile Include="GS\Renderers\HW\GSTextureReplacementLoaders.cpp" />
|
<ClCompile Include="GS\Renderers\HW\GSTextureReplacementLoaders.cpp" />
|
||||||
<ClCompile Include="GS\Renderers\HW\GSTextureReplacements.cpp" />
|
<ClCompile Include="GS\Renderers\HW\GSTextureReplacements.cpp" />
|
||||||
<ClCompile Include="GS\Window\GSwxDialog.cpp" />
|
<ClCompile Include="GS\Window\GSwxDialog.cpp" />
|
||||||
|
@ -516,6 +518,8 @@
|
||||||
<ClInclude Include="Gif_Unit.h" />
|
<ClInclude Include="Gif_Unit.h" />
|
||||||
<ClInclude Include="GSDumpReplayer.h" />
|
<ClInclude Include="GSDumpReplayer.h" />
|
||||||
<ClInclude Include="GS\Renderers\DX11\D3D.h" />
|
<ClInclude Include="GS\Renderers\DX11\D3D.h" />
|
||||||
|
<ClInclude Include="GS\Renderers\DX12\GSDevice12.h" />
|
||||||
|
<ClInclude Include="GS\Renderers\DX12\GSTexture12.h" />
|
||||||
<ClInclude Include="GS\Renderers\HW\GSTextureReplacements.h" />
|
<ClInclude Include="GS\Renderers\HW\GSTextureReplacements.h" />
|
||||||
<ClInclude Include="GS\Window\GSwxDialog.h" />
|
<ClInclude Include="GS\Window\GSwxDialog.h" />
|
||||||
<ClInclude Include="GS\Renderers\Vulkan\GSDeviceVK.h" />
|
<ClInclude Include="GS\Renderers\Vulkan\GSDeviceVK.h" />
|
||||||
|
|
|
@ -229,6 +229,9 @@
|
||||||
<Filter Include="System\Ps2\GS\Shaders\Direct3D11">
|
<Filter Include="System\Ps2\GS\Shaders\Direct3D11">
|
||||||
<UniqueIdentifier>{eb697f5b-85f5-424a-a7e4-8d8b73d3426e}</UniqueIdentifier>
|
<UniqueIdentifier>{eb697f5b-85f5-424a-a7e4-8d8b73d3426e}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="System\Ps2\GS\Renderers\Direct3D12">
|
||||||
|
<UniqueIdentifier>{3951f622-8975-4d9a-9bc0-65e6646b9416}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="Utilities\folderdesc.txt">
|
<None Include="Utilities\folderdesc.txt">
|
||||||
|
@ -1251,6 +1254,12 @@
|
||||||
<Filter>System\Ps2\EmotionEngine\EE\Dynarec</Filter>
|
<Filter>System\Ps2\EmotionEngine\EE\Dynarec</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="GSDumpReplayer.cpp" />
|
<ClCompile Include="GSDumpReplayer.cpp" />
|
||||||
|
<ClCompile Include="GS\Renderers\DX12\GSTexture12.cpp">
|
||||||
|
<Filter>System\Ps2\GS\Renderers\Direct3D12</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="GS\Renderers\DX12\GSDevice12.cpp">
|
||||||
|
<Filter>System\Ps2\GS\Renderers\Direct3D12</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="Frontend\D3D12HostDisplay.cpp">
|
<ClCompile Include="Frontend\D3D12HostDisplay.cpp">
|
||||||
<Filter>Host</Filter>
|
<Filter>Host</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -2068,6 +2077,12 @@
|
||||||
<Filter>System\Ps2\EmotionEngine\EE\Dynarec</Filter>
|
<Filter>System\Ps2\EmotionEngine\EE\Dynarec</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="GSDumpReplayer.h" />
|
<ClInclude Include="GSDumpReplayer.h" />
|
||||||
|
<ClInclude Include="GS\Renderers\DX12\GSTexture12.h">
|
||||||
|
<Filter>System\Ps2\GS\Renderers\Direct3D12</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="GS\Renderers\DX12\GSDevice12.h">
|
||||||
|
<Filter>System\Ps2\GS\Renderers\Direct3D12</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="Frontend\D3D12HostDisplay.h">
|
<ClInclude Include="Frontend\D3D12HostDisplay.h">
|
||||||
<Filter>Host</Filter>
|
<Filter>Host</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
Loading…
Reference in New Issue