@@ -12,7 +12,7 @@
#include "Core/ConfigManager.h"
#include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DState.h"
#include "VideoBackends/D3D/D3DTexture.h"
#include "VideoBackends/D3D/DXTexture.h"
#include "VideoCommon/VideoConfig.h"

namespace DX11
@@ -42,7 +42,8 @@ IDXGISwapChain1* swapchain = nullptr;
static IDXGIFactory2* s_dxgi_factory;
static ID3D11Debug* s_debug;
static D3D_FEATURE_LEVEL s_featlevel;
static D3DTexture2D* s_backbuf;
static std::unique_ptr<DXTexture> s_swap_chain_texture;
static std::unique_ptr<DXFramebuffer> s_swap_chain_framebuffer;

static std::vector<DXGI_SAMPLE_DESC> s_aa_modes; // supported AA modes of the current adapter

@@ -244,18 +245,40 @@ static bool SupportsBPTCTextures(ID3D11Device* dev)
return (bc7_support & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0;
}

static bool CreateSwapChainTextures()
static bool CreateSwapChainFramebuffer()
{
ID3D11Texture2D* buf;
HRESULT hr = swapchain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&buf);
ID3D11Texture2D* texture;
HRESULT hr = swapchain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&texture);
CHECK(SUCCEEDED(hr), "GetBuffer for swap chain failed with HRESULT %08X", hr);
if (FAILED(hr))
return false;

s_backbuf = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET);
SAFE_RELEASE(buf);
SetDebugObjectName(s_backbuf->GetTex(), "backbuffer texture");
SetDebugObjectName(s_backbuf->GetRTV(), "backbuffer render target view");
D3D11_TEXTURE2D_DESC desc;
texture->GetDesc(&desc);

s_swap_chain_texture = std::make_unique<DXTexture>(
TextureConfig(desc.Width, desc.Height, desc.MipLevels, desc.ArraySize, desc.SampleDesc.Count,
AbstractTextureFormat::RGBA8, AbstractTextureFlag_RenderTarget),
texture, nullptr, nullptr);

ID3D11RenderTargetView* rtv;
CD3D11_RENDER_TARGET_VIEW_DESC rtv_desc(texture, D3D11_RTV_DIMENSION_TEXTURE2DARRAY, desc.Format,
0, 0, desc.ArraySize);
hr = device->CreateRenderTargetView(texture, &rtv_desc, &rtv);
CHECK(SUCCEEDED(hr), "Create render target view for swap chain");
if (FAILED(hr))
{
s_swap_chain_texture.reset();
return false;
}

SetDebugObjectName(texture, "backbuffer texture");
SetDebugObjectName(rtv, "backbuffer render target view");
s_swap_chain_framebuffer = std::make_unique<DXFramebuffer>(
s_swap_chain_texture.get(), nullptr, AbstractTextureFormat::RGBA8,
AbstractTextureFormat::Undefined, desc.Width, desc.Height, desc.ArraySize,
desc.SampleDesc.Count, rtv, nullptr, nullptr);

return true;
}

@@ -300,7 +323,7 @@ static bool CreateSwapChain(HWND hWnd)
return false;
}

if (!CreateSwapChainTextures())
if (!CreateSwapChainFramebuffer())
{
SAFE_RELEASE(swapchain);
return false;
@@ -451,7 +474,8 @@ void Close()

// release all bound resources
context->ClearState();
SAFE_RELEASE(s_backbuf);
s_swap_chain_framebuffer.reset();
s_swap_chain_texture.reset();
SAFE_RELEASE(swapchain);
SAFE_DELETE(stateman);
context->Flush(); // immediately destroy device objects
@@ -527,9 +551,13 @@ const char* ComputeShaderVersionString()
return "cs_4_0";
}

D3DTexture2D* GetBackBuffer()
DXTexture* GetSwapChainTexture()
{
return s_swap_chain_texture.get();
}
DXFramebuffer* GetSwapChainFramebuffer()
{
return s_backbuf;
return s_swap_chain_framebuffer.get();
}
bool BGRATexturesSupported()
{
@@ -568,7 +596,8 @@ u32 GetMaxTextureSize(D3D_FEATURE_LEVEL feature_level)

void Reset(HWND new_wnd)
{
SAFE_RELEASE(s_backbuf);
s_swap_chain_framebuffer.reset();
s_swap_chain_texture.reset();

if (swapchain)
{
@@ -583,10 +612,11 @@ void Reset(HWND new_wnd)

void ResizeSwapChain()
{
SAFE_RELEASE(s_backbuf);
s_swap_chain_framebuffer.reset();
s_swap_chain_texture.reset();
const UINT swap_chain_flags = AllowTearingSupported() ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;
swapchain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_R8G8B8A8_UNORM, swap_chain_flags);
if (!CreateSwapChainTextures())
if (!CreateSwapChainFramebuffer())
{
PanicAlert("Failed to get swap chain textures");
SAFE_RELEASE(swapchain);
@@ -38,7 +38,8 @@ namespace DX11
PanicAlert("%s failed in %s at line %d: " Message, __func__, __FILE__, __LINE__, __VA_ARGS__); \
}

class D3DTexture2D;
class DXTexture;
class DXFramebuffer;

namespace D3D
{
@@ -64,7 +65,8 @@ void Reset(HWND new_wnd);
void ResizeSwapChain();
void Present();

D3DTexture2D* GetBackBuffer();
DXTexture* GetSwapChainTexture();
DXFramebuffer* GetSwapChainFramebuffer();
const char* PixelShaderVersionString();
const char* GeometryShaderVersionString();
const char* VertexShaderVersionString();

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

@@ -12,6 +12,7 @@

#include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DState.h"
#include "VideoBackends/D3D/DXTexture.h"
#include "VideoCommon/VideoConfig.h"

namespace DX11
@@ -28,19 +29,31 @@ void StateManager::Apply()
if (!m_dirtyFlags)
return;

const int textureMaskShift = Common::LeastSignificantSetBit((u32)DirtyFlag_Texture0);
const int samplerMaskShift = Common::LeastSignificantSetBit((u32)DirtyFlag_Sampler0);
// Framebuffer changes must occur before texture changes, otherwise the D3D runtime messes with
// our bindings and sets them to null to prevent hazards.
if (m_dirtyFlags & DirtyFlag_Framebuffer)
{
if (g_ActiveConfig.backend_info.bSupportsBBox)
{
D3D::context->OMSetRenderTargetsAndUnorderedAccessViews(
m_pending.framebuffer->GetNumRTVs(),
m_pending.use_integer_rtv ? m_pending.framebuffer->GetIntegerRTVArray() :
m_pending.framebuffer->GetRTVArray(),
m_pending.framebuffer->GetDSV(), 2, 1, &m_pending.uav, nullptr);
}
else
{
D3D::context->OMSetRenderTargets(m_pending.framebuffer->GetNumRTVs(),
m_pending.use_integer_rtv ?
m_pending.framebuffer->GetIntegerRTVArray() :
m_pending.framebuffer->GetRTVArray(),
m_pending.framebuffer->GetDSV());
}
m_current.framebuffer = m_pending.framebuffer;
m_current.uav = m_pending.uav;
m_current.use_integer_rtv = m_pending.use_integer_rtv;
}

u32 dirtyTextures =
(m_dirtyFlags &
(DirtyFlag_Texture0 | DirtyFlag_Texture1 | DirtyFlag_Texture2 | DirtyFlag_Texture3 |
DirtyFlag_Texture4 | DirtyFlag_Texture5 | DirtyFlag_Texture6 | DirtyFlag_Texture7)) >>
textureMaskShift;
u32 dirtySamplers =
(m_dirtyFlags &
(DirtyFlag_Sampler0 | DirtyFlag_Sampler1 | DirtyFlag_Sampler2 | DirtyFlag_Sampler3 |
DirtyFlag_Sampler4 | DirtyFlag_Sampler5 | DirtyFlag_Sampler6 | DirtyFlag_Sampler7)) >>
samplerMaskShift;
u32 dirtyConstants = m_dirtyFlags & (DirtyFlag_PixelConstants | DirtyFlag_VertexConstants |
DirtyFlag_GeometryConstants);
u32 dirtyShaders =
@@ -103,30 +116,6 @@ void StateManager::Apply()
}
}

while (dirtyTextures)
{
const int index = Common::LeastSignificantSetBit(dirtyTextures);
if (m_current.textures[index] != m_pending.textures[index])
{
D3D::context->PSSetShaderResources(index, 1, &m_pending.textures[index]);
m_current.textures[index] = m_pending.textures[index];
}

dirtyTextures &= ~(1 << index);
}

while (dirtySamplers)
{
const int index = Common::LeastSignificantSetBit(dirtySamplers);
if (m_current.samplers[index] != m_pending.samplers[index])
{
D3D::context->PSSetSamplers(index, 1, &m_pending.samplers[index]);
m_current.samplers[index] = m_pending.samplers[index];
}

dirtySamplers &= ~(1 << index);
}

if (dirtyShaders)
{
if (m_current.pixelShader != m_pending.pixelShader)
@@ -164,9 +153,51 @@ void StateManager::Apply()
m_current.rasterizerState = m_pending.rasterizerState;
}

ApplyTextures();

m_dirtyFlags = 0;
}

void StateManager::ApplyTextures()
{
const int textureMaskShift = Common::LeastSignificantSetBit((u32)DirtyFlag_Texture0);
const int samplerMaskShift = Common::LeastSignificantSetBit((u32)DirtyFlag_Sampler0);

u32 dirtyTextures =
(m_dirtyFlags &
(DirtyFlag_Texture0 | DirtyFlag_Texture1 | DirtyFlag_Texture2 | DirtyFlag_Texture3 |
DirtyFlag_Texture4 | DirtyFlag_Texture5 | DirtyFlag_Texture6 | DirtyFlag_Texture7)) >>
textureMaskShift;
u32 dirtySamplers =
(m_dirtyFlags &
(DirtyFlag_Sampler0 | DirtyFlag_Sampler1 | DirtyFlag_Sampler2 | DirtyFlag_Sampler3 |
DirtyFlag_Sampler4 | DirtyFlag_Sampler5 | DirtyFlag_Sampler6 | DirtyFlag_Sampler7)) >>
samplerMaskShift;
while (dirtyTextures)
{
const int index = Common::LeastSignificantSetBit(dirtyTextures);
if (m_current.textures[index] != m_pending.textures[index])
{
D3D::context->PSSetShaderResources(index, 1, &m_pending.textures[index]);
m_current.textures[index] = m_pending.textures[index];
}

dirtyTextures &= ~(1 << index);
}

while (dirtySamplers)
{
const int index = Common::LeastSignificantSetBit(dirtySamplers);
if (m_current.samplers[index] != m_pending.samplers[index])
{
D3D::context->PSSetSamplers(index, 1, &m_pending.samplers[index]);
m_current.samplers[index] = m_pending.samplers[index];
}

dirtySamplers &= ~(1 << index);
}
}

u32 StateManager::UnsetTexture(ID3D11ShaderResourceView* srv)
{
u32 mask = 0;
@@ -193,6 +224,78 @@ void StateManager::SetTextureByMask(u32 textureSlotMask, ID3D11ShaderResourceVie
}
}

void StateManager::SetComputeUAV(ID3D11UnorderedAccessView* uav)
{
if (m_compute_image == uav)
return;

m_compute_image = uav;
D3D::context->CSSetUnorderedAccessViews(0, 1, &uav, nullptr);
}

void StateManager::SetComputeShader(ID3D11ComputeShader* shader)
{
if (m_compute_shader == shader)
return;

m_compute_shader = shader;
D3D::context->CSSetShader(shader, nullptr, 0);
}

void StateManager::SyncComputeBindings()
{
if (m_compute_constants != m_pending.pixelConstants[0])
{
m_compute_constants = m_pending.pixelConstants[0];
D3D::context->CSSetConstantBuffers(0, 1, &m_compute_constants);
}

for (u32 start = 0; start < static_cast<u32>(m_compute_textures.size());)
{
if (m_compute_textures[start] == m_pending.textures[start])
{
start++;
continue;
}

m_compute_textures[start] = m_pending.textures[start];

u32 end = start + 1;
for (; end < static_cast<u32>(m_compute_textures.size()); end++)
{
if (m_compute_textures[end] == m_pending.textures[end])
break;

m_compute_textures[end] = m_pending.textures[end];
}

D3D::context->CSSetShaderResources(start, end - start, &m_compute_textures[start]);
start = end;
}

for (u32 start = 0; start < static_cast<u32>(m_compute_samplers.size());)
{
if (m_compute_samplers[start] == m_pending.samplers[start])
{
start++;
continue;
}

m_compute_samplers[start] = m_pending.samplers[start];

u32 end = start + 1;
for (; end < static_cast<u32>(m_compute_samplers.size()); end++)
{
if (m_compute_samplers[end] == m_pending.samplers[end])
break;

m_compute_samplers[end] = m_pending.samplers[end];
}

D3D::context->CSSetSamplers(start, end - start, &m_compute_samplers[start]);
start = end;
}
}
} // namespace D3D

StateCache::~StateCache()
@@ -16,6 +16,8 @@

namespace DX11
{
class DXFramebuffer;

class StateCache
{
public:
@@ -112,14 +114,6 @@ class StateManager
m_pending.geometryConstants = buffer;
}

void SetComputeConstants(ID3D11Buffer* buffer)
{
if (m_current.computeConstants != buffer)
m_dirtyFlags |= DirtyFlag_ComputeConstants;

m_pending.computeConstants = buffer;
}

void SetVertexBuffer(ID3D11Buffer* buffer, u32 stride, u32 offset)
{
if (m_current.vertexBuffer != buffer || m_current.vertexBufferStride != stride ||
@@ -187,22 +181,45 @@ class StateManager
m_pending.geometryShader = shader;
}

void SetComputeShader(ID3D11ComputeShader* shader)
void SetFramebuffer(DXFramebuffer* fb)
{
if (m_current.computeShader != shader)
m_dirtyFlags |= DirtyFlag_ComputeShader;
if (m_current.framebuffer != fb)
m_dirtyFlags |= DirtyFlag_Framebuffer;

m_pending.computeShader = shader;
m_pending.framebuffer = fb;
}

void SetOMUAV(ID3D11UnorderedAccessView* uav)
{
if (m_current.uav != uav)
m_dirtyFlags |= DirtyFlag_Framebuffer;

m_pending.uav = uav;
}

void SetIntegerRTV(bool enable)
{
if (m_current.use_integer_rtv != enable)
m_dirtyFlags |= DirtyFlag_Framebuffer;

m_pending.use_integer_rtv = enable;
}

// removes currently set texture from all slots, returns mask of previously bound slots
u32 UnsetTexture(ID3D11ShaderResourceView* srv);
void SetTextureByMask(u32 textureSlotMask, ID3D11ShaderResourceView* srv);
void ApplyTextures();

// call this immediately before any drawing operation or to explicitly apply pending resource
// state changes
void Apply();

// Binds constant buffers/textures/samplers to the compute shader stage.
// We don't track these explicitly because it's not often-used.
void SetComputeUAV(ID3D11UnorderedAccessView* uav);
void SetComputeShader(ID3D11ComputeShader* shader);
void SyncComputeBindings();

private:
enum DirtyFlags
{
@@ -227,20 +244,19 @@ class StateManager
DirtyFlag_PixelConstants = 1 << 16,
DirtyFlag_VertexConstants = 1 << 17,
DirtyFlag_GeometryConstants = 1 << 18,
DirtyFlag_ComputeConstants = 1 << 19,

DirtyFlag_VertexBuffer = 1 << 20,
DirtyFlag_IndexBuffer = 1 << 21,
DirtyFlag_VertexBuffer = 1 << 19,
DirtyFlag_IndexBuffer = 1 << 20,

DirtyFlag_PixelShader = 1 << 22,
DirtyFlag_VertexShader = 1 << 23,
DirtyFlag_GeometryShader = 1 << 24,
DirtyFlag_ComputeShader = 1 << 25,
DirtyFlag_PixelShader = 1 << 21,
DirtyFlag_VertexShader = 1 << 22,
DirtyFlag_GeometryShader = 1 << 23,

DirtyFlag_InputAssembler = 1 << 26,
DirtyFlag_BlendState = 1 << 27,
DirtyFlag_DepthState = 1 << 28,
DirtyFlag_RasterizerState = 1 << 29,
DirtyFlag_InputAssembler = 1 << 24,
DirtyFlag_BlendState = 1 << 25,
DirtyFlag_DepthState = 1 << 26,
DirtyFlag_RasterizerState = 1 << 27,
DirtyFlag_Framebuffer = 1 << 28
};

u32 m_dirtyFlags = ~0u;
@@ -252,7 +268,6 @@ class StateManager
std::array<ID3D11Buffer*, 2> pixelConstants;
ID3D11Buffer* vertexConstants;
ID3D11Buffer* geometryConstants;
ID3D11Buffer* computeConstants;
ID3D11Buffer* vertexBuffer;
ID3D11Buffer* indexBuffer;
u32 vertexBufferStride;
@@ -262,18 +277,27 @@ class StateManager
ID3D11PixelShader* pixelShader;
ID3D11VertexShader* vertexShader;
ID3D11GeometryShader* geometryShader;
ID3D11ComputeShader* computeShader;
ID3D11BlendState* blendState;
ID3D11DepthStencilState* depthState;
ID3D11RasterizerState* rasterizerState;
DXFramebuffer* framebuffer;
ID3D11UnorderedAccessView* uav;
bool use_integer_rtv;
};

Resources m_pending = {};
Resources m_current = {};

// Compute resources are synced with the graphics resources when we need them.
ID3D11Buffer* m_compute_constants = nullptr;
std::array<ID3D11ShaderResourceView*, 8> m_compute_textures{};
std::array<ID3D11SamplerState*, 8> m_compute_samplers{};
ID3D11UnorderedAccessView* m_compute_image = nullptr;
ID3D11ComputeShader* m_compute_shader = nullptr;
};

extern StateManager* stateman;

} // namespace
} // namespace D3D

} // namespace DX11

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

@@ -22,11 +22,11 @@ DXPipeline::DXPipeline(ID3D11InputLayout* input_layout, ID3D11VertexShader* vert
ID3D11GeometryShader* geometry_shader, ID3D11PixelShader* pixel_shader,
ID3D11RasterizerState* rasterizer_state,
ID3D11DepthStencilState* depth_state, ID3D11BlendState* blend_state,
D3D11_PRIMITIVE_TOPOLOGY primitive_topology)
D3D11_PRIMITIVE_TOPOLOGY primitive_topology, bool use_logic_op)
: m_input_layout(input_layout), m_vertex_shader(vertex_shader),
m_geometry_shader(geometry_shader), m_pixel_shader(pixel_shader),
m_rasterizer_state(rasterizer_state), m_depth_state(depth_state), m_blend_state(blend_state),
m_primitive_topology(primitive_topology)
m_primitive_topology(primitive_topology), m_use_logic_op(use_logic_op)
{
if (m_input_layout)
m_input_layout->AddRef();
@@ -84,13 +84,16 @@ std::unique_ptr<DXPipeline> DXPipeline::Create(const AbstractPipelineConfig& con
ASSERT(vertex_shader != nullptr && pixel_shader != nullptr);

ID3D11InputLayout* input_layout =
const_cast<D3DVertexFormat*>(static_cast<const D3DVertexFormat*>(config.vertex_format))
->GetInputLayout(vertex_shader->GetByteCode());
config.vertex_format ?
const_cast<D3DVertexFormat*>(static_cast<const D3DVertexFormat*>(config.vertex_format))
->GetInputLayout(vertex_shader->GetByteCode().data(),
vertex_shader->GetByteCode().size()) :
nullptr;

return std::make_unique<DXPipeline>(input_layout, vertex_shader->GetD3DVertexShader(),
geometry_shader ? geometry_shader->GetD3DGeometryShader() :
nullptr,
pixel_shader->GetD3DPixelShader(), rasterizer_state,
depth_state, blend_state, primitive_topology);
return std::make_unique<DXPipeline>(
input_layout, vertex_shader->GetD3DVertexShader(),
geometry_shader ? geometry_shader->GetD3DGeometryShader() : nullptr,
pixel_shader->GetD3DPixelShader(), rasterizer_state, depth_state, blend_state,
primitive_topology, config.blending_state.logicopenable);
}
} // namespace DX11
@@ -16,7 +16,8 @@ class DXPipeline final : public AbstractPipeline
DXPipeline(ID3D11InputLayout* input_layout, ID3D11VertexShader* vertex_shader,
ID3D11GeometryShader* geometry_shader, ID3D11PixelShader* pixel_shader,
ID3D11RasterizerState* rasterizer_state, ID3D11DepthStencilState* depth_state,
ID3D11BlendState* blend_state, D3D11_PRIMITIVE_TOPOLOGY primitive_topology);
ID3D11BlendState* blend_state, D3D11_PRIMITIVE_TOPOLOGY primitive_topology,
bool use_logic_op);
~DXPipeline() override;

ID3D11InputLayout* GetInputLayout() const { return m_input_layout; }
@@ -28,6 +29,8 @@ class DXPipeline final : public AbstractPipeline
ID3D11BlendState* GetBlendState() const { return m_blend_state; }
D3D11_PRIMITIVE_TOPOLOGY GetPrimitiveTopology() const { return m_primitive_topology; }
bool HasGeometryShader() const { return m_geometry_shader != nullptr; }
bool UseLogicOp() const { return m_use_logic_op; }

static std::unique_ptr<DXPipeline> Create(const AbstractPipelineConfig& config);

private:
@@ -39,5 +42,6 @@ class DXPipeline final : public AbstractPipeline
ID3D11DepthStencilState* m_depth_state;
ID3D11BlendState* m_blend_state;
D3D11_PRIMITIVE_TOPOLOGY m_primitive_topology;
bool m_use_logic_op;
};
} // namespace DX11
@@ -2,43 +2,28 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.

#include <fstream>

#include "Common/Assert.h"
#include "Common/FileUtil.h"
#include "Common/Logging/Log.h"
#include "Common/MsgHandler.h"
#include "Common/StringUtil.h"

#include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DShader.h"
#include "VideoBackends/D3D/DXShader.h"
#include "VideoCommon/VideoConfig.h"

namespace DX11
{
DXShader::DXShader(D3DBlob* bytecode, ID3D11VertexShader* vs)
: AbstractShader(ShaderStage::Vertex), m_bytecode(bytecode), m_shader(vs)
{
}

DXShader::DXShader(D3DBlob* bytecode, ID3D11GeometryShader* gs)
: AbstractShader(ShaderStage::Geometry), m_bytecode(bytecode), m_shader(gs)
{
}

DXShader::DXShader(D3DBlob* bytecode, ID3D11PixelShader* ps)
: AbstractShader(ShaderStage::Pixel), m_bytecode(bytecode), m_shader(ps)
{
}

DXShader::DXShader(D3DBlob* bytecode, ID3D11ComputeShader* cs)
: AbstractShader(ShaderStage::Compute), m_bytecode(bytecode), m_shader(cs)
DXShader::DXShader(ShaderStage stage, BinaryData bytecode, ID3D11DeviceChild* shader)
: AbstractShader(stage), m_bytecode(bytecode), m_shader(shader)
{
}

DXShader::~DXShader()
{
m_shader->Release();
m_bytecode->Release();
}

D3DBlob* DXShader::GetByteCode() const
{
return m_bytecode;
}

ID3D11VertexShader* DXShader::GetD3DVertexShader() const
@@ -67,48 +52,62 @@ ID3D11ComputeShader* DXShader::GetD3DComputeShader() const

bool DXShader::HasBinary() const
{
ASSERT(m_bytecode);
return true;
}

AbstractShader::BinaryData DXShader::GetBinary() const
{
return BinaryData(m_bytecode->Data(), m_bytecode->Data() + m_bytecode->Size());
return m_bytecode;
}

std::unique_ptr<DXShader> DXShader::CreateFromBlob(ShaderStage stage, D3DBlob* bytecode)
std::unique_ptr<DXShader> DXShader::CreateFromBytecode(ShaderStage stage, BinaryData bytecode)
{
switch (stage)
{
case ShaderStage::Vertex:
{
ID3D11VertexShader* vs = D3D::CreateVertexShaderFromByteCode(bytecode);
if (vs)
return std::make_unique<DXShader>(bytecode, vs);
ID3D11VertexShader* vs;
HRESULT hr = D3D::device->CreateVertexShader(bytecode.data(), bytecode.size(), nullptr, &vs);
CHECK(SUCCEEDED(hr), "Create vertex shader");
if (FAILED(hr))
return nullptr;

return std::make_unique<DXShader>(ShaderStage::Vertex, std::move(bytecode), vs);
}
break;

case ShaderStage::Geometry:
{
ID3D11GeometryShader* gs = D3D::CreateGeometryShaderFromByteCode(bytecode);
if (gs)
return std::make_unique<DXShader>(bytecode, gs);
ID3D11GeometryShader* gs;
HRESULT hr = D3D::device->CreateGeometryShader(bytecode.data(), bytecode.size(), nullptr, &gs);
CHECK(SUCCEEDED(hr), "Create geometry shader");
if (FAILED(hr))
return nullptr;

return std::make_unique<DXShader>(ShaderStage::Geometry, std::move(bytecode), gs);
}
break;

case ShaderStage::Pixel:
{
ID3D11PixelShader* ps = D3D::CreatePixelShaderFromByteCode(bytecode);
if (ps)
return std::make_unique<DXShader>(bytecode, ps);
ID3D11PixelShader* ps;
HRESULT hr = D3D::device->CreatePixelShader(bytecode.data(), bytecode.size(), nullptr, &ps);
CHECK(SUCCEEDED(hr), "Create pixel shader");
if (FAILED(hr))
return nullptr;

return std::make_unique<DXShader>(ShaderStage::Pixel, std::move(bytecode), ps);
}
break;

case ShaderStage::Compute:
{
ID3D11ComputeShader* cs = D3D::CreateComputeShaderFromByteCode(bytecode);
if (cs)
return std::make_unique<DXShader>(bytecode, cs);
ID3D11ComputeShader* cs;
HRESULT hr = D3D::device->CreateComputeShader(bytecode.data(), bytecode.size(), nullptr, &cs);
CHECK(SUCCEEDED(hr), "Create compute shader");
if (FAILED(hr))
return nullptr;

return std::make_unique<DXShader>(ShaderStage::Compute, std::move(bytecode), cs);
}
break;

@@ -119,65 +118,85 @@ std::unique_ptr<DXShader> DXShader::CreateFromBlob(ShaderStage stage, D3DBlob* b
return nullptr;
}

std::unique_ptr<DXShader> DXShader::CreateFromSource(ShaderStage stage, const char* source,
size_t length)
static const char* GetCompileTarget(ShaderStage stage)
{
D3DBlob* bytecode;
switch (stage)
{
case ShaderStage::Vertex:
{
if (!D3D::CompileVertexShader(std::string(source, length), &bytecode))
return nullptr;
}
break;

return D3D::VertexShaderVersionString();
case ShaderStage::Geometry:
{
if (!D3D::CompileGeometryShader(std::string(source, length), &bytecode))
return nullptr;
return D3D::GeometryShaderVersionString();
case ShaderStage::Pixel:
return D3D::PixelShaderVersionString();
case ShaderStage::Compute:
return D3D::ComputeShaderVersionString();
default:
return "";
}
break;
}

case ShaderStage::Pixel:
bool DXShader::CompileShader(BinaryData* out_bytecode, ShaderStage stage, const char* source,
size_t length)
{
static constexpr D3D_SHADER_MACRO macros[] = {{"API_D3D", "1"}, {nullptr, nullptr}};
const UINT flags = g_ActiveConfig.bEnableValidationLayer ?
(D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION) :
(D3DCOMPILE_OPTIMIZATION_LEVEL3 | D3DCOMPILE_SKIP_VALIDATION);
const char* target = GetCompileTarget(stage);

ID3DBlob* code = nullptr;
ID3DBlob* errors = nullptr;
HRESULT hr = PD3DCompile(source, length, nullptr, macros, nullptr, "main", target, flags, 0,
&code, &errors);
if (FAILED(hr))
{
if (!D3D::CompilePixelShader(std::string(source, length), &bytecode))
return nullptr;
static int num_failures = 0;
std::string filename = StringFromFormat(
"%sbad_%s_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), target, num_failures++);
std::ofstream file;
File::OpenFStream(file, filename, std::ios_base::out);
file.write(source, length);
file << "\n";
file.write(static_cast<const char*>(errors->GetBufferPointer()), errors->GetBufferSize());
file.close();

PanicAlert("Failed to compile %s:\nDebug info (%s):\n%s", filename.c_str(), target,
static_cast<const char*>(errors->GetBufferPointer()));
errors->Release();
return false;
}
break;

case ShaderStage::Compute:
if (errors && errors->GetBufferSize() > 0)
{
if (!D3D::CompileComputeShader(std::string(source, length), &bytecode))
return nullptr;
WARN_LOG(VIDEO, "%s compilation succeeded with warnings:\n%s", target,
static_cast<const char*>(errors->GetBufferPointer()));
}
SAFE_RELEASE(errors);

default:
return nullptr;
}
out_bytecode->resize(code->GetBufferSize());
std::memcpy(out_bytecode->data(), code->GetBufferPointer(), code->GetBufferSize());
code->Release();
return true;
}

std::unique_ptr<DXShader> shader = CreateFromBlob(stage, bytecode);
if (!shader)
{
bytecode->Release();
std::unique_ptr<DXShader> DXShader::CreateFromSource(ShaderStage stage, const char* source,
size_t length)
{
BinaryData bytecode;
if (!CompileShader(&bytecode, stage, source, length))
return nullptr;
}

return shader;
return CreateFromBytecode(stage, std::move(bytecode));
}

std::unique_ptr<DXShader> DXShader::CreateFromBinary(ShaderStage stage, const void* data,
size_t length)
{
D3DBlob* bytecode = new D3DBlob(static_cast<unsigned int>(length), static_cast<const u8*>(data));
std::unique_ptr<DXShader> shader = CreateFromBlob(stage, bytecode);
if (!shader)
{
bytecode->Release();
if (length == 0)
return nullptr;
}

return shader;
BinaryData bytecode(length);
std::memcpy(bytecode.data(), data, length);
return CreateFromBytecode(stage, std::move(bytecode));
}

} // namespace DX11
@@ -3,28 +3,21 @@
// Refer to the license.txt file included.

#pragma once

#include <cstddef>
#include <d3d11.h>
#include <memory>
#include "Common/CommonTypes.h"

#include "VideoBackends/D3D/D3DBlob.h"
#include "VideoCommon/AbstractShader.h"

namespace DX11
{
class DXShader final : public AbstractShader
{
public:
// Note: vs/gs/ps/cs references are transferred.
DXShader(D3DBlob* bytecode, ID3D11VertexShader* vs);
DXShader(D3DBlob* bytecode, ID3D11GeometryShader* gs);
DXShader(D3DBlob* bytecode, ID3D11PixelShader* ps);
DXShader(D3DBlob* bytecode, ID3D11ComputeShader* cs);
DXShader(ShaderStage stage, BinaryData bytecode, ID3D11DeviceChild* shader);
~DXShader() override;

D3DBlob* GetByteCode() const;
const BinaryData& GetByteCode() const { return m_bytecode; }

ID3D11VertexShader* GetD3DVertexShader() const;
ID3D11GeometryShader* GetD3DGeometryShader() const;
ID3D11PixelShader* GetD3DPixelShader() const;
@@ -33,16 +26,19 @@ class DXShader final : public AbstractShader
bool HasBinary() const override;
BinaryData GetBinary() const override;

// Creates a new shader object. The reference to bytecode is not transfered upon failure.
static std::unique_ptr<DXShader> CreateFromBlob(ShaderStage stage, D3DBlob* bytecode);
// Creates a new shader object.
static std::unique_ptr<DXShader> CreateFromBytecode(ShaderStage stage, BinaryData bytecode);
static bool CompileShader(BinaryData* out_bytecode, ShaderStage stage, const char* source,
size_t length);

static std::unique_ptr<DXShader> CreateFromBinary(ShaderStage stage, const void* data,
size_t length);
static std::unique_ptr<DXShader> CreateFromSource(ShaderStage stage, const char* source,
size_t length);

private:
ID3D11DeviceChild* m_shader;
D3DBlob* m_bytecode;
BinaryData m_bytecode;
};

} // namespace DX11

Large diffs are not rendered by default.

@@ -4,39 +4,42 @@

#pragma once

#include <d3d11.h>
#include <memory>
#include "Common/CommonTypes.h"

#include "VideoCommon/AbstractFramebuffer.h"
#include "VideoCommon/AbstractStagingTexture.h"
#include "VideoCommon/AbstractTexture.h"

class D3DTexture2D;

namespace DX11
{
class DXTexture final : public AbstractTexture
{
public:
explicit DXTexture(const TextureConfig& tex_config);
explicit DXTexture(const TextureConfig& tex_config, ID3D11Texture2D* d3d_texture,
ID3D11ShaderResourceView* d3d_srv, ID3D11UnorderedAccessView* d3d_uav);
~DXTexture();

static std::unique_ptr<DXTexture> Create(const TextureConfig& config);

void CopyRectangleFromTexture(const AbstractTexture* src,
const MathUtil::Rectangle<int>& src_rect, u32 src_layer,
u32 src_level, const MathUtil::Rectangle<int>& dst_rect,
u32 dst_layer, u32 dst_level) override;
void ScaleRectangleFromTexture(const AbstractTexture* source,
const MathUtil::Rectangle<int>& srcrect,
const MathUtil::Rectangle<int>& dstrect) override;
void ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& rect,
u32 layer, u32 level) override;
void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
size_t buffer_size) override;

D3DTexture2D* GetRawTexIdentifier() const;
ID3D11Texture2D* GetD3DTexture() const { return m_d3d_texture; }
ID3D11ShaderResourceView* GetD3DSRV() const { return m_d3d_srv; }
ID3D11UnorderedAccessView* GetD3DUAV() const { return m_d3d_uav; }

private:
D3DTexture2D* m_texture;
ID3D11Texture2D* m_d3d_texture;
ID3D11ShaderResourceView* m_d3d_srv;
ID3D11UnorderedAccessView* m_d3d_uav;
};

class DXStagingTexture final : public AbstractStagingTexture
@@ -68,19 +71,22 @@ class DXStagingTexture final : public AbstractStagingTexture
class DXFramebuffer final : public AbstractFramebuffer
{
public:
DXFramebuffer(AbstractTextureFormat color_format, AbstractTextureFormat depth_format, u32 width,
DXFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
AbstractTextureFormat color_format, AbstractTextureFormat depth_format, u32 width,
u32 height, u32 layers, u32 samples, ID3D11RenderTargetView* rtv,
ID3D11DepthStencilView* dsv);
ID3D11RenderTargetView* integer_rtv, ID3D11DepthStencilView* dsv);
~DXFramebuffer() override;

ID3D11RenderTargetView* const* GetRTVArray() const { return &m_rtv; }
ID3D11RenderTargetView* const* GetIntegerRTVArray() const { return &m_integer_rtv; }
UINT GetNumRTVs() const { return m_rtv ? 1 : 0; }
ID3D11DepthStencilView* GetDSV() const { return m_dsv; }
static std::unique_ptr<DXFramebuffer> Create(const DXTexture* color_attachment,
const DXTexture* depth_attachment);
static std::unique_ptr<DXFramebuffer> Create(DXTexture* color_attachment,
DXTexture* depth_attachment);

protected:
ID3D11RenderTargetView* m_rtv;
ID3D11RenderTargetView* m_integer_rtv;
ID3D11DepthStencilView* m_dsv;
};

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

@@ -5,18 +5,18 @@
#include <array>

#include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DBlob.h"
#include "VideoBackends/D3D/D3DState.h"
#include "VideoBackends/D3D/DXShader.h"
#include "VideoBackends/D3D/Render.h"
#include "VideoBackends/D3D/VertexManager.h"
#include "VideoBackends/D3D/VertexShaderCache.h"
#include "VideoCommon/NativeVertexFormat.h"

namespace DX11
{
std::mutex s_input_layout_lock;

std::unique_ptr<NativeVertexFormat>
VertexManager::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
Renderer::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
{
return std::make_unique<D3DVertexFormat>(vtx_decl);
}
@@ -77,11 +77,11 @@ DXGI_FORMAT VarToD3D(VarType t, int size, bool integer)
return retval;
}

D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& _vtx_decl)
{
this->vtx_decl = _vtx_decl;
D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& vtx_decl)
: NativeVertexFormat(vtx_decl)

const AttributeFormat* format = &_vtx_decl.position;
{
const AttributeFormat* format = &vtx_decl.position;
if (format->enable)
{
m_elems[m_num_elems].SemanticName = "POSITION";
@@ -93,7 +93,7 @@ D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& _vtx_decl)

for (int i = 0; i < 3; i++)
{
format = &_vtx_decl.normals[i];
format = &vtx_decl.normals[i];
if (format->enable)
{
m_elems[m_num_elems].SemanticName = "NORMAL";
@@ -107,7 +107,7 @@ D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& _vtx_decl)

for (int i = 0; i < 2; i++)
{
format = &_vtx_decl.colors[i];
format = &vtx_decl.colors[i];
if (format->enable)
{
m_elems[m_num_elems].SemanticName = "COLOR";
@@ -121,7 +121,7 @@ D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& _vtx_decl)

for (int i = 0; i < 8; i++)
{
format = &_vtx_decl.texcoords[i];
format = &vtx_decl.texcoords[i];
if (format->enable)
{
m_elems[m_num_elems].SemanticName = "TEXCOORD";
@@ -133,7 +133,7 @@ D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& _vtx_decl)
}
}

format = &_vtx_decl.posmtx;
format = &vtx_decl.posmtx;
if (format->enable)
{
m_elems[m_num_elems].SemanticName = "BLENDINDICES";
@@ -150,16 +150,16 @@ D3DVertexFormat::~D3DVertexFormat()
SAFE_RELEASE(layout);
}

ID3D11InputLayout* D3DVertexFormat::GetInputLayout(D3DBlob* vs_bytecode)
ID3D11InputLayout* D3DVertexFormat::GetInputLayout(const void* vs_bytecode, size_t vs_bytecode_size)
{
// CreateInputLayout requires a shader input, but it only looks at the signature of the shader,
// so we don't need to recompute it if the shader changes.
ID3D11InputLayout* layout = m_layout.load();
if (layout)
return layout;

HRESULT hr = DX11::D3D::device->CreateInputLayout(
m_elems.data(), m_num_elems, vs_bytecode->Data(), vs_bytecode->Size(), &layout);
HRESULT hr = D3D::device->CreateInputLayout(m_elems.data(), m_num_elems, vs_bytecode,
vs_bytecode_size, &layout);
if (FAILED(hr))
PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__);
DX11::D3D::SetDebugObjectName(m_layout, "input layout used to emulate the GX pipeline");

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.