Move most backend functionality to VideoCommon

This commit is contained in:
Stenzek
2019-02-15 11:59:50 +10:00
parent 933f3ba008
commit f039149198
182 changed files with 8334 additions and 15917 deletions

View File

@ -5,6 +5,7 @@
#include "VideoBackends/D3D/BoundingBox.h"
#include "Common/CommonTypes.h"
#include "Common/MsgHandler.h"
#include "VideoBackends/D3D/D3DState.h"
#include "VideoCommon/VideoConfig.h"
namespace DX11
@ -54,6 +55,7 @@ void BBox::Init()
hr = D3D::device->CreateUnorderedAccessView(s_bbox_buffer, &UAVdesc, &s_bbox_uav);
CHECK(SUCCEEDED(hr), "Create BoundingBox UAV.");
D3D::SetDebugObjectName(s_bbox_uav, "BoundingBox UAV");
D3D::stateman->SetOMUAV(s_bbox_uav);
}
}
@ -83,4 +85,4 @@ int BBox::Get(int index)
D3D::context->Unmap(s_bbox_staging_buffer, 0);
return data;
}
};
}; // namespace DX11

View File

@ -3,42 +3,22 @@ add_library(videod3d
BoundingBox.h
D3DBase.cpp
D3DBase.h
D3DBlob.cpp
D3DBlob.h
D3DShader.cpp
D3DShader.h
D3DState.cpp
D3DState.h
D3DTexture.cpp
D3DTexture.h
D3DUtil.cpp
D3DUtil.h
DXPipeline.cpp
DXPipeline.h
DXShader.cpp
DXShader.h
DXTexture.cpp
DXTexture.h
FramebufferManager.cpp
FramebufferManager.h
GeometryShaderCache.cpp
GeometryShaderCache.h
main.cpp
NativeVertexFormat.cpp
PerfQuery.cpp
PerfQuery.h
PixelShaderCache.cpp
PixelShaderCache.h
PSTextureEncoder.cpp
PSTextureEncoder.h
Render.cpp
Render.h
TextureCache.cpp
TextureCache.h
VertexManager.cpp
VertexManager.h
VertexShaderCache.cpp
VertexShaderCache.h
VideoBackend.h
)

View File

@ -38,46 +38,26 @@
<ItemGroup>
<ClCompile Include="BoundingBox.cpp" />
<ClCompile Include="D3DBase.cpp" />
<ClCompile Include="D3DBlob.cpp" />
<ClCompile Include="D3DShader.cpp" />
<ClCompile Include="D3DState.cpp" />
<ClCompile Include="D3DTexture.cpp" />
<ClCompile Include="D3DUtil.cpp" />
<ClCompile Include="DXPipeline.cpp" />
<ClCompile Include="DXShader.cpp" />
<ClCompile Include="DXTexture.cpp" />
<ClCompile Include="FramebufferManager.cpp" />
<ClCompile Include="GeometryShaderCache.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="NativeVertexFormat.cpp" />
<ClCompile Include="PerfQuery.cpp" />
<ClCompile Include="PixelShaderCache.cpp" />
<ClCompile Include="PSTextureEncoder.cpp" />
<ClCompile Include="Render.cpp" />
<ClCompile Include="TextureCache.cpp" />
<ClCompile Include="VertexManager.cpp" />
<ClCompile Include="VertexShaderCache.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="BoundingBox.h" />
<ClInclude Include="D3DBase.h" />
<ClInclude Include="D3DBlob.h" />
<ClInclude Include="D3DShader.h" />
<ClInclude Include="D3DState.h" />
<ClInclude Include="D3DTexture.h" />
<ClInclude Include="D3DUtil.h" />
<ClInclude Include="DXPipeline.h" />
<ClInclude Include="DXShader.h" />
<ClInclude Include="DXTexture.h" />
<ClInclude Include="FramebufferManager.h" />
<ClInclude Include="GeometryShaderCache.h" />
<ClInclude Include="PerfQuery.h" />
<ClInclude Include="PixelShaderCache.h" />
<ClInclude Include="PSTextureEncoder.h" />
<ClInclude Include="Render.h" />
<ClInclude Include="TextureCache.h" />
<ClInclude Include="VertexManager.h" />
<ClInclude Include="VertexShaderCache.h" />
<ClInclude Include="VideoBackend.h" />
</ItemGroup>
<ItemGroup>

View File

@ -12,51 +12,21 @@
<ClCompile Include="D3DBase.cpp">
<Filter>D3D</Filter>
</ClCompile>
<ClCompile Include="D3DBlob.cpp">
<Filter>D3D</Filter>
</ClCompile>
<ClCompile Include="D3DShader.cpp">
<Filter>D3D</Filter>
</ClCompile>
<ClCompile Include="D3DTexture.cpp">
<Filter>D3D</Filter>
</ClCompile>
<ClCompile Include="D3DUtil.cpp">
<Filter>D3D</Filter>
</ClCompile>
<ClCompile Include="D3DState.cpp">
<Filter>D3D</Filter>
</ClCompile>
<ClCompile Include="FramebufferManager.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="GeometryShaderCache.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="NativeVertexFormat.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="PerfQuery.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="PixelShaderCache.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="PSTextureEncoder.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="Render.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="TextureCache.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="VertexManager.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="VertexShaderCache.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="main.cpp" />
<ClCompile Include="BoundingBox.cpp">
<Filter>Render</Filter>
@ -75,48 +45,18 @@
<ClInclude Include="D3DBase.h">
<Filter>D3D</Filter>
</ClInclude>
<ClInclude Include="D3DBlob.h">
<Filter>D3D</Filter>
</ClInclude>
<ClInclude Include="D3DShader.h">
<Filter>D3D</Filter>
</ClInclude>
<ClInclude Include="D3DTexture.h">
<Filter>D3D</Filter>
</ClInclude>
<ClInclude Include="D3DUtil.h">
<Filter>D3D</Filter>
</ClInclude>
<ClInclude Include="D3DState.h">
<Filter>D3D</Filter>
</ClInclude>
<ClInclude Include="FramebufferManager.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="GeometryShaderCache.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="PerfQuery.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="PixelShaderCache.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="PSTextureEncoder.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="Render.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="TextureCache.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="VertexManager.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="VertexShaderCache.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="VideoBackend.h" />
<ClInclude Include="BoundingBox.h">
<Filter>Render</Filter>

View File

@ -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_backbuf;
return s_swap_chain_texture.get();
}
DXFramebuffer* GetSwapChainFramebuffer()
{
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);

View File

@ -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();

View File

@ -1,60 +0,0 @@
// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <d3d11.h>
#include "VideoBackends/D3D/D3DBlob.h"
namespace DX11
{
D3DBlob::D3DBlob(unsigned int blob_size, const u8* init_data)
: ref(1), size(blob_size), blob(nullptr)
{
data = new u8[blob_size];
if (init_data)
memcpy(data, init_data, size);
}
D3DBlob::D3DBlob(ID3D10Blob* d3dblob) : ref(1)
{
blob = d3dblob;
data = (u8*)blob->GetBufferPointer();
size = (unsigned int)blob->GetBufferSize();
d3dblob->AddRef();
}
D3DBlob::~D3DBlob()
{
if (blob)
blob->Release();
else
delete[] data;
}
void D3DBlob::AddRef()
{
++ref;
}
unsigned int D3DBlob::Release()
{
if (--ref == 0)
{
delete this;
return 0;
}
return ref;
}
unsigned int D3DBlob::Size() const
{
return size;
}
u8* D3DBlob::Data()
{
return data;
}
} // namespace DX11

View File

@ -1,39 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include "Common/CommonTypes.h"
struct ID3D10Blob;
namespace DX11
{
// use this class instead ID3D10Blob or ID3D11Blob whenever possible
class D3DBlob
{
public:
// memory will be copied into an own buffer
D3DBlob(unsigned int blob_size, const u8* init_data = nullptr);
// d3dblob will be AddRef'd
D3DBlob(ID3D10Blob* d3dblob);
void AddRef();
unsigned int Release();
unsigned int Size() const;
u8* Data();
private:
~D3DBlob();
unsigned int ref;
unsigned int size;
u8* data;
ID3D10Blob* blob;
};
} // namespace

View File

@ -1,304 +0,0 @@
// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <fstream>
#include <string>
#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 "VideoCommon/VideoConfig.h"
namespace DX11
{
namespace D3D
{
// bytecode->shader
ID3D11VertexShader* CreateVertexShaderFromByteCode(const void* bytecode, size_t len)
{
ID3D11VertexShader* v_shader;
HRESULT hr = D3D::device->CreateVertexShader(bytecode, len, nullptr, &v_shader);
if (FAILED(hr))
return nullptr;
return v_shader;
}
// code->bytecode
bool CompileVertexShader(const std::string& code, D3DBlob** blob)
{
ID3D10Blob* shaderBuffer = nullptr;
ID3D10Blob* errorBuffer = nullptr;
#if defined(_DEBUG) || defined(DEBUGFAST)
UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY | D3D10_SHADER_DEBUG;
#else
UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY | D3D10_SHADER_OPTIMIZATION_LEVEL3 |
D3D10_SHADER_SKIP_VALIDATION;
#endif
HRESULT hr = PD3DCompile(code.c_str(), code.length(), nullptr, nullptr, nullptr, "main",
D3D::VertexShaderVersionString(), flags, 0, &shaderBuffer, &errorBuffer);
if (errorBuffer)
{
INFO_LOG(VIDEO, "Vertex shader compiler messages:\n%s",
(const char*)errorBuffer->GetBufferPointer());
}
if (FAILED(hr))
{
static int num_failures = 0;
std::string filename = StringFromFormat("%sbad_vs_%04i.txt",
File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
std::ofstream file;
File::OpenFStream(file, filename, std::ios_base::out);
file << code;
file.close();
PanicAlert("Failed to compile vertex shader: %s\nDebug info (%s):\n%s", filename.c_str(),
D3D::VertexShaderVersionString(), (const char*)errorBuffer->GetBufferPointer());
*blob = nullptr;
errorBuffer->Release();
}
else
{
*blob = new D3DBlob(shaderBuffer);
shaderBuffer->Release();
}
return SUCCEEDED(hr);
}
// bytecode->shader
ID3D11GeometryShader* CreateGeometryShaderFromByteCode(const void* bytecode, size_t len)
{
ID3D11GeometryShader* g_shader;
HRESULT hr = D3D::device->CreateGeometryShader(bytecode, len, nullptr, &g_shader);
if (FAILED(hr))
return nullptr;
return g_shader;
}
// code->bytecode
bool CompileGeometryShader(const std::string& code, D3DBlob** blob,
const D3D_SHADER_MACRO* pDefines)
{
ID3D10Blob* shaderBuffer = nullptr;
ID3D10Blob* errorBuffer = nullptr;
#if defined(_DEBUG) || defined(DEBUGFAST)
UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY | D3D10_SHADER_DEBUG;
#else
UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY | D3D10_SHADER_OPTIMIZATION_LEVEL3 |
D3D10_SHADER_SKIP_VALIDATION;
#endif
HRESULT hr =
PD3DCompile(code.c_str(), code.length(), nullptr, pDefines, nullptr, "main",
D3D::GeometryShaderVersionString(), flags, 0, &shaderBuffer, &errorBuffer);
if (errorBuffer)
{
INFO_LOG(VIDEO, "Geometry shader compiler messages:\n%s",
(const char*)errorBuffer->GetBufferPointer());
}
if (FAILED(hr))
{
static int num_failures = 0;
std::string filename = StringFromFormat("%sbad_gs_%04i.txt",
File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
std::ofstream file;
File::OpenFStream(file, filename, std::ios_base::out);
file << code;
file.close();
PanicAlert("Failed to compile geometry shader: %s\nDebug info (%s):\n%s", filename.c_str(),
D3D::GeometryShaderVersionString(), (const char*)errorBuffer->GetBufferPointer());
*blob = nullptr;
errorBuffer->Release();
}
else
{
*blob = new D3DBlob(shaderBuffer);
shaderBuffer->Release();
}
return SUCCEEDED(hr);
}
// bytecode->shader
ID3D11PixelShader* CreatePixelShaderFromByteCode(const void* bytecode, size_t len)
{
ID3D11PixelShader* p_shader;
HRESULT hr = D3D::device->CreatePixelShader(bytecode, len, nullptr, &p_shader);
if (FAILED(hr))
{
PanicAlert("CreatePixelShaderFromByteCode failed at %s %d\n", __FILE__, __LINE__);
p_shader = nullptr;
}
return p_shader;
}
// code->bytecode
bool CompilePixelShader(const std::string& code, D3DBlob** blob, const D3D_SHADER_MACRO* pDefines)
{
ID3D10Blob* shaderBuffer = nullptr;
ID3D10Blob* errorBuffer = nullptr;
#if defined(_DEBUG) || defined(DEBUGFAST)
UINT flags = D3D10_SHADER_DEBUG;
#else
UINT flags = D3D10_SHADER_OPTIMIZATION_LEVEL3;
#endif
HRESULT hr = PD3DCompile(code.c_str(), code.length(), nullptr, pDefines, nullptr, "main",
D3D::PixelShaderVersionString(), flags, 0, &shaderBuffer, &errorBuffer);
if (errorBuffer)
{
INFO_LOG(VIDEO, "Pixel shader compiler messages:\n%s",
(const char*)errorBuffer->GetBufferPointer());
}
if (FAILED(hr))
{
static int num_failures = 0;
std::string filename = StringFromFormat("%sbad_ps_%04i.txt",
File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
std::ofstream file;
File::OpenFStream(file, filename, std::ios_base::out);
file << code;
file.close();
PanicAlert("Failed to compile pixel shader: %s\nDebug info (%s):\n%s", filename.c_str(),
D3D::PixelShaderVersionString(), (const char*)errorBuffer->GetBufferPointer());
*blob = nullptr;
errorBuffer->Release();
}
else
{
*blob = new D3DBlob(shaderBuffer);
shaderBuffer->Release();
}
return SUCCEEDED(hr);
}
// bytecode->shader
ID3D11ComputeShader* CreateComputeShaderFromByteCode(const void* bytecode, size_t len)
{
ID3D11ComputeShader* shader;
HRESULT hr = D3D::device->CreateComputeShader(bytecode, len, nullptr, &shader);
if (FAILED(hr))
{
PanicAlert("CreateComputeShaderFromByteCode failed at %s %d\n", __FILE__, __LINE__);
return nullptr;
}
return shader;
}
// code->bytecode
bool CompileComputeShader(const std::string& code, D3DBlob** blob, const D3D_SHADER_MACRO* pDefines)
{
ID3D10Blob* shaderBuffer = nullptr;
ID3D10Blob* errorBuffer = nullptr;
#if defined(_DEBUG) || defined(DEBUGFAST)
UINT flags = D3D10_SHADER_DEBUG;
#else
UINT flags = D3D10_SHADER_OPTIMIZATION_LEVEL3;
#endif
HRESULT hr =
PD3DCompile(code.c_str(), code.length(), nullptr, pDefines, nullptr, "main",
D3D::ComputeShaderVersionString(), flags, 0, &shaderBuffer, &errorBuffer);
if (errorBuffer)
{
INFO_LOG(VIDEO, "Compute shader compiler messages:\n%s",
(const char*)errorBuffer->GetBufferPointer());
}
if (FAILED(hr))
{
static int num_failures = 0;
std::string filename = StringFromFormat("%sbad_cs_%04i.txt",
File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
std::ofstream file;
File::OpenFStream(file, filename, std::ios_base::out);
file << code;
file.close();
PanicAlert("Failed to compile compute shader: %s\nDebug info (%s):\n%s", filename.c_str(),
D3D::ComputeShaderVersionString(),
reinterpret_cast<const char*>(errorBuffer->GetBufferPointer()));
*blob = nullptr;
errorBuffer->Release();
}
else
{
*blob = new D3DBlob(shaderBuffer);
shaderBuffer->Release();
}
return SUCCEEDED(hr);
}
ID3D11VertexShader* CompileAndCreateVertexShader(const std::string& code)
{
D3DBlob* blob = nullptr;
if (CompileVertexShader(code, &blob))
{
ID3D11VertexShader* v_shader = CreateVertexShaderFromByteCode(blob);
blob->Release();
return v_shader;
}
return nullptr;
}
ID3D11GeometryShader* CompileAndCreateGeometryShader(const std::string& code,
const D3D_SHADER_MACRO* pDefines)
{
D3DBlob* blob = nullptr;
if (CompileGeometryShader(code, &blob, pDefines))
{
ID3D11GeometryShader* g_shader = CreateGeometryShaderFromByteCode(blob);
blob->Release();
return g_shader;
}
return nullptr;
}
ID3D11PixelShader* CompileAndCreatePixelShader(const std::string& code)
{
D3DBlob* blob = nullptr;
CompilePixelShader(code, &blob);
if (blob)
{
ID3D11PixelShader* p_shader = CreatePixelShaderFromByteCode(blob);
blob->Release();
return p_shader;
}
return nullptr;
}
ID3D11ComputeShader* CompileAndCreateComputeShader(const std::string& code)
{
D3DBlob* blob = nullptr;
CompileComputeShader(code, &blob);
if (blob)
{
ID3D11ComputeShader* shader = CreateComputeShaderFromByteCode(blob);
blob->Release();
return shader;
}
return nullptr;
}
} // namespace
} // namespace DX11

View File

@ -1,78 +0,0 @@
// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <string>
#include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DBlob.h"
struct ID3D11PixelShader;
struct ID3D11VertexShader;
namespace DX11
{
namespace D3D
{
ID3D11VertexShader* CreateVertexShaderFromByteCode(const void* bytecode, size_t len);
ID3D11GeometryShader* CreateGeometryShaderFromByteCode(const void* bytecode, size_t len);
ID3D11PixelShader* CreatePixelShaderFromByteCode(const void* bytecode, size_t len);
ID3D11ComputeShader* CreateComputeShaderFromByteCode(const void* bytecode, size_t len);
// The returned bytecode buffers should be Release()d.
bool CompileVertexShader(const std::string& code, D3DBlob** blob);
bool CompileGeometryShader(const std::string& code, D3DBlob** blob,
const D3D_SHADER_MACRO* pDefines = nullptr);
bool CompilePixelShader(const std::string& code, D3DBlob** blob,
const D3D_SHADER_MACRO* pDefines = nullptr);
bool CompileComputeShader(const std::string& code, D3DBlob** blob,
const D3D_SHADER_MACRO* pDefines = nullptr);
// Utility functions
ID3D11VertexShader* CompileAndCreateVertexShader(const std::string& code);
ID3D11GeometryShader* CompileAndCreateGeometryShader(const std::string& code,
const D3D_SHADER_MACRO* pDefines = nullptr);
ID3D11PixelShader* CompileAndCreatePixelShader(const std::string& code);
ID3D11ComputeShader* CompileAndCreateComputeShader(const std::string& code);
inline ID3D11VertexShader* CreateVertexShaderFromByteCode(D3DBlob* bytecode)
{
return CreateVertexShaderFromByteCode(bytecode->Data(), bytecode->Size());
}
inline ID3D11GeometryShader* CreateGeometryShaderFromByteCode(D3DBlob* bytecode)
{
return CreateGeometryShaderFromByteCode(bytecode->Data(), bytecode->Size());
}
inline ID3D11PixelShader* CreatePixelShaderFromByteCode(D3DBlob* bytecode)
{
return CreatePixelShaderFromByteCode(bytecode->Data(), bytecode->Size());
}
inline ID3D11ComputeShader* CreateComputeShaderFromByteCode(D3DBlob* bytecode)
{
return CreateComputeShaderFromByteCode(bytecode->Data(), bytecode->Size());
}
inline ID3D11VertexShader* CompileAndCreateVertexShader(D3DBlob* code)
{
return CompileAndCreateVertexShader(reinterpret_cast<const char*>(code->Data()));
}
inline ID3D11GeometryShader*
CompileAndCreateGeometryShader(D3DBlob* code, const D3D_SHADER_MACRO* pDefines = nullptr)
{
return CompileAndCreateGeometryShader(reinterpret_cast<const char*>(code->Data()), pDefines);
}
inline ID3D11PixelShader* CompileAndCreatePixelShader(D3DBlob* code)
{
return CompileAndCreatePixelShader(reinterpret_cast<const char*>(code->Data()));
}
inline ID3D11ComputeShader* CompileAndCreateComputeShader(D3DBlob* code)
{
return CompileAndCreateComputeShader(reinterpret_cast<const char*>(code->Data()));
}
}
} // namespace DX11

View File

@ -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()

View File

@ -16,6 +16,8 @@
namespace DX11
{
class DXFramebuffer;
class StateCache
{
public:
@ -112,14 +114,6 @@ public:
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 @@ public:
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 @@ private:
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 @@ private:
std::array<ID3D11Buffer*, 2> pixelConstants;
ID3D11Buffer* vertexConstants;
ID3D11Buffer* geometryConstants;
ID3D11Buffer* computeConstants;
ID3D11Buffer* vertexBuffer;
ID3D11Buffer* indexBuffer;
u32 vertexBufferStride;
@ -262,18 +277,27 @@ private:
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

View File

@ -1,105 +0,0 @@
// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <algorithm>
#include "Common/CommonTypes.h"
#include "Common/MsgHandler.h"
#include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DTexture.h"
namespace DX11
{
D3DTexture2D* D3DTexture2D::Create(unsigned int width, unsigned int height, D3D11_BIND_FLAG bind,
D3D11_USAGE usage, DXGI_FORMAT fmt, unsigned int levels,
unsigned int slices, D3D11_SUBRESOURCE_DATA* data)
{
ID3D11Texture2D* pTexture = nullptr;
HRESULT hr;
D3D11_CPU_ACCESS_FLAG cpuflags;
if (usage == D3D11_USAGE_STAGING)
cpuflags = (D3D11_CPU_ACCESS_FLAG)((int)D3D11_CPU_ACCESS_WRITE | (int)D3D11_CPU_ACCESS_READ);
else if (usage == D3D11_USAGE_DYNAMIC)
cpuflags = D3D11_CPU_ACCESS_WRITE;
else
cpuflags = (D3D11_CPU_ACCESS_FLAG)0;
D3D11_TEXTURE2D_DESC texdesc =
CD3D11_TEXTURE2D_DESC(fmt, width, height, slices, levels, bind, usage, cpuflags);
hr = D3D::device->CreateTexture2D(&texdesc, data, &pTexture);
if (FAILED(hr))
{
PanicAlert("Failed to create texture at %s, line %d: hr=%#x\n", __FILE__, __LINE__, hr);
return nullptr;
}
D3DTexture2D* ret = new D3DTexture2D(pTexture, bind);
SAFE_RELEASE(pTexture);
return ret;
}
void D3DTexture2D::AddRef()
{
++ref;
}
UINT D3DTexture2D::Release()
{
--ref;
if (ref == 0)
{
delete this;
return 0;
}
return ref;
}
ID3D11Texture2D*& D3DTexture2D::GetTex()
{
return tex;
}
ID3D11ShaderResourceView*& D3DTexture2D::GetSRV()
{
return srv;
}
ID3D11RenderTargetView*& D3DTexture2D::GetRTV()
{
return rtv;
}
ID3D11DepthStencilView*& D3DTexture2D::GetDSV()
{
return dsv;
}
D3DTexture2D::D3DTexture2D(ID3D11Texture2D* texptr, D3D11_BIND_FLAG bind, DXGI_FORMAT srv_format,
DXGI_FORMAT dsv_format, DXGI_FORMAT rtv_format, bool multisampled)
: tex{texptr}
{
D3D11_SRV_DIMENSION srv_dim =
multisampled ? D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY : D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
D3D11_DSV_DIMENSION dsv_dim =
multisampled ? D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY : D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
D3D11_RTV_DIMENSION rtv_dim =
multisampled ? D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY : D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = CD3D11_SHADER_RESOURCE_VIEW_DESC(srv_dim, srv_format);
D3D11_DEPTH_STENCIL_VIEW_DESC dsv_desc = CD3D11_DEPTH_STENCIL_VIEW_DESC(dsv_dim, dsv_format);
D3D11_RENDER_TARGET_VIEW_DESC rtv_desc = CD3D11_RENDER_TARGET_VIEW_DESC(rtv_dim, rtv_format);
if (bind & D3D11_BIND_SHADER_RESOURCE)
D3D::device->CreateShaderResourceView(tex, &srv_desc, &srv);
if (bind & D3D11_BIND_RENDER_TARGET)
D3D::device->CreateRenderTargetView(tex, &rtv_desc, &rtv);
if (bind & D3D11_BIND_DEPTH_STENCIL)
D3D::device->CreateDepthStencilView(tex, &dsv_desc, &dsv);
tex->AddRef();
}
D3DTexture2D::~D3DTexture2D()
{
SAFE_RELEASE(srv);
SAFE_RELEASE(rtv);
SAFE_RELEASE(dsv);
SAFE_RELEASE(tex);
}
} // namespace DX11

View File

@ -1,48 +0,0 @@
// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <d3d11.h>
#include "Common/CommonTypes.h"
namespace DX11
{
class D3DTexture2D
{
public:
// there are two ways to create a D3DTexture2D object:
// either create an ID3D11Texture2D object, pass it to the constructor and specify what views
// to create
// or let the texture automatically be created by D3DTexture2D::Create
D3DTexture2D(ID3D11Texture2D* texptr, D3D11_BIND_FLAG bind,
DXGI_FORMAT srv_format = DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT dsv_format = DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT rtv_format = DXGI_FORMAT_UNKNOWN, bool multisampled = false);
static D3DTexture2D* Create(unsigned int width, unsigned int height, D3D11_BIND_FLAG bind,
D3D11_USAGE usage, DXGI_FORMAT, unsigned int levels = 1,
unsigned int slices = 1, D3D11_SUBRESOURCE_DATA* data = nullptr);
// reference counting, use AddRef() when creating a new reference and Release() it when you don't
// need it anymore
void AddRef();
UINT Release();
ID3D11Texture2D*& GetTex();
ID3D11ShaderResourceView*& GetSRV();
ID3D11RenderTargetView*& GetRTV();
ID3D11DepthStencilView*& GetDSV();
private:
~D3DTexture2D();
ID3D11Texture2D* tex;
ID3D11ShaderResourceView* srv = nullptr;
ID3D11RenderTargetView* rtv = nullptr;
ID3D11DepthStencilView* dsv = nullptr;
UINT ref = 1;
};
} // namespace DX11

View File

@ -1,407 +0,0 @@
// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "VideoBackends/D3D/D3DUtil.h"
#include <cctype>
#include <list>
#include <string>
#include "Common/Align.h"
#include "Common/Assert.h"
#include "Common/Logging/Log.h"
#include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DShader.h"
#include "VideoBackends/D3D/D3DState.h"
#include "VideoBackends/D3D/GeometryShaderCache.h"
#include "VideoBackends/D3D/PixelShaderCache.h"
#include "VideoBackends/D3D/VertexShaderCache.h"
#include "VideoCommon/VideoBackendBase.h"
namespace DX11
{
namespace D3D
{
// Ring buffer class, shared between the draw* functions
class UtilVertexBuffer
{
public:
UtilVertexBuffer(unsigned int size) : max_size(size)
{
D3D11_BUFFER_DESC desc = CD3D11_BUFFER_DESC(max_size, D3D11_BIND_VERTEX_BUFFER,
D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
device->CreateBuffer(&desc, nullptr, &buf);
}
~UtilVertexBuffer() { buf->Release(); }
int GetSize() const { return max_size; }
// returns vertex offset to the new data
int AppendData(void* data, unsigned int size, unsigned int vertex_size)
{
D3D11_MAPPED_SUBRESOURCE map;
if (offset + size >= max_size)
{
// wrap buffer around and notify observers
offset = 0;
context->Map(buf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
for (bool* observer : observers)
*observer = true;
}
else
{
context->Map(buf, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &map);
}
offset = Common::AlignUp(offset, vertex_size);
memcpy((u8*)map.pData + offset, data, size);
context->Unmap(buf, 0);
offset += size;
return (offset - size) / vertex_size;
}
int BeginAppendData(void** write_ptr, unsigned int size, unsigned int vertex_size)
{
DEBUG_ASSERT(size < max_size);
D3D11_MAPPED_SUBRESOURCE map;
unsigned int aligned_offset = Common::AlignUp(offset, vertex_size);
if (aligned_offset + size > max_size)
{
// wrap buffer around and notify observers
offset = 0;
aligned_offset = 0;
context->Map(buf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
for (bool* observer : observers)
*observer = true;
}
else
{
context->Map(buf, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &map);
}
*write_ptr = reinterpret_cast<byte*>(map.pData) + aligned_offset;
offset = aligned_offset + size;
return aligned_offset / vertex_size;
}
void EndAppendData() { context->Unmap(buf, 0); }
void AddWrapObserver(bool* observer) { observers.push_back(observer); }
inline ID3D11Buffer*& GetBuffer() { return buf; }
private:
ID3D11Buffer* buf = nullptr;
unsigned int offset = 0;
unsigned int max_size;
std::list<bool*> observers;
};
static UtilVertexBuffer* util_vbuf = nullptr;
static ID3D11SamplerState* linear_copy_sampler = nullptr;
static ID3D11SamplerState* point_copy_sampler = nullptr;
struct STQVertex
{
float x, y, z, u, v, w;
};
struct ClearVertex
{
float x, y, z;
u32 col;
};
struct ColVertex
{
float x, y, z;
u32 col;
};
struct TexQuadData
{
float u1, v1, u2, v2, S, G;
};
static TexQuadData tex_quad_data;
struct DrawQuadData
{
float x1, y1, x2, y2, z;
u32 col;
};
static DrawQuadData draw_quad_data;
struct ClearQuadData
{
u32 col;
float z;
};
static ClearQuadData clear_quad_data;
// ring buffer offsets
static int stq_offset, cq_offset, clearq_offset;
// observer variables for ring buffer wraps
static bool stq_observer, cq_observer, clearq_observer;
void InitUtils()
{
util_vbuf = new UtilVertexBuffer(65536); // 64KiB
float border[4] = {0.f, 0.f, 0.f, 0.f};
D3D11_SAMPLER_DESC samDesc = CD3D11_SAMPLER_DESC(
D3D11_FILTER_MIN_MAG_MIP_POINT, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER,
D3D11_TEXTURE_ADDRESS_BORDER, 0.f, 1, D3D11_COMPARISON_ALWAYS, border, 0.f, 0.f);
HRESULT hr = D3D::device->CreateSamplerState(&samDesc, &point_copy_sampler);
if (FAILED(hr))
PanicAlert("Failed to create sampler state at %s %d\n", __FILE__, __LINE__);
else
SetDebugObjectName(point_copy_sampler, "point copy sampler state");
samDesc = CD3D11_SAMPLER_DESC(D3D11_FILTER_MIN_MAG_MIP_LINEAR, D3D11_TEXTURE_ADDRESS_BORDER,
D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, 0.f, 1,
D3D11_COMPARISON_ALWAYS, border, 0.f, 0.f);
hr = D3D::device->CreateSamplerState(&samDesc, &linear_copy_sampler);
if (FAILED(hr))
PanicAlert("Failed to create sampler state at %s %d\n", __FILE__, __LINE__);
else
SetDebugObjectName(linear_copy_sampler, "linear copy sampler state");
// cached data used to avoid unnecessarily reloading the vertex buffers
memset(&tex_quad_data, 0, sizeof(tex_quad_data));
memset(&draw_quad_data, 0, sizeof(draw_quad_data));
memset(&clear_quad_data, 0, sizeof(clear_quad_data));
// make sure to properly load the vertex data whenever the corresponding functions get called the
// first time
stq_observer = cq_observer = clearq_observer = true;
util_vbuf->AddWrapObserver(&stq_observer);
util_vbuf->AddWrapObserver(&cq_observer);
util_vbuf->AddWrapObserver(&clearq_observer);
}
void ShutdownUtils()
{
SAFE_RELEASE(point_copy_sampler);
SAFE_RELEASE(linear_copy_sampler);
SAFE_DELETE(util_vbuf);
}
void SetPointCopySampler()
{
D3D::stateman->SetSampler(0, point_copy_sampler);
}
void SetLinearCopySampler()
{
D3D::stateman->SetSampler(0, linear_copy_sampler);
}
void drawShadedTexQuad(ID3D11ShaderResourceView* texture, const D3D11_RECT* rSource,
int SourceWidth, int SourceHeight, ID3D11PixelShader* PShader,
ID3D11VertexShader* VShader, ID3D11InputLayout* layout,
ID3D11GeometryShader* GShader, u32 slice)
{
float sw = 1.0f / (float)SourceWidth;
float sh = 1.0f / (float)SourceHeight;
float u1 = ((float)rSource->left) * sw;
float u2 = ((float)rSource->right) * sw;
float v1 = ((float)rSource->top) * sh;
float v2 = ((float)rSource->bottom) * sh;
float S = (float)slice;
STQVertex coords[4] = {
{-1.0f, 1.0f, 0.0f, u1, v1, S},
{1.0f, 1.0f, 0.0f, u2, v1, S},
{-1.0f, -1.0f, 0.0f, u1, v2, S},
{1.0f, -1.0f, 0.0f, u2, v2, S},
};
// only upload the data to VRAM if it changed
if (stq_observer || tex_quad_data.u1 != u1 || tex_quad_data.v1 != v1 || tex_quad_data.u2 != u2 ||
tex_quad_data.v2 != v2 || tex_quad_data.S != S)
{
stq_offset = util_vbuf->AppendData(coords, sizeof(coords), sizeof(STQVertex));
stq_observer = false;
tex_quad_data.u1 = u1;
tex_quad_data.v1 = v1;
tex_quad_data.u2 = u2;
tex_quad_data.v2 = v2;
tex_quad_data.S = S;
}
UINT stride = sizeof(STQVertex);
UINT offset = 0;
D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
D3D::stateman->SetInputLayout(layout);
D3D::stateman->SetVertexBuffer(util_vbuf->GetBuffer(), stride, offset);
D3D::stateman->SetPixelShader(PShader);
D3D::stateman->SetTexture(0, texture);
D3D::stateman->SetVertexShader(VShader);
D3D::stateman->SetGeometryShader(GShader);
D3D::stateman->Apply();
D3D::context->Draw(4, stq_offset);
D3D::stateman->SetTexture(0, nullptr); // immediately unbind the texture
D3D::stateman->Apply();
D3D::stateman->SetGeometryShader(nullptr);
}
// Fills a certain area of the current render target with the specified color
// destination coordinates normalized to (-1;1)
void drawColorQuad(u32 Color, float z, float x1, float y1, float x2, float y2)
{
ColVertex coords[4] = {
{x1, y1, z, Color},
{x2, y1, z, Color},
{x1, y2, z, Color},
{x2, y2, z, Color},
};
if (cq_observer || draw_quad_data.x1 != x1 || draw_quad_data.y1 != y1 ||
draw_quad_data.x2 != x2 || draw_quad_data.y2 != y2 || draw_quad_data.col != Color ||
draw_quad_data.z != z)
{
cq_offset = util_vbuf->AppendData(coords, sizeof(coords), sizeof(ColVertex));
cq_observer = false;
draw_quad_data.x1 = x1;
draw_quad_data.y1 = y1;
draw_quad_data.x2 = x2;
draw_quad_data.y2 = y2;
draw_quad_data.col = Color;
draw_quad_data.z = z;
}
stateman->SetVertexShader(VertexShaderCache::GetClearVertexShader());
stateman->SetGeometryShader(GeometryShaderCache::GetClearGeometryShader());
stateman->SetPixelShader(PixelShaderCache::GetClearProgram());
stateman->SetInputLayout(VertexShaderCache::GetClearInputLayout());
UINT stride = sizeof(ColVertex);
UINT offset = 0;
stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
stateman->SetVertexBuffer(util_vbuf->GetBuffer(), stride, offset);
stateman->Apply();
context->Draw(4, cq_offset);
stateman->SetGeometryShader(nullptr);
}
void drawClearQuad(u32 Color, float z)
{
ClearVertex coords[4] = {
{-1.0f, 1.0f, z, Color},
{1.0f, 1.0f, z, Color},
{-1.0f, -1.0f, z, Color},
{1.0f, -1.0f, z, Color},
};
if (clearq_observer || clear_quad_data.col != Color || clear_quad_data.z != z)
{
clearq_offset = util_vbuf->AppendData(coords, sizeof(coords), sizeof(ClearVertex));
clearq_observer = false;
clear_quad_data.col = Color;
clear_quad_data.z = z;
}
stateman->SetVertexShader(VertexShaderCache::GetClearVertexShader());
stateman->SetGeometryShader(GeometryShaderCache::GetClearGeometryShader());
stateman->SetPixelShader(PixelShaderCache::GetClearProgram());
stateman->SetInputLayout(VertexShaderCache::GetClearInputLayout());
UINT stride = sizeof(ClearVertex);
UINT offset = 0;
stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
stateman->SetVertexBuffer(util_vbuf->GetBuffer(), stride, offset);
stateman->Apply();
context->Draw(4, clearq_offset);
stateman->SetGeometryShader(nullptr);
}
static void InitColVertex(ColVertex* vert, float x, float y, float z, u32 col)
{
vert->x = x;
vert->y = y;
vert->z = z;
vert->col = col;
}
void DrawEFBPokeQuads(EFBAccessType type, const EfbPokeData* points, size_t num_points)
{
const size_t COL_QUAD_SIZE = sizeof(ColVertex) * 6;
// Set common state
stateman->SetVertexShader(VertexShaderCache::GetClearVertexShader());
stateman->SetGeometryShader(GeometryShaderCache::GetClearGeometryShader());
stateman->SetPixelShader(PixelShaderCache::GetClearProgram());
stateman->SetInputLayout(VertexShaderCache::GetClearInputLayout());
stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
stateman->SetVertexBuffer(util_vbuf->GetBuffer(), sizeof(ColVertex), 0);
stateman->Apply();
// if drawing a large number of points at once, this will have to be split into multiple passes.
size_t points_per_draw = util_vbuf->GetSize() / COL_QUAD_SIZE;
size_t current_point_index = 0;
while (current_point_index < num_points)
{
size_t points_to_draw = std::min(num_points - current_point_index, points_per_draw);
size_t required_bytes = COL_QUAD_SIZE * points_to_draw;
// map and reserve enough buffer space for this draw
void* buffer_ptr;
int base_vertex_index =
util_vbuf->BeginAppendData(&buffer_ptr, (int)required_bytes, sizeof(ColVertex));
// generate quads for each efb point
ColVertex* base_vertex_ptr = reinterpret_cast<ColVertex*>(buffer_ptr);
for (size_t i = 0; i < points_to_draw; i++)
{
// generate quad from the single point (clip-space coordinates)
const EfbPokeData* point = &points[current_point_index];
float x1 = float(point->x) * 2.0f / EFB_WIDTH - 1.0f;
float y1 = -float(point->y) * 2.0f / EFB_HEIGHT + 1.0f;
float x2 = float(point->x + 1) * 2.0f / EFB_WIDTH - 1.0f;
float y2 = -float(point->y + 1) * 2.0f / EFB_HEIGHT + 1.0f;
float z = 0.0f;
u32 col = 0;
if (type == EFBAccessType::PokeZ)
{
z = 1.0f - static_cast<float>(point->data & 0xFFFFFF) / 16777216.0f;
}
else
{
col = ((point->data & 0xFF00FF00) | ((point->data >> 16) & 0xFF) |
((point->data << 16) & 0xFF0000));
}
current_point_index++;
// quad -> triangles
ColVertex* vertex = &base_vertex_ptr[i * 6];
InitColVertex(&vertex[0], x1, y1, z, col);
InitColVertex(&vertex[1], x2, y1, z, col);
InitColVertex(&vertex[2], x1, y2, z, col);
InitColVertex(&vertex[3], x1, y2, z, col);
InitColVertex(&vertex[4], x2, y1, z, col);
InitColVertex(&vertex[5], x2, y2, z, col);
}
// unmap the util buffer, and issue the draw
util_vbuf->EndAppendData();
context->Draw(6 * (UINT)points_to_draw, base_vertex_index);
}
stateman->SetGeometryShader(GeometryShaderCache::GetClearGeometryShader());
}
} // namespace D3D
} // namespace DX11

View File

@ -1,32 +0,0 @@
// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <d3d11.h>
#include <string>
#include "Common/CommonTypes.h"
#include "VideoCommon/RenderBase.h"
namespace DX11
{
namespace D3D
{
void InitUtils();
void ShutdownUtils();
void SetPointCopySampler();
void SetLinearCopySampler();
void drawShadedTexQuad(ID3D11ShaderResourceView* texture, const D3D11_RECT* rSource,
int SourceWidth, int SourceHeight, ID3D11PixelShader* PShader,
ID3D11VertexShader* VShader, ID3D11InputLayout* layout,
ID3D11GeometryShader* GShader = nullptr, u32 slice = 0);
void drawClearQuad(u32 Color, float z);
void drawColorQuad(u32 Color, float z, float x1, float y1, float x2, float y2);
void DrawEFBPokeQuads(EFBAccessType type, const EfbPokeData* points, size_t num_points);
}
}

View File

@ -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

View File

@ -16,7 +16,8 @@ public:
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 @@ public:
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 @@ private:
ID3D11DepthStencilState* m_depth_state;
ID3D11BlendState* m_blend_state;
D3D11_PRIMITIVE_TOPOLOGY m_primitive_topology;
bool m_use_logic_op;
};
} // namespace DX11

View File

@ -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;
}
break;
return D3D::GeometryShaderVersionString();
case ShaderStage::Pixel:
{
if (!D3D::CompilePixelShader(std::string(source, length), &bytecode))
return nullptr;
}
break;
return D3D::PixelShaderVersionString();
case ShaderStage::Compute:
{
if (!D3D::CompileComputeShader(std::string(source, length), &bytecode))
return nullptr;
}
return D3D::ComputeShaderVersionString();
default:
return nullptr;
return "";
}
}
std::unique_ptr<DXShader> shader = CreateFromBlob(stage, bytecode);
if (!shader)
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))
{
bytecode->Release();
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;
}
return shader;
if (errors && errors->GetBufferSize() > 0)
{
WARN_LOG(VIDEO, "%s compilation succeeded with warnings:\n%s", target,
static_cast<const char*>(errors->GetBufferPointer()));
}
SAFE_RELEASE(errors);
out_bytecode->resize(code->GetBufferSize());
std::memcpy(out_bytecode->data(), code->GetBufferPointer(), code->GetBufferSize());
code->Release();
return true;
}
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 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

View File

@ -3,13 +3,9 @@
// 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
@ -17,14 +13,11 @@ 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,8 +26,11 @@ public:
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,
@ -42,7 +38,7 @@ public:
private:
ID3D11DeviceChild* m_shader;
D3DBlob* m_bytecode;
BinaryData m_bytecode;
};
} // namespace DX11

View File

@ -9,25 +9,47 @@
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DState.h"
#include "VideoBackends/D3D/D3DTexture.h"
#include "VideoBackends/D3D/D3DUtil.h"
#include "VideoBackends/D3D/DXTexture.h"
#include "VideoBackends/D3D/FramebufferManager.h"
#include "VideoBackends/D3D/GeometryShaderCache.h"
#include "VideoBackends/D3D/PixelShaderCache.h"
#include "VideoBackends/D3D/TextureCache.h"
#include "VideoBackends/D3D/VertexShaderCache.h"
#include "VideoCommon/ImageWrite.h"
#include "VideoCommon/TextureConfig.h"
namespace DX11
{
namespace
{
DXGI_FORMAT GetDXGIFormatForHostFormat(AbstractTextureFormat format)
DXGI_FORMAT GetDXGIFormatForHostFormat(AbstractTextureFormat format, bool typeless)
{
switch (format)
{
case AbstractTextureFormat::DXT1:
return DXGI_FORMAT_BC1_UNORM;
case AbstractTextureFormat::DXT3:
return DXGI_FORMAT_BC2_UNORM;
case AbstractTextureFormat::DXT5:
return DXGI_FORMAT_BC3_UNORM;
case AbstractTextureFormat::BPTC:
return DXGI_FORMAT_BC7_UNORM;
case AbstractTextureFormat::RGBA8:
return typeless ? DXGI_FORMAT_R8G8B8A8_TYPELESS : DXGI_FORMAT_R8G8B8A8_UNORM;
case AbstractTextureFormat::BGRA8:
return typeless ? DXGI_FORMAT_B8G8R8A8_TYPELESS : DXGI_FORMAT_B8G8R8A8_UNORM;
case AbstractTextureFormat::R16:
return typeless ? DXGI_FORMAT_R16_TYPELESS : DXGI_FORMAT_R16_UNORM;
case AbstractTextureFormat::R32F:
return typeless ? DXGI_FORMAT_R32_TYPELESS : DXGI_FORMAT_R32_FLOAT;
case AbstractTextureFormat::D16:
return DXGI_FORMAT_R16_TYPELESS;
case AbstractTextureFormat::D24_S8:
return DXGI_FORMAT_R24G8_TYPELESS;
case AbstractTextureFormat::D32F:
return DXGI_FORMAT_R32_TYPELESS;
case AbstractTextureFormat::D32F_S8:
return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
default:
PanicAlert("Unhandled texture format.");
return DXGI_FORMAT_R8G8B8A8_UNORM;
}
}
DXGI_FORMAT GetSRVFormatForHostFormat(AbstractTextureFormat format)
{
switch (format)
{
@ -47,23 +69,6 @@ DXGI_FORMAT GetDXGIFormatForHostFormat(AbstractTextureFormat format)
return DXGI_FORMAT_R16_UNORM;
case AbstractTextureFormat::R32F:
return DXGI_FORMAT_R32_FLOAT;
case AbstractTextureFormat::D16:
return DXGI_FORMAT_R16_TYPELESS;
case AbstractTextureFormat::D24_S8:
return DXGI_FORMAT_R24G8_TYPELESS;
case AbstractTextureFormat::D32F:
return DXGI_FORMAT_R32_TYPELESS;
case AbstractTextureFormat::D32F_S8:
return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
default:
PanicAlert("Unhandled texture format.");
return DXGI_FORMAT_R8G8B8A8_UNORM;
}
}
DXGI_FORMAT GetSRVFormatForHostFormat(AbstractTextureFormat format)
{
switch (format)
{
case AbstractTextureFormat::D16:
return DXGI_FORMAT_R16_UNORM;
case AbstractTextureFormat::D24_S8:
@ -73,7 +78,25 @@ DXGI_FORMAT GetSRVFormatForHostFormat(AbstractTextureFormat format)
case AbstractTextureFormat::D32F_S8:
return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
default:
return GetDXGIFormatForHostFormat(format);
PanicAlert("Unhandled SRV format");
return DXGI_FORMAT_UNKNOWN;
}
}
DXGI_FORMAT GetRTVFormatForHostFormat(AbstractTextureFormat format, bool integer)
{
switch (format)
{
case AbstractTextureFormat::RGBA8:
return integer ? DXGI_FORMAT_R8G8B8A8_UINT : DXGI_FORMAT_R8G8B8A8_UNORM;
case AbstractTextureFormat::BGRA8:
return DXGI_FORMAT_B8G8R8A8_UNORM;
case AbstractTextureFormat::R16:
return integer ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R16_UNORM;
case AbstractTextureFormat::R32F:
return DXGI_FORMAT_R32_FLOAT;
default:
PanicAlert("Unhandled RTV format");
return DXGI_FORMAT_UNKNOWN;
}
}
DXGI_FORMAT GetDSVFormatForHostFormat(AbstractTextureFormat format)
@ -89,55 +112,87 @@ DXGI_FORMAT GetDSVFormatForHostFormat(AbstractTextureFormat format)
case AbstractTextureFormat::D32F_S8:
return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
default:
return GetDXGIFormatForHostFormat(format);
PanicAlert("Unhandled DSV format");
return DXGI_FORMAT_UNKNOWN;
}
}
} // Anonymous namespace
DXTexture::DXTexture(const TextureConfig& tex_config) : AbstractTexture(tex_config)
DXTexture::DXTexture(const TextureConfig& tex_config, ID3D11Texture2D* d3d_texture,
ID3D11ShaderResourceView* d3d_srv, ID3D11UnorderedAccessView* d3d_uav)
: AbstractTexture(tex_config), m_d3d_texture(d3d_texture), m_d3d_srv(d3d_srv),
m_d3d_uav(d3d_uav)
{
DXGI_FORMAT tex_format = GetDXGIFormatForHostFormat(m_config.format);
DXGI_FORMAT srv_format = GetSRVFormatForHostFormat(m_config.format);
DXGI_FORMAT rtv_format = DXGI_FORMAT_UNKNOWN;
DXGI_FORMAT dsv_format = DXGI_FORMAT_UNKNOWN;
UINT bind_flags = D3D11_BIND_SHADER_RESOURCE;
if (tex_config.rendertarget)
{
if (IsDepthFormat(tex_config.format))
{
bind_flags |= D3D11_BIND_DEPTH_STENCIL;
dsv_format = GetDSVFormatForHostFormat(m_config.format);
}
else
{
bind_flags |= D3D11_BIND_RENDER_TARGET;
rtv_format = tex_format;
}
}
CD3D11_TEXTURE2D_DESC texdesc(tex_format, tex_config.width, tex_config.height, tex_config.layers,
tex_config.levels, bind_flags, D3D11_USAGE_DEFAULT, 0,
tex_config.samples, 0, 0);
ID3D11Texture2D* pTexture;
HRESULT hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &pTexture);
CHECK(SUCCEEDED(hr), "Create backing DXTexture");
m_texture = new D3DTexture2D(pTexture, static_cast<D3D11_BIND_FLAG>(bind_flags), srv_format,
dsv_format, rtv_format, tex_config.samples > 1);
SAFE_RELEASE(pTexture);
}
DXTexture::~DXTexture()
{
g_renderer->UnbindTexture(this);
m_texture->Release();
if (m_d3d_uav)
m_d3d_uav->Release();
if (m_d3d_srv)
{
if (D3D::stateman->UnsetTexture(m_d3d_srv) != 0)
D3D::stateman->ApplyTextures();
m_d3d_srv->Release();
}
m_d3d_texture->Release();
}
D3DTexture2D* DXTexture::GetRawTexIdentifier() const
std::unique_ptr<DXTexture> DXTexture::Create(const TextureConfig& config)
{
return m_texture;
// Use typeless to create the texture when it's a render target, so we can alias it with an
// integer format (for EFB).
const DXGI_FORMAT tex_format = GetDXGIFormatForHostFormat(config.format, config.IsRenderTarget());
const DXGI_FORMAT srv_format = GetSRVFormatForHostFormat(config.format);
UINT bindflags = D3D11_BIND_SHADER_RESOURCE;
if (config.IsRenderTarget())
bindflags |= IsDepthFormat(config.format) ? D3D11_BIND_DEPTH_STENCIL : D3D11_BIND_RENDER_TARGET;
if (config.IsComputeImage())
bindflags |= D3D11_BIND_UNORDERED_ACCESS;
CD3D11_TEXTURE2D_DESC desc(tex_format, config.width, config.height, config.layers, config.levels,
bindflags, D3D11_USAGE_DEFAULT, 0, config.samples, 0, 0);
ID3D11Texture2D* d3d_texture;
HRESULT hr = D3D::device->CreateTexture2D(&desc, nullptr, &d3d_texture);
if (FAILED(hr))
{
PanicAlert("Failed to create %ux%ux%u D3D backing texture", config.width, config.height,
config.layers);
return nullptr;
}
ID3D11ShaderResourceView* d3d_srv;
const CD3D11_SHADER_RESOURCE_VIEW_DESC srv_desc(d3d_texture,
config.IsMultisampled() ?
D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY :
D3D11_SRV_DIMENSION_TEXTURE2DARRAY,
srv_format, 0, config.levels, 0, config.layers);
hr = D3D::device->CreateShaderResourceView(d3d_texture, &srv_desc, &d3d_srv);
if (FAILED(hr))
{
PanicAlert("Failed to create %ux%ux%u D3D SRV", config.width, config.height, config.layers);
d3d_texture->Release();
return nullptr;
}
ID3D11UnorderedAccessView* d3d_uav = nullptr;
if (config.IsComputeImage())
{
const CD3D11_UNORDERED_ACCESS_VIEW_DESC uav_desc(
d3d_texture, D3D11_UAV_DIMENSION_TEXTURE2DARRAY, srv_format, 0, 0, config.layers);
hr = D3D::device->CreateUnorderedAccessView(d3d_texture, &uav_desc, &d3d_uav);
if (FAILED(hr))
{
PanicAlert("Failed to create %ux%ux%u D3D UAV", config.width, config.height, config.layers);
d3d_uav->Release();
d3d_texture->Release();
return nullptr;
}
}
return std::make_unique<DXTexture>(config, d3d_texture, d3d_srv, d3d_uav);
}
void DXTexture::CopyRectangleFromTexture(const AbstractTexture* src,
@ -158,42 +213,11 @@ void DXTexture::CopyRectangleFromTexture(const AbstractTexture* src,
src_box.back = 1;
D3D::context->CopySubresourceRegion(
m_texture->GetTex(), D3D11CalcSubresource(dst_level, dst_layer, m_config.levels),
dst_rect.left, dst_rect.top, 0, srcentry->m_texture->GetTex(),
m_d3d_texture, D3D11CalcSubresource(dst_level, dst_layer, m_config.levels), dst_rect.left,
dst_rect.top, 0, srcentry->m_d3d_texture,
D3D11CalcSubresource(src_level, src_layer, srcentry->m_config.levels), &src_box);
}
void DXTexture::ScaleRectangleFromTexture(const AbstractTexture* source,
const MathUtil::Rectangle<int>& srcrect,
const MathUtil::Rectangle<int>& dstrect)
{
const DXTexture* srcentry = static_cast<const DXTexture*>(source);
ASSERT(m_config.rendertarget);
g_renderer->ResetAPIState(); // reset any game specific settings
const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(float(dstrect.left), float(dstrect.top),
float(dstrect.GetWidth()), float(dstrect.GetHeight()));
D3D::stateman->UnsetTexture(m_texture->GetSRV());
D3D::stateman->Apply();
D3D::context->OMSetRenderTargets(1, &m_texture->GetRTV(), nullptr);
D3D::context->RSSetViewports(1, &vp);
D3D::SetLinearCopySampler();
D3D11_RECT srcRC;
srcRC.left = srcrect.left;
srcRC.right = srcrect.right;
srcRC.top = srcrect.top;
srcRC.bottom = srcrect.bottom;
D3D::drawShadedTexQuad(
srcentry->m_texture->GetSRV(), &srcRC, srcentry->m_config.width, srcentry->m_config.height,
PixelShaderCache::GetColorCopyProgram(false), VertexShaderCache::GetSimpleVertexShader(),
VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader(), 0);
g_renderer->RestoreAPIState();
}
void DXTexture::ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& rect,
u32 layer, u32 level)
{
@ -204,16 +228,16 @@ void DXTexture::ResolveFromTexture(const AbstractTexture* src, const MathUtil::R
rect.top + rect.GetHeight() <= static_cast<int>(srcentry->m_config.height));
D3D::context->ResolveSubresource(
m_texture->GetTex(), D3D11CalcSubresource(level, layer, m_config.levels),
srcentry->m_texture->GetTex(), D3D11CalcSubresource(level, layer, srcentry->m_config.levels),
GetDXGIFormatForHostFormat(m_config.format));
m_d3d_texture, D3D11CalcSubresource(level, layer, m_config.levels), srcentry->m_d3d_texture,
D3D11CalcSubresource(level, layer, srcentry->m_config.levels),
GetDXGIFormatForHostFormat(m_config.format, false));
}
void DXTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
size_t buffer_size)
{
size_t src_pitch = CalculateStrideForFormat(m_config.format, row_length);
D3D::context->UpdateSubresource(m_texture->GetTex(), level, nullptr, buffer,
D3D::context->UpdateSubresource(m_d3d_texture, level, nullptr, buffer,
static_cast<UINT>(src_pitch), 0);
}
@ -251,8 +275,8 @@ std::unique_ptr<DXStagingTexture> DXStagingTexture::Create(StagingTextureType ty
cpu_flags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
}
CD3D11_TEXTURE2D_DESC desc(GetDXGIFormatForHostFormat(config.format), config.width, config.height,
1, 1, 0, usage, cpu_flags);
CD3D11_TEXTURE2D_DESC desc(GetDXGIFormatForHostFormat(config.format, false), config.width,
config.height, 1, 1, 0, usage, cpu_flags);
ID3D11Texture2D* texture;
HRESULT hr = D3D::device->CreateTexture2D(&desc, nullptr, &texture);
@ -267,22 +291,33 @@ void DXStagingTexture::CopyFromTexture(const AbstractTexture* src,
const MathUtil::Rectangle<int>& src_rect, u32 src_layer,
u32 src_level, const MathUtil::Rectangle<int>& dst_rect)
{
ASSERT(m_type == StagingTextureType::Readback);
ASSERT(m_type == StagingTextureType::Readback || m_type == StagingTextureType::Mutable);
ASSERT(src_rect.GetWidth() == dst_rect.GetWidth() &&
src_rect.GetHeight() == dst_rect.GetHeight());
ASSERT(src_rect.left >= 0 && static_cast<u32>(src_rect.right) <= src->GetConfig().width &&
src_rect.top >= 0 && static_cast<u32>(src_rect.bottom) <= src->GetConfig().height);
ASSERT(src_rect.left >= 0 && static_cast<u32>(src_rect.right) <= src->GetWidth() &&
src_rect.top >= 0 && static_cast<u32>(src_rect.bottom) <= src->GetHeight());
ASSERT(dst_rect.left >= 0 && static_cast<u32>(dst_rect.right) <= m_config.width &&
dst_rect.top >= 0 && static_cast<u32>(dst_rect.bottom) <= m_config.height);
if (IsMapped())
DXStagingTexture::Unmap();
CD3D11_BOX src_box(src_rect.left, src_rect.top, 0, src_rect.right, src_rect.bottom, 1);
D3D::context->CopySubresourceRegion(
m_tex, 0, static_cast<u32>(dst_rect.left), static_cast<u32>(dst_rect.top), 0,
static_cast<const DXTexture*>(src)->GetRawTexIdentifier()->GetTex(),
D3D11CalcSubresource(src_level, src_layer, src->GetConfig().levels), &src_box);
if (static_cast<u32>(src_rect.GetWidth()) == GetWidth() &&
static_cast<u32>(src_rect.GetHeight()) == GetHeight())
{
// Copy whole resource, needed for depth textures.
D3D::context->CopySubresourceRegion(
m_tex, 0, 0, 0, 0, static_cast<const DXTexture*>(src)->GetD3DTexture(),
D3D11CalcSubresource(src_level, src_layer, src->GetLevels()), nullptr);
}
else
{
CD3D11_BOX src_box(src_rect.left, src_rect.top, 0, src_rect.right, src_rect.bottom, 1);
D3D::context->CopySubresourceRegion(
m_tex, 0, static_cast<u32>(dst_rect.left), static_cast<u32>(dst_rect.top), 0,
static_cast<const DXTexture*>(src)->GetD3DTexture(),
D3D11CalcSubresource(src_level, src_layer, src->GetLevels()), &src_box);
}
m_needs_flush = true;
}
@ -294,19 +329,29 @@ void DXStagingTexture::CopyToTexture(const MathUtil::Rectangle<int>& src_rect, A
ASSERT(m_type == StagingTextureType::Upload);
ASSERT(src_rect.GetWidth() == dst_rect.GetWidth() &&
src_rect.GetHeight() == dst_rect.GetHeight());
ASSERT(src_rect.left >= 0 && static_cast<u32>(src_rect.right) <= m_config.width &&
src_rect.top >= 0 && static_cast<u32>(src_rect.bottom) <= m_config.height);
ASSERT(dst_rect.left >= 0 && static_cast<u32>(dst_rect.right) <= dst->GetConfig().width &&
dst_rect.top >= 0 && static_cast<u32>(dst_rect.bottom) <= dst->GetConfig().height);
ASSERT(src_rect.left >= 0 && static_cast<u32>(src_rect.right) <= GetWidth() &&
src_rect.top >= 0 && static_cast<u32>(src_rect.bottom) <= GetHeight());
ASSERT(dst_rect.left >= 0 && static_cast<u32>(dst_rect.right) <= dst->GetWidth() &&
dst_rect.top >= 0 && static_cast<u32>(dst_rect.bottom) <= dst->GetHeight());
if (IsMapped())
DXStagingTexture::Unmap();
CD3D11_BOX src_box(src_rect.left, src_rect.top, 0, src_rect.right, src_rect.bottom, 1);
D3D::context->CopySubresourceRegion(
static_cast<const DXTexture*>(dst)->GetRawTexIdentifier()->GetTex(),
D3D11CalcSubresource(dst_level, dst_layer, dst->GetConfig().levels),
static_cast<u32>(dst_rect.left), static_cast<u32>(dst_rect.top), 0, m_tex, 0, &src_box);
if (static_cast<u32>(src_rect.GetWidth()) == dst->GetWidth() &&
static_cast<u32>(src_rect.GetHeight()) == dst->GetHeight())
{
D3D::context->CopySubresourceRegion(
static_cast<const DXTexture*>(dst)->GetD3DTexture(),
D3D11CalcSubresource(dst_level, dst_layer, dst->GetLevels()), 0, 0, 0, m_tex, 0, nullptr);
}
else
{
CD3D11_BOX src_box(src_rect.left, src_rect.top, 0, src_rect.right, src_rect.bottom, 1);
D3D::context->CopySubresourceRegion(
static_cast<const DXTexture*>(dst)->GetD3DTexture(),
D3D11CalcSubresource(dst_level, dst_layer, dst->GetLevels()),
static_cast<u32>(dst_rect.left), static_cast<u32>(dst_rect.top), 0, m_tex, 0, &src_box);
}
}
bool DXStagingTexture::Map()
@ -348,11 +393,14 @@ void DXStagingTexture::Flush()
m_needs_flush = false;
}
DXFramebuffer::DXFramebuffer(AbstractTextureFormat color_format, AbstractTextureFormat depth_format,
DXFramebuffer::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)
: AbstractFramebuffer(color_format, depth_format, width, height, layers, samples), m_rtv(rtv),
m_dsv(dsv)
ID3D11RenderTargetView* rtv, ID3D11RenderTargetView* integer_rtv,
ID3D11DepthStencilView* dsv)
: AbstractFramebuffer(color_attachment, depth_attachment, color_format, depth_format, width,
height, layers, samples),
m_rtv(rtv), m_integer_rtv(integer_rtv), m_dsv(dsv)
{
}
@ -360,12 +408,14 @@ DXFramebuffer::~DXFramebuffer()
{
if (m_rtv)
m_rtv->Release();
if (m_integer_rtv)
m_integer_rtv->Release();
if (m_dsv)
m_dsv->Release();
}
std::unique_ptr<DXFramebuffer> DXFramebuffer::Create(const DXTexture* color_attachment,
const DXTexture* depth_attachment)
std::unique_ptr<DXFramebuffer> DXFramebuffer::Create(DXTexture* color_attachment,
DXTexture* depth_attachment)
{
if (!ValidateConfig(color_attachment, depth_attachment))
return nullptr;
@ -381,55 +431,45 @@ std::unique_ptr<DXFramebuffer> DXFramebuffer::Create(const DXTexture* color_atta
const u32 samples = either_attachment->GetSamples();
ID3D11RenderTargetView* rtv = nullptr;
ID3D11RenderTargetView* integer_rtv = nullptr;
if (color_attachment)
{
D3D11_RENDER_TARGET_VIEW_DESC desc;
desc.Format = GetDXGIFormatForHostFormat(color_attachment->GetConfig().format);
if (color_attachment->GetConfig().IsMultisampled())
{
desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY;
desc.Texture2DMSArray.ArraySize = color_attachment->GetConfig().layers;
desc.Texture2DMSArray.FirstArraySlice = 0;
}
else
{
desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
desc.Texture2DArray.ArraySize = color_attachment->GetConfig().layers;
desc.Texture2DArray.FirstArraySlice = 0;
desc.Texture2DArray.MipSlice = 0;
}
HRESULT hr = D3D::device->CreateRenderTargetView(
color_attachment->GetRawTexIdentifier()->GetTex(), &desc, &rtv);
CD3D11_RENDER_TARGET_VIEW_DESC desc(
color_attachment->IsMultisampled() ? D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY :
D3D11_RTV_DIMENSION_TEXTURE2DARRAY,
GetRTVFormatForHostFormat(color_attachment->GetFormat(), false), 0, 0,
color_attachment->GetLayers());
HRESULT hr =
D3D::device->CreateRenderTargetView(color_attachment->GetD3DTexture(), &desc, &rtv);
CHECK(SUCCEEDED(hr), "Create render target view for framebuffer");
// Only create the integer RTV on Win8+.
DXGI_FORMAT integer_format = GetRTVFormatForHostFormat(color_attachment->GetFormat(), true);
if (D3D::device1 && integer_format != desc.Format)
{
desc.Format = integer_format;
hr = D3D::device->CreateRenderTargetView(color_attachment->GetD3DTexture(), &desc,
&integer_rtv);
CHECK(SUCCEEDED(hr), "Create integer render target view for framebuffer");
}
}
ID3D11DepthStencilView* dsv = nullptr;
if (depth_attachment)
{
D3D11_DEPTH_STENCIL_VIEW_DESC desc;
desc.Format = GetDXGIFormatForHostFormat(depth_attachment->GetConfig().format);
if (depth_attachment->GetConfig().IsMultisampled())
{
desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY;
desc.Texture2DMSArray.ArraySize = depth_attachment->GetConfig().layers;
desc.Texture2DMSArray.FirstArraySlice = 0;
}
else
{
desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
desc.Texture2DArray.ArraySize = depth_attachment->GetConfig().layers;
desc.Texture2DArray.FirstArraySlice = 0;
desc.Texture2DArray.MipSlice = 0;
}
HRESULT hr = D3D::device->CreateDepthStencilView(
depth_attachment->GetRawTexIdentifier()->GetTex(), &desc, &dsv);
const CD3D11_DEPTH_STENCIL_VIEW_DESC desc(
depth_attachment->GetConfig().IsMultisampled() ? D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY :
D3D11_DSV_DIMENSION_TEXTURE2DARRAY,
GetDSVFormatForHostFormat(depth_attachment->GetFormat()), 0, 0,
depth_attachment->GetLayers(), 0);
HRESULT hr =
D3D::device->CreateDepthStencilView(depth_attachment->GetD3DTexture(), &desc, &dsv);
CHECK(SUCCEEDED(hr), "Create depth stencil view for framebuffer");
}
return std::make_unique<DXFramebuffer>(color_format, depth_format, width, height, layers, samples,
rtv, dsv);
return std::make_unique<DXFramebuffer>(color_attachment, depth_attachment, color_format,
depth_format, width, height, layers, samples, rtv,
integer_rtv, dsv);
}
} // namespace DX11

View File

@ -4,6 +4,7 @@
#pragma once
#include <d3d11.h>
#include <memory>
#include "Common/CommonTypes.h"
@ -11,32 +12,34 @@
#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 @@ private:
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;
};

View File

@ -1,303 +0,0 @@
// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "VideoBackends/D3D/FramebufferManager.h"
#include <memory>
#include <utility>
#include "Common/CommonTypes.h"
#include "Core/HW/Memmap.h"
#include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DState.h"
#include "VideoBackends/D3D/D3DUtil.h"
#include "VideoBackends/D3D/GeometryShaderCache.h"
#include "VideoBackends/D3D/PixelShaderCache.h"
#include "VideoBackends/D3D/Render.h"
#include "VideoBackends/D3D/VertexShaderCache.h"
#include "VideoCommon/VideoConfig.h"
namespace DX11
{
static bool s_integer_efb_render_target = false;
FramebufferManager::Efb FramebufferManager::m_efb;
unsigned int FramebufferManager::m_target_width;
unsigned int FramebufferManager::m_target_height;
D3DTexture2D*& FramebufferManager::GetEFBColorTexture()
{
return m_efb.color_tex;
}
D3DTexture2D*& FramebufferManager::GetEFBColorReadTexture()
{
return m_efb.color_read_texture;
}
ID3D11Texture2D*& FramebufferManager::GetEFBColorStagingBuffer()
{
return m_efb.color_staging_buf;
}
D3DTexture2D*& FramebufferManager::GetEFBDepthTexture()
{
return m_efb.depth_tex;
}
D3DTexture2D*& FramebufferManager::GetEFBDepthReadTexture()
{
return m_efb.depth_read_texture;
}
ID3D11Texture2D*& FramebufferManager::GetEFBDepthStagingBuffer()
{
return m_efb.depth_staging_buf;
}
D3DTexture2D*& FramebufferManager::GetResolvedEFBColorTexture()
{
if (g_ActiveConfig.iMultisamples > 1)
{
for (int i = 0; i < m_efb.slices; i++)
D3D::context->ResolveSubresource(m_efb.resolved_color_tex->GetTex(),
D3D11CalcSubresource(0, i, 1), m_efb.color_tex->GetTex(),
D3D11CalcSubresource(0, i, 1), DXGI_FORMAT_R8G8B8A8_UNORM);
return m_efb.resolved_color_tex;
}
else
{
return m_efb.color_tex;
}
}
D3DTexture2D*& FramebufferManager::GetResolvedEFBDepthTexture()
{
if (g_ActiveConfig.iMultisamples > 1)
{
// ResolveSubresource does not work with depth textures.
// Instead, we use a shader that selects the minimum depth from all samples.
g_renderer->ResetAPIState();
CD3D11_VIEWPORT viewport(0.f, 0.f, (float)m_target_width, (float)m_target_height);
D3D::context->RSSetViewports(1, &viewport);
D3D::context->OMSetRenderTargets(1, &m_efb.resolved_depth_tex->GetRTV(), nullptr);
const D3D11_RECT source_rect = CD3D11_RECT(0, 0, m_target_width, m_target_height);
D3D::drawShadedTexQuad(
m_efb.depth_tex->GetSRV(), &source_rect, m_target_width, m_target_height,
PixelShaderCache::GetDepthResolveProgram(), VertexShaderCache::GetSimpleVertexShader(),
VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader());
g_renderer->RestoreAPIState();
return m_efb.resolved_depth_tex;
}
else
{
return m_efb.depth_tex;
}
}
void FramebufferManager::SwapReinterpretTexture()
{
std::swap(m_efb.color_tex, m_efb.color_temp_tex);
std::swap(m_efb.color_int_rtv, m_efb.color_temp_int_rtv);
}
void FramebufferManager::SetIntegerEFBRenderTarget(bool enabled)
{
if (s_integer_efb_render_target == enabled)
return;
// We only use UINT render targets for logic ops, which is only supported with D3D11.1.
if (!D3D::device1)
return;
s_integer_efb_render_target = enabled;
BindEFBRenderTarget();
}
void FramebufferManager::BindEFBRenderTarget(bool bind_depth)
{
ID3D11RenderTargetView* rtv =
s_integer_efb_render_target ? m_efb.color_int_rtv : m_efb.color_tex->GetRTV();
ID3D11DepthStencilView* dsv = bind_depth ? m_efb.depth_tex->GetDSV() : nullptr;
D3D::context->OMSetRenderTargets(1, &rtv, dsv);
}
FramebufferManager::FramebufferManager(int target_width, int target_height)
{
static constexpr std::array<float, 4> clear_color = {0.0f, 0.0f, 0.0f, 1.0f};
m_target_width = static_cast<unsigned int>(std::max(target_width, 1));
m_target_height = static_cast<unsigned int>(std::max(target_height, 1));
DXGI_SAMPLE_DESC sample_desc;
sample_desc.Count = g_ActiveConfig.iMultisamples;
sample_desc.Quality = 0;
ID3D11Texture2D* buf;
D3D11_TEXTURE2D_DESC texdesc;
HRESULT hr;
m_EFBLayers = m_efb.slices = (g_ActiveConfig.stereo_mode != StereoMode::Off) ? 2 : 1;
// EFB color texture - primary render target
texdesc =
CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_TYPELESS, m_target_width, m_target_height,
m_efb.slices, 1, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET,
D3D11_USAGE_DEFAULT, 0, sample_desc.Count, sample_desc.Quality);
hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf);
CHECK(hr == S_OK, "create EFB color texture (size: %dx%d; hr=%#x)", m_target_width,
m_target_height, hr);
m_efb.color_tex = new D3DTexture2D(
buf, (D3D11_BIND_FLAG)(D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET),
DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM,
(sample_desc.Count > 1));
SAFE_RELEASE(buf);
D3D::SetDebugObjectName(m_efb.color_tex->GetTex(), "EFB color texture");
D3D::SetDebugObjectName(m_efb.color_tex->GetSRV(), "EFB color texture shader resource view");
D3D::SetDebugObjectName(m_efb.color_tex->GetRTV(), "EFB color texture render target view");
D3D::context->ClearRenderTargetView(m_efb.color_tex->GetRTV(), clear_color.data());
// Temporary EFB color texture - used in ReinterpretPixelData
texdesc =
CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_TYPELESS, m_target_width, m_target_height,
m_efb.slices, 1, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET,
D3D11_USAGE_DEFAULT, 0, sample_desc.Count, sample_desc.Quality);
hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf);
CHECK(hr == S_OK, "create EFB color temp texture (size: %dx%d; hr=%#x)", m_target_width,
m_target_height, hr);
m_efb.color_temp_tex = new D3DTexture2D(
buf, (D3D11_BIND_FLAG)(D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET),
DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM,
(sample_desc.Count > 1));
SAFE_RELEASE(buf);
D3D::SetDebugObjectName(m_efb.color_temp_tex->GetTex(), "EFB color temp texture");
D3D::SetDebugObjectName(m_efb.color_temp_tex->GetSRV(),
"EFB color temp texture shader resource view");
D3D::SetDebugObjectName(m_efb.color_temp_tex->GetRTV(),
"EFB color temp texture render target view");
D3D::context->ClearRenderTargetView(m_efb.color_temp_tex->GetRTV(), clear_color.data());
// Integer render targets for EFB, used for logic op
CD3D11_RENDER_TARGET_VIEW_DESC int_rtv_desc(m_efb.color_tex->GetTex(),
g_ActiveConfig.iMultisamples > 1 ?
D3D11_RTV_DIMENSION_TEXTURE2DMS :
D3D11_RTV_DIMENSION_TEXTURE2D,
DXGI_FORMAT_R8G8B8A8_UINT);
hr = D3D::device->CreateRenderTargetView(m_efb.color_tex->GetTex(), &int_rtv_desc,
&m_efb.color_int_rtv);
CHECK(hr == S_OK, "create EFB integer RTV(hr=%#x)", hr);
hr = D3D::device->CreateRenderTargetView(m_efb.color_temp_tex->GetTex(), &int_rtv_desc,
&m_efb.color_temp_int_rtv);
CHECK(hr == S_OK, "create EFB integer RTV(hr=%#x)", hr);
// Render buffer for AccessEFB (color data)
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, 1, 1, D3D11_BIND_RENDER_TARGET);
hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf);
CHECK(hr == S_OK, "create EFB color read texture (hr=%#x)", hr);
m_efb.color_read_texture = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET);
SAFE_RELEASE(buf);
D3D::SetDebugObjectName(m_efb.color_read_texture->GetTex(),
"EFB color read texture (used in Renderer::AccessEFB)");
D3D::SetDebugObjectName(
m_efb.color_read_texture->GetRTV(),
"EFB color read texture render target view (used in Renderer::AccessEFB)");
// AccessEFB - Sysmem buffer used to retrieve the pixel data from depth_read_texture
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, 1, 1, 0, D3D11_USAGE_STAGING,
D3D11_CPU_ACCESS_READ);
hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &m_efb.color_staging_buf);
CHECK(hr == S_OK, "create EFB color staging buffer (hr=%#x)", hr);
D3D::SetDebugObjectName(m_efb.color_staging_buf,
"EFB color staging texture (used for Renderer::AccessEFB)");
// EFB depth buffer - primary depth buffer
texdesc =
CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_TYPELESS, m_target_width, m_target_height, m_efb.slices,
1, D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE,
D3D11_USAGE_DEFAULT, 0, sample_desc.Count, sample_desc.Quality);
hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf);
CHECK(hr == S_OK, "create EFB depth texture (size: %dx%d; hr=%#x)", m_target_width,
m_target_height, hr);
m_efb.depth_tex = new D3DTexture2D(
buf, (D3D11_BIND_FLAG)(D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE),
DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_D32_FLOAT, DXGI_FORMAT_UNKNOWN, (sample_desc.Count > 1));
SAFE_RELEASE(buf);
D3D::SetDebugObjectName(m_efb.depth_tex->GetTex(), "EFB depth texture");
D3D::SetDebugObjectName(m_efb.depth_tex->GetDSV(), "EFB depth texture depth stencil view");
D3D::SetDebugObjectName(m_efb.depth_tex->GetSRV(), "EFB depth texture shader resource view");
D3D::context->ClearDepthStencilView(m_efb.depth_tex->GetDSV(), D3D11_CLEAR_DEPTH, 0.0f, 0);
// Render buffer for AccessEFB (depth data)
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_FLOAT, 1, 1, 1, 1, D3D11_BIND_RENDER_TARGET);
hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf);
CHECK(hr == S_OK, "create EFB depth read texture (hr=%#x)", hr);
m_efb.depth_read_texture = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET);
SAFE_RELEASE(buf);
D3D::SetDebugObjectName(m_efb.depth_read_texture->GetTex(),
"EFB depth read texture (used in Renderer::AccessEFB)");
D3D::SetDebugObjectName(
m_efb.depth_read_texture->GetRTV(),
"EFB depth read texture render target view (used in Renderer::AccessEFB)");
// AccessEFB - Sysmem buffer used to retrieve the pixel data from depth_read_texture
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_FLOAT, 1, 1, 1, 1, 0, D3D11_USAGE_STAGING,
D3D11_CPU_ACCESS_READ);
hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &m_efb.depth_staging_buf);
CHECK(hr == S_OK, "create EFB depth staging buffer (hr=%#x)", hr);
D3D::SetDebugObjectName(m_efb.depth_staging_buf,
"EFB depth staging texture (used for Renderer::AccessEFB)");
if (g_ActiveConfig.iMultisamples > 1)
{
// Framebuffer resolve textures (color+depth)
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, m_target_width, m_target_height,
m_efb.slices, 1, D3D11_BIND_SHADER_RESOURCE,
D3D11_USAGE_DEFAULT, 0, 1);
hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf);
CHECK(hr == S_OK, "create EFB color resolve texture (size: %dx%d; hr=%#x)", m_target_width,
m_target_height, hr);
m_efb.resolved_color_tex =
new D3DTexture2D(buf, D3D11_BIND_SHADER_RESOURCE, DXGI_FORMAT_R8G8B8A8_UNORM);
SAFE_RELEASE(buf);
D3D::SetDebugObjectName(m_efb.resolved_color_tex->GetTex(), "EFB color resolve texture");
D3D::SetDebugObjectName(m_efb.resolved_color_tex->GetSRV(),
"EFB color resolve texture shader resource view");
texdesc =
CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_FLOAT, m_target_width, m_target_height, m_efb.slices,
1, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf);
CHECK(hr == S_OK, "create EFB depth resolve texture (size: %dx%d; hr=%#x)", m_target_width,
m_target_height, hr);
m_efb.resolved_depth_tex = new D3DTexture2D(
buf, (D3D11_BIND_FLAG)(D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET),
DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R32_FLOAT);
SAFE_RELEASE(buf);
D3D::SetDebugObjectName(m_efb.resolved_depth_tex->GetTex(), "EFB depth resolve texture");
D3D::SetDebugObjectName(m_efb.resolved_depth_tex->GetSRV(),
"EFB depth resolve texture shader resource view");
}
else
{
m_efb.resolved_color_tex = nullptr;
m_efb.resolved_depth_tex = nullptr;
}
s_integer_efb_render_target = false;
}
FramebufferManager::~FramebufferManager()
{
SAFE_RELEASE(m_efb.color_tex);
SAFE_RELEASE(m_efb.color_int_rtv);
SAFE_RELEASE(m_efb.color_temp_tex);
SAFE_RELEASE(m_efb.color_temp_int_rtv);
SAFE_RELEASE(m_efb.color_staging_buf);
SAFE_RELEASE(m_efb.color_read_texture);
SAFE_RELEASE(m_efb.resolved_color_tex);
SAFE_RELEASE(m_efb.depth_tex);
SAFE_RELEASE(m_efb.depth_staging_buf);
SAFE_RELEASE(m_efb.depth_read_texture);
SAFE_RELEASE(m_efb.resolved_depth_tex);
}
} // namespace DX11

View File

@ -1,96 +0,0 @@
// Copyright 2009 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <d3d11.h>
#include <memory>
#include <utility>
#include "Common/CommonTypes.h"
#include "VideoBackends/D3D/D3DTexture.h"
#include "VideoCommon/FramebufferManagerBase.h"
namespace DX11
{
// On the GameCube, the game sends a request for the graphics processor to
// transfer its internal EFB (Embedded Framebuffer) to an area in GameCube RAM
// called the XFB (External Framebuffer). The size and location of the XFB is
// decided at the time of the copy, and the format is always YUYV. The video
// interface is given a pointer to the XFB, which will be decoded and
// displayed on the TV.
//
// There are two ways for Dolphin to emulate this:
//
// Real XFB mode:
//
// Dolphin will behave like the GameCube and encode the EFB to
// a portion of GameCube RAM. The emulated video interface will decode the data
// for output to the screen.
//
// Advantages: Behaves exactly like the GameCube.
// Disadvantages: Resolution will be limited.
//
// Virtual XFB mode:
//
// When a request is made to copy the EFB to an XFB, Dolphin
// will remember the RAM location and size of the XFB in a Virtual XFB list.
// The video interface will look up the XFB in the list and use the enhanced
// data stored there, if available.
//
// Advantages: Enables high resolution graphics, better than real hardware.
// Disadvantages: If the GameCube CPU writes directly to the XFB (which is
// possible but uncommon), the Virtual XFB will not capture this information.
// There may be multiple XFBs in GameCube RAM. This is the maximum number to
// virtualize.
class FramebufferManager : public FramebufferManagerBase
{
public:
FramebufferManager(int target_width, int target_height);
~FramebufferManager();
static D3DTexture2D*& GetEFBColorTexture();
static D3DTexture2D*& GetEFBColorReadTexture();
static ID3D11Texture2D*& GetEFBColorStagingBuffer();
static D3DTexture2D*& GetEFBDepthTexture();
static D3DTexture2D*& GetEFBDepthReadTexture();
static ID3D11Texture2D*& GetEFBDepthStagingBuffer();
static D3DTexture2D*& GetResolvedEFBColorTexture();
static D3DTexture2D*& GetResolvedEFBDepthTexture();
static D3DTexture2D*& GetEFBColorTempTexture() { return m_efb.color_temp_tex; }
static void SwapReinterpretTexture();
static void SetIntegerEFBRenderTarget(bool enabled);
static void BindEFBRenderTarget(bool bind_depth = true);
private:
static struct Efb
{
D3DTexture2D* color_tex;
ID3D11RenderTargetView* color_int_rtv;
ID3D11Texture2D* color_staging_buf;
D3DTexture2D* color_read_texture;
D3DTexture2D* depth_tex;
ID3D11Texture2D* depth_staging_buf;
D3DTexture2D* depth_read_texture;
D3DTexture2D* color_temp_tex;
ID3D11RenderTargetView* color_temp_int_rtv;
D3DTexture2D* resolved_color_tex;
D3DTexture2D* resolved_depth_tex;
int slices;
} m_efb;
static unsigned int m_target_width;
static unsigned int m_target_height;
};
} // namespace DX11

View File

@ -1,113 +0,0 @@
// Copyright 2014 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <string>
#include "Common/FileUtil.h"
#include "Common/StringUtil.h"
#include "Core/ConfigManager.h"
#include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DShader.h"
#include "VideoBackends/D3D/D3DState.h"
#include "VideoBackends/D3D/FramebufferManager.h"
#include "VideoBackends/D3D/GeometryShaderCache.h"
#include "VideoCommon/Debugger.h"
#include "VideoCommon/GeometryShaderGen.h"
#include "VideoCommon/VideoConfig.h"
namespace DX11
{
ID3D11GeometryShader* ClearGeometryShader = nullptr;
ID3D11GeometryShader* CopyGeometryShader = nullptr;
ID3D11GeometryShader* GeometryShaderCache::GetClearGeometryShader()
{
return (g_ActiveConfig.stereo_mode != StereoMode::Off) ? ClearGeometryShader : nullptr;
}
ID3D11GeometryShader* GeometryShaderCache::GetCopyGeometryShader()
{
return (g_ActiveConfig.stereo_mode != StereoMode::Off) ? CopyGeometryShader : nullptr;
}
const char clear_shader_code[] = {
"struct VSOUTPUT\n"
"{\n"
" float4 vPosition : POSITION;\n"
" float4 vColor0 : COLOR0;\n"
"};\n"
"struct GSOUTPUT\n"
"{\n"
" float4 vPosition : POSITION;\n"
" float4 vColor0 : COLOR0;\n"
" uint slice : SV_RenderTargetArrayIndex;\n"
"};\n"
"[maxvertexcount(6)]\n"
"void main(triangle VSOUTPUT o[3], inout TriangleStream<GSOUTPUT> Output)\n"
"{\n"
"for(int slice = 0; slice < 2; slice++)\n"
"{\n"
" for(int i = 0; i < 3; i++)\n"
" {\n"
" GSOUTPUT OUT;\n"
" OUT.vPosition = o[i].vPosition;\n"
" OUT.vColor0 = o[i].vColor0;\n"
" OUT.slice = slice;\n"
" Output.Append(OUT);\n"
" }\n"
" Output.RestartStrip();\n"
"}\n"
"}\n"};
const char copy_shader_code[] = {
"struct VSOUTPUT\n"
"{\n"
" float4 vPosition : POSITION;\n"
" float3 vTexCoord : TEXCOORD0;\n"
"};\n"
"struct GSOUTPUT\n"
"{\n"
" float4 vPosition : POSITION;\n"
" float3 vTexCoord : TEXCOORD0;\n"
" uint slice : SV_RenderTargetArrayIndex;\n"
"};\n"
"[maxvertexcount(6)]\n"
"void main(triangle VSOUTPUT o[3], inout TriangleStream<GSOUTPUT> Output)\n"
"{\n"
"for(int slice = 0; slice < 2; slice++)\n"
"{\n"
" for(int i = 0; i < 3; i++)\n"
" {\n"
" GSOUTPUT OUT;\n"
" OUT.vPosition = o[i].vPosition;\n"
" OUT.vTexCoord = o[i].vTexCoord;\n"
" OUT.vTexCoord.z = float(slice);\n"
" OUT.slice = slice;\n"
" Output.Append(OUT);\n"
" }\n"
" Output.RestartStrip();\n"
"}\n"
"}\n"};
void GeometryShaderCache::Init()
{
// used when drawing clear quads
ClearGeometryShader = D3D::CompileAndCreateGeometryShader(clear_shader_code);
CHECK(ClearGeometryShader != nullptr, "Create clear geometry shader");
D3D::SetDebugObjectName(ClearGeometryShader, "clear geometry shader");
// used for buffer copy
CopyGeometryShader = D3D::CompileAndCreateGeometryShader(copy_shader_code);
CHECK(CopyGeometryShader != nullptr, "Create copy geometry shader");
D3D::SetDebugObjectName(CopyGeometryShader, "copy geometry shader");
}
void GeometryShaderCache::Shutdown()
{
SAFE_RELEASE(ClearGeometryShader);
SAFE_RELEASE(CopyGeometryShader);
}
} // DX11

View File

@ -1,27 +0,0 @@
// Copyright 2014 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <d3d11.h>
#include <map>
#include "VideoCommon/GeometryShaderGen.h"
namespace DX11
{
class GeometryShaderCache
{
public:
static void Init();
static void Shutdown();
static ID3D11GeometryShader* GetClearGeometryShader();
static ID3D11GeometryShader* GetCopyGeometryShader();
static ID3D11Buffer* GetConstantBuffer();
static void UpdateConstantBuffer(const void* data, u32 data_size);
};
} // namespace DX11

View File

@ -5,10 +5,10 @@
#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
@ -16,7 +16,7 @@ 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,7 +150,7 @@ 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.
@ -158,8 +158,8 @@ ID3D11InputLayout* D3DVertexFormat::GetInputLayout(D3DBlob* vs_bytecode)
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");

View File

@ -1,160 +0,0 @@
// Copyright 2011 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "VideoBackends/D3D/PSTextureEncoder.h"
#include "Common/Assert.h"
#include "Common/Logging/Log.h"
#include "Core/HW/Memmap.h"
#include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DShader.h"
#include "VideoBackends/D3D/D3DState.h"
#include "VideoBackends/D3D/D3DUtil.h"
#include "VideoBackends/D3D/DXTexture.h"
#include "VideoBackends/D3D/FramebufferManager.h"
#include "VideoBackends/D3D/Render.h"
#include "VideoBackends/D3D/TextureCache.h"
#include "VideoBackends/D3D/VertexShaderCache.h"
#include "VideoCommon/AbstractStagingTexture.h"
#include "VideoCommon/AbstractTexture.h"
#include "VideoCommon/TextureConversionShader.h"
#include "VideoCommon/VideoCommon.h"
namespace DX11
{
struct EFBEncodeParams
{
s32 SrcLeft;
s32 SrcTop;
u32 DestWidth;
u32 ScaleFactor;
float y_scale;
float gamma_rcp;
float clamp_top;
float clamp_bottom;
float filter_coefficients[3];
u32 padding;
};
PSTextureEncoder::PSTextureEncoder()
{
}
PSTextureEncoder::~PSTextureEncoder() = default;
void PSTextureEncoder::Init()
{
m_encoding_render_texture = g_renderer->CreateTexture(TextureCache::GetEncodingTextureConfig());
ASSERT(m_encoding_render_texture);
// Create constant buffer for uploading data to shaders
D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(EFBEncodeParams), D3D11_BIND_CONSTANT_BUFFER);
HRESULT hr = D3D::device->CreateBuffer(&bd, nullptr, &m_encode_params);
CHECK(SUCCEEDED(hr), "create efb encode params buffer");
D3D::SetDebugObjectName(m_encode_params, "efb encoder params buffer");
}
void PSTextureEncoder::Shutdown()
{
for (auto& it : m_encoding_shaders)
SAFE_RELEASE(it.second);
m_encoding_shaders.clear();
SAFE_RELEASE(m_encode_params);
}
void PSTextureEncoder::Encode(
AbstractStagingTexture* dst, const EFBCopyParams& params, u32 native_width, u32 bytes_per_row,
u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect, bool scale_by_half,
float y_scale, float gamma, bool clamp_top, bool clamp_bottom,
const TextureCacheBase::CopyFilterCoefficientArray& filter_coefficients)
{
// Resolve MSAA targets before copying.
// FIXME: Instead of resolving EFB, it would be better to pick out a
// single sample from each pixel. The game may break if it isn't
// expecting the blurred edges around multisampled shapes.
ID3D11ShaderResourceView* pEFB = params.depth ?
FramebufferManager::GetResolvedEFBDepthTexture()->GetSRV() :
FramebufferManager::GetResolvedEFBColorTexture()->GetSRV();
// Reset API
g_renderer->ResetAPIState();
// Set up all the state for EFB encoding
{
const u32 words_per_row = bytes_per_row / sizeof(u32);
D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, FLOAT(words_per_row), FLOAT(num_blocks_y));
D3D::context->RSSetViewports(1, &vp);
constexpr EFBRectangle fullSrcRect(0, 0, EFB_WIDTH, EFB_HEIGHT);
TargetRectangle targetRect = g_renderer->ConvertEFBRectangle(fullSrcRect);
D3D::context->OMSetRenderTargets(
1,
&static_cast<DXTexture*>(m_encoding_render_texture.get())->GetRawTexIdentifier()->GetRTV(),
nullptr);
EFBEncodeParams encode_params;
encode_params.SrcLeft = src_rect.left;
encode_params.SrcTop = src_rect.top;
encode_params.DestWidth = native_width;
encode_params.ScaleFactor = scale_by_half ? 2 : 1;
encode_params.y_scale = y_scale;
encode_params.gamma_rcp = 1.0f / gamma;
encode_params.clamp_top = clamp_top ? src_rect.top / float(EFB_HEIGHT) : 0.0f;
encode_params.clamp_bottom = clamp_bottom ? src_rect.bottom / float(EFB_HEIGHT) : 1.0f;
for (size_t i = 0; i < filter_coefficients.size(); i++)
encode_params.filter_coefficients[i] = filter_coefficients[i];
D3D::context->UpdateSubresource(m_encode_params, 0, nullptr, &encode_params, 0, 0);
D3D::stateman->SetPixelConstants(m_encode_params);
// We also linear filtering for both box filtering and downsampling higher resolutions to 1x
// TODO: This only produces perfect downsampling for 2x IR, other resolutions will need more
// complex down filtering to average all pixels and produce the correct result.
// Also, box filtering won't be correct for anything other than 1x IR
if (scale_by_half || g_renderer->GetEFBScale() != 1 || y_scale > 1.0f)
D3D::SetLinearCopySampler();
else
D3D::SetPointCopySampler();
D3D::drawShadedTexQuad(pEFB, targetRect.AsRECT(), g_renderer->GetTargetWidth(),
g_renderer->GetTargetHeight(), GetEncodingPixelShader(params),
VertexShaderCache::GetSimpleVertexShader(),
VertexShaderCache::GetSimpleInputLayout());
// Copy to staging buffer
MathUtil::Rectangle<int> copy_rect(0, 0, words_per_row, num_blocks_y);
dst->CopyFromTexture(m_encoding_render_texture.get(), copy_rect, 0, 0, copy_rect);
}
g_renderer->RestoreAPIState();
}
ID3D11PixelShader* PSTextureEncoder::GetEncodingPixelShader(const EFBCopyParams& params)
{
auto iter = m_encoding_shaders.find(params);
if (iter != m_encoding_shaders.end())
return iter->second;
D3DBlob* bytecode = nullptr;
const char* shader = TextureConversionShaderTiled::GenerateEncodingShader(params, APIType::D3D);
if (!D3D::CompilePixelShader(shader, &bytecode))
{
PanicAlert("Failed to compile texture encoding shader.");
m_encoding_shaders[params] = nullptr;
return nullptr;
}
ID3D11PixelShader* newShader;
HRESULT hr =
D3D::device->CreatePixelShader(bytecode->Data(), bytecode->Size(), nullptr, &newShader);
CHECK(SUCCEEDED(hr), "create efb encoder pixel shader");
m_encoding_shaders.emplace(params, newShader);
return newShader;
}
} // namespace DX11

View File

@ -1,53 +0,0 @@
// Copyright 2011 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <map>
#include <memory>
#include "Common/CommonTypes.h"
#include "VideoCommon/TextureCacheBase.h"
#include "VideoCommon/TextureConversionShader.h"
#include "VideoCommon/VideoCommon.h"
class AbstractTexture;
class AbstractStagingTexture;
struct ID3D11Texture2D;
struct ID3D11RenderTargetView;
struct ID3D11Buffer;
struct ID3D11InputLayout;
struct ID3D11VertexShader;
struct ID3D11PixelShader;
struct ID3D11ClassLinkage;
struct ID3D11ClassInstance;
struct ID3D11BlendState;
struct ID3D11DepthStencilState;
struct ID3D11RasterizerState;
struct ID3D11SamplerState;
namespace DX11
{
class PSTextureEncoder final
{
public:
PSTextureEncoder();
~PSTextureEncoder();
void Init();
void Shutdown();
void Encode(AbstractStagingTexture* dst, const EFBCopyParams& params, u32 native_width,
u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect,
bool scale_by_half, float y_scale, float gamma, bool clamp_top, bool clamp_bottom,
const TextureCacheBase::CopyFilterCoefficientArray& filter_coefficients);
private:
ID3D11PixelShader* GetEncodingPixelShader(const EFBCopyParams& params);
ID3D11Buffer* m_encode_params = nullptr;
std::unique_ptr<AbstractTexture> m_encoding_render_texture;
std::map<EFBCopyParams, ID3D11PixelShader*> m_encoding_shaders;
};
}

View File

@ -1,315 +0,0 @@
// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <string>
#include "Common/CommonTypes.h"
#include "Common/FileUtil.h"
#include "Common/MsgHandler.h"
#include "Common/StringUtil.h"
#include "Core/ConfigManager.h"
#include "Core/Host.h"
#include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DShader.h"
#include "VideoBackends/D3D/D3DState.h"
#include "VideoBackends/D3D/PixelShaderCache.h"
#include "VideoCommon/Debugger.h"
#include "VideoCommon/PixelShaderGen.h"
#include "VideoCommon/VideoConfig.h"
namespace DX11
{
ID3D11PixelShader* s_ColorCopyProgram[2] = {nullptr};
ID3D11PixelShader* s_ClearProgram = nullptr;
ID3D11PixelShader* s_AnaglyphProgram = nullptr;
ID3D11PixelShader* s_DepthResolveProgram = nullptr;
ID3D11PixelShader* s_rgba6_to_rgb8[2] = {nullptr};
ID3D11PixelShader* s_rgb8_to_rgba6[2] = {nullptr};
const char clear_program_code[] = {"void main(\n"
"out float4 ocol0 : SV_Target,\n"
"in float4 pos : SV_Position,\n"
"in float4 incol0 : COLOR0){\n"
"ocol0 = incol0;\n"
"}\n"};
// TODO: Find some way to avoid having separate shaders for non-MSAA and MSAA...
const char color_copy_program_code[] = {"sampler samp0 : register(s0);\n"
"Texture2DArray Tex0 : register(t0);\n"
"void main(\n"
"out float4 ocol0 : SV_Target,\n"
"in float4 pos : SV_Position,\n"
"in float3 uv0 : TEXCOORD0){\n"
"ocol0 = Tex0.Sample(samp0,uv0);\n"
"}\n"};
// Anaglyph Red-Cyan shader based on Dubois algorithm
// Constants taken from the paper:
// "Conversion of a Stereo Pair to Anaglyph with
// the Least-Squares Projection Method"
// Eric Dubois, March 2009
const char anaglyph_program_code[] = {"sampler samp0 : register(s0);\n"
"Texture2DArray Tex0 : register(t0);\n"
"void main(\n"
"out float4 ocol0 : SV_Target,\n"
"in float4 pos : SV_Position,\n"
"in float3 uv0 : TEXCOORD0){\n"
"float4 c0 = Tex0.Sample(samp0, float3(uv0.xy, 0.0));\n"
"float4 c1 = Tex0.Sample(samp0, float3(uv0.xy, 1.0));\n"
"float3x3 l = float3x3( 0.437, 0.449, 0.164,\n"
" -0.062,-0.062,-0.024,\n"
" -0.048,-0.050,-0.017);\n"
"float3x3 r = float3x3(-0.011,-0.032,-0.007,\n"
" 0.377, 0.761, 0.009,\n"
" -0.026,-0.093, 1.234);\n"
"ocol0 = float4(mul(l, c0.rgb) + mul(r, c1.rgb), c0.a);\n"
"}\n"};
// TODO: Improve sampling algorithm!
const char color_copy_program_code_msaa[] = {
"#define SAMPLES %d\n"
"sampler samp0 : register(s0);\n"
"Texture2DMSArray<float4, SAMPLES> Tex0 : register(t0);\n"
"void main(\n"
"out float4 ocol0 : SV_Target,\n"
"in float4 pos : SV_Position,\n"
"in float3 uv0 : TEXCOORD0){\n"
"int width, height, slices, samples;\n"
"Tex0.GetDimensions(width, height, slices, samples);\n"
"ocol0 = 0;\n"
"for(int i = 0; i < SAMPLES; ++i)\n"
" ocol0 += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n"
"ocol0 /= SAMPLES;\n"
"}\n"};
const char depth_resolve_program[] = {
"#define SAMPLES %d\n"
"Texture2DMSArray<float4, SAMPLES> Tex0 : register(t0);\n"
"void main(\n"
" out float ocol0 : SV_Target,\n"
" in float4 pos : SV_Position,\n"
" in float3 uv0 : TEXCOORD0)\n"
"{\n"
" int width, height, slices, samples;\n"
" Tex0.GetDimensions(width, height, slices, samples);\n"
" ocol0 = Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), 0).x;\n"
" for(int i = 1; i < SAMPLES; ++i)\n"
" ocol0 = min(ocol0, Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i).x);\n"
"}\n"};
const char reint_rgba6_to_rgb8[] = {"sampler samp0 : register(s0);\n"
"Texture2DArray Tex0 : register(t0);\n"
"void main(\n"
" out float4 ocol0 : SV_Target,\n"
" in float4 pos : SV_Position,\n"
" in float3 uv0 : TEXCOORD0)\n"
"{\n"
" int4 src6 = round(Tex0.Sample(samp0,uv0) * 63.f);\n"
" int4 dst8;\n"
" dst8.r = (src6.r << 2) | (src6.g >> 4);\n"
" dst8.g = ((src6.g & 0xF) << 4) | (src6.b >> 2);\n"
" dst8.b = ((src6.b & 0x3) << 6) | src6.a;\n"
" dst8.a = 255;\n"
" ocol0 = (float4)dst8 / 255.f;\n"
"}"};
const char reint_rgba6_to_rgb8_msaa[] = {
"#define SAMPLES %d\n"
"sampler samp0 : register(s0);\n"
"Texture2DMSArray<float4, SAMPLES> Tex0 : register(t0);\n"
"void main(\n"
" out float4 ocol0 : SV_Target,\n"
" in float4 pos : SV_Position,\n"
" in float3 uv0 : TEXCOORD0)\n"
"{\n"
" int width, height, slices, samples;\n"
" Tex0.GetDimensions(width, height, slices, samples);\n"
" float4 texcol = 0;\n"
" for (int i = 0; i < SAMPLES; ++i)\n"
" texcol += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n"
" texcol /= SAMPLES;\n"
" int4 src6 = round(texcol * 63.f);\n"
" int4 dst8;\n"
" dst8.r = (src6.r << 2) | (src6.g >> 4);\n"
" dst8.g = ((src6.g & 0xF) << 4) | (src6.b >> 2);\n"
" dst8.b = ((src6.b & 0x3) << 6) | src6.a;\n"
" dst8.a = 255;\n"
" ocol0 = (float4)dst8 / 255.f;\n"
"}"};
const char reint_rgb8_to_rgba6[] = {"sampler samp0 : register(s0);\n"
"Texture2DArray Tex0 : register(t0);\n"
"void main(\n"
" out float4 ocol0 : SV_Target,\n"
" in float4 pos : SV_Position,\n"
" in float3 uv0 : TEXCOORD0)\n"
"{\n"
" int4 src8 = round(Tex0.Sample(samp0,uv0) * 255.f);\n"
" int4 dst6;\n"
" dst6.r = src8.r >> 2;\n"
" dst6.g = ((src8.r & 0x3) << 4) | (src8.g >> 4);\n"
" dst6.b = ((src8.g & 0xF) << 2) | (src8.b >> 6);\n"
" dst6.a = src8.b & 0x3F;\n"
" ocol0 = (float4)dst6 / 63.f;\n"
"}\n"};
const char reint_rgb8_to_rgba6_msaa[] = {
"#define SAMPLES %d\n"
"sampler samp0 : register(s0);\n"
"Texture2DMSArray<float4, SAMPLES> Tex0 : register(t0);\n"
"void main(\n"
" out float4 ocol0 : SV_Target,\n"
" in float4 pos : SV_Position,\n"
" in float3 uv0 : TEXCOORD0)\n"
"{\n"
" int width, height, slices, samples;\n"
" Tex0.GetDimensions(width, height, slices, samples);\n"
" float4 texcol = 0;\n"
" for (int i = 0; i < SAMPLES; ++i)\n"
" texcol += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n"
" texcol /= SAMPLES;\n"
" int4 src8 = round(texcol * 255.f);\n"
" int4 dst6;\n"
" dst6.r = src8.r >> 2;\n"
" dst6.g = ((src8.r & 0x3) << 4) | (src8.g >> 4);\n"
" dst6.b = ((src8.g & 0xF) << 2) | (src8.b >> 6);\n"
" dst6.a = src8.b & 0x3F;\n"
" ocol0 = (float4)dst6 / 63.f;\n"
"}\n"};
ID3D11PixelShader* PixelShaderCache::ReinterpRGBA6ToRGB8(bool multisampled)
{
if (!multisampled || g_ActiveConfig.iMultisamples <= 1)
{
if (!s_rgba6_to_rgb8[0])
{
s_rgba6_to_rgb8[0] = D3D::CompileAndCreatePixelShader(reint_rgba6_to_rgb8);
CHECK(s_rgba6_to_rgb8[0], "Create RGBA6 to RGB8 pixel shader");
D3D::SetDebugObjectName(s_rgba6_to_rgb8[0], "RGBA6 to RGB8 pixel shader");
}
return s_rgba6_to_rgb8[0];
}
else if (!s_rgba6_to_rgb8[1])
{
// create MSAA shader for current AA mode
std::string buf = StringFromFormat(reint_rgba6_to_rgb8_msaa, g_ActiveConfig.iMultisamples);
s_rgba6_to_rgb8[1] = D3D::CompileAndCreatePixelShader(buf);
CHECK(s_rgba6_to_rgb8[1], "Create RGBA6 to RGB8 MSAA pixel shader");
D3D::SetDebugObjectName(s_rgba6_to_rgb8[1], "RGBA6 to RGB8 MSAA pixel shader");
}
return s_rgba6_to_rgb8[1];
}
ID3D11PixelShader* PixelShaderCache::ReinterpRGB8ToRGBA6(bool multisampled)
{
if (!multisampled || g_ActiveConfig.iMultisamples <= 1)
{
if (!s_rgb8_to_rgba6[0])
{
s_rgb8_to_rgba6[0] = D3D::CompileAndCreatePixelShader(reint_rgb8_to_rgba6);
CHECK(s_rgb8_to_rgba6[0], "Create RGB8 to RGBA6 pixel shader");
D3D::SetDebugObjectName(s_rgb8_to_rgba6[0], "RGB8 to RGBA6 pixel shader");
}
return s_rgb8_to_rgba6[0];
}
else if (!s_rgb8_to_rgba6[1])
{
// create MSAA shader for current AA mode
std::string buf = StringFromFormat(reint_rgb8_to_rgba6_msaa, g_ActiveConfig.iMultisamples);
s_rgb8_to_rgba6[1] = D3D::CompileAndCreatePixelShader(buf);
CHECK(s_rgb8_to_rgba6[1], "Create RGB8 to RGBA6 MSAA pixel shader");
D3D::SetDebugObjectName(s_rgb8_to_rgba6[1], "RGB8 to RGBA6 MSAA pixel shader");
}
return s_rgb8_to_rgba6[1];
}
ID3D11PixelShader* PixelShaderCache::GetColorCopyProgram(bool multisampled)
{
if (!multisampled || g_ActiveConfig.iMultisamples <= 1)
{
return s_ColorCopyProgram[0];
}
else if (s_ColorCopyProgram[1])
{
return s_ColorCopyProgram[1];
}
else
{
// create MSAA shader for current AA mode
std::string buf = StringFromFormat(color_copy_program_code_msaa, g_ActiveConfig.iMultisamples);
s_ColorCopyProgram[1] = D3D::CompileAndCreatePixelShader(buf);
CHECK(s_ColorCopyProgram[1] != nullptr, "Create color copy MSAA pixel shader");
D3D::SetDebugObjectName(s_ColorCopyProgram[1], "color copy MSAA pixel shader");
return s_ColorCopyProgram[1];
}
}
ID3D11PixelShader* PixelShaderCache::GetClearProgram()
{
return s_ClearProgram;
}
ID3D11PixelShader* PixelShaderCache::GetAnaglyphProgram()
{
return s_AnaglyphProgram;
}
ID3D11PixelShader* PixelShaderCache::GetDepthResolveProgram()
{
if (s_DepthResolveProgram != nullptr)
return s_DepthResolveProgram;
// create MSAA shader for current AA mode
std::string buf = StringFromFormat(depth_resolve_program, g_ActiveConfig.iMultisamples);
s_DepthResolveProgram = D3D::CompileAndCreatePixelShader(buf);
CHECK(s_DepthResolveProgram != nullptr, "Create depth matrix MSAA pixel shader");
D3D::SetDebugObjectName(s_DepthResolveProgram, "depth resolve pixel shader");
return s_DepthResolveProgram;
}
void PixelShaderCache::Init()
{
// used when drawing clear quads
s_ClearProgram = D3D::CompileAndCreatePixelShader(clear_program_code);
CHECK(s_ClearProgram != nullptr, "Create clear pixel shader");
D3D::SetDebugObjectName(s_ClearProgram, "clear pixel shader");
// used for anaglyph stereoscopy
s_AnaglyphProgram = D3D::CompileAndCreatePixelShader(anaglyph_program_code);
CHECK(s_AnaglyphProgram != nullptr, "Create anaglyph pixel shader");
D3D::SetDebugObjectName(s_AnaglyphProgram, "anaglyph pixel shader");
// used when copying/resolving the color buffer
s_ColorCopyProgram[0] = D3D::CompileAndCreatePixelShader(color_copy_program_code);
CHECK(s_ColorCopyProgram[0] != nullptr, "Create color copy pixel shader");
D3D::SetDebugObjectName(s_ColorCopyProgram[0], "color copy pixel shader");
}
// Used in Swap() when AA mode has changed
void PixelShaderCache::InvalidateMSAAShaders()
{
SAFE_RELEASE(s_ColorCopyProgram[1]);
SAFE_RELEASE(s_rgb8_to_rgba6[1]);
SAFE_RELEASE(s_rgba6_to_rgb8[1]);
SAFE_RELEASE(s_DepthResolveProgram);
}
void PixelShaderCache::Shutdown()
{
SAFE_RELEASE(s_ClearProgram);
SAFE_RELEASE(s_AnaglyphProgram);
SAFE_RELEASE(s_DepthResolveProgram);
for (int i = 0; i < 2; ++i)
{
SAFE_RELEASE(s_ColorCopyProgram[i]);
SAFE_RELEASE(s_rgba6_to_rgb8[i]);
SAFE_RELEASE(s_rgb8_to_rgba6[i]);
}
}
} // DX11

View File

@ -1,34 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <d3d11.h>
#include <map>
#include "VideoCommon/AsyncShaderCompiler.h"
#include "VideoCommon/PixelShaderGen.h"
#include "VideoCommon/UberShaderPixel.h"
namespace DX11
{
class D3DBlob;
class PixelShaderCache
{
public:
static void Init();
static void Shutdown();
static ID3D11PixelShader* GetColorCopyProgram(bool multisampled);
static ID3D11PixelShader* GetClearProgram();
static ID3D11PixelShader* GetAnaglyphProgram();
static ID3D11PixelShader* GetDepthResolveProgram();
static ID3D11PixelShader* ReinterpRGBA6ToRGB8(bool multisampled);
static ID3D11PixelShader* ReinterpRGB8ToRGBA6(bool multisampled);
static void InvalidateMSAAShaders();
};
} // namespace DX11

View File

@ -23,33 +23,19 @@
#include "VideoBackends/D3D/BoundingBox.h"
#include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DState.h"
#include "VideoBackends/D3D/D3DUtil.h"
#include "VideoBackends/D3D/DXPipeline.h"
#include "VideoBackends/D3D/DXShader.h"
#include "VideoBackends/D3D/DXTexture.h"
#include "VideoBackends/D3D/FramebufferManager.h"
#include "VideoBackends/D3D/GeometryShaderCache.h"
#include "VideoBackends/D3D/PixelShaderCache.h"
#include "VideoBackends/D3D/TextureCache.h"
#include "VideoBackends/D3D/VertexShaderCache.h"
#include "VideoCommon/BPFunctions.h"
#include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/PixelEngine.h"
#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/PostProcessing.h"
#include "VideoCommon/RenderState.h"
#include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoConfig.h"
#include "VideoCommon/XFMemory.h"
namespace DX11
{
// Reserve 512KB for vertices, and 64KB for uniforms.
// This should be sufficient for our usages, and if more is required,
// we split it into multiple draws.
constexpr u32 UTILITY_VBO_SIZE = 512 * 1024;
constexpr u32 UTILITY_UBO_SIZE = 64 * 1024;
// Nvidia stereo blitting struct defined in "nvstereo.h" from the Nvidia SDK
typedef struct _Nv_Stereo_Image_Header
{
@ -67,118 +53,9 @@ Renderer::Renderer(int backbuffer_width, int backbuffer_height, float backbuffer
AbstractTextureFormat::RGBA8)
{
m_last_fullscreen_state = D3D::GetFullscreenState();
g_framebuffer_manager = std::make_unique<FramebufferManager>(m_target_width, m_target_height);
SetupDeviceObjects();
D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)m_target_width, (float)m_target_height);
D3D::context->RSSetViewports(1, &vp);
FramebufferManager::BindEFBRenderTarget();
m_current_framebuffer_width = m_target_width;
m_current_framebuffer_height = m_target_height;
}
Renderer::~Renderer()
{
TeardownDeviceObjects();
}
void Renderer::SetupDeviceObjects()
{
HRESULT hr;
D3D11_DEPTH_STENCIL_DESC ddesc;
ddesc.DepthEnable = FALSE;
ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
ddesc.DepthFunc = D3D11_COMPARISON_ALWAYS;
ddesc.StencilEnable = FALSE;
ddesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
ddesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
hr = D3D::device->CreateDepthStencilState(&ddesc, &m_clear_depth_states[0]);
CHECK(hr == S_OK, "Create depth state for Renderer::ClearScreen");
ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
ddesc.DepthEnable = TRUE;
hr = D3D::device->CreateDepthStencilState(&ddesc, &m_clear_depth_states[1]);
CHECK(hr == S_OK, "Create depth state for Renderer::ClearScreen");
ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
hr = D3D::device->CreateDepthStencilState(&ddesc, &m_clear_depth_states[2]);
CHECK(hr == S_OK, "Create depth state for Renderer::ClearScreen");
D3D::SetDebugObjectName(m_clear_depth_states[0],
"depth state for Renderer::ClearScreen (depth buffer disabled)");
D3D::SetDebugObjectName(
m_clear_depth_states[1],
"depth state for Renderer::ClearScreen (depth buffer enabled, writing enabled)");
D3D::SetDebugObjectName(
m_clear_depth_states[2],
"depth state for Renderer::ClearScreen (depth buffer enabled, writing disabled)");
D3D11_BLEND_DESC blenddesc;
blenddesc.AlphaToCoverageEnable = FALSE;
blenddesc.IndependentBlendEnable = FALSE;
blenddesc.RenderTarget[0].BlendEnable = FALSE;
blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
blenddesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
blenddesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO;
blenddesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
hr = D3D::device->CreateBlendState(&blenddesc, &m_reset_blend_state);
CHECK(hr == S_OK, "Create blend state for Renderer::ResetAPIState");
D3D::SetDebugObjectName(m_reset_blend_state, "blend state for Renderer::ResetAPIState");
m_clear_blend_states[0] = m_reset_blend_state;
m_reset_blend_state->AddRef();
blenddesc.RenderTarget[0].RenderTargetWriteMask =
D3D11_COLOR_WRITE_ENABLE_RED | D3D11_COLOR_WRITE_ENABLE_GREEN | D3D11_COLOR_WRITE_ENABLE_BLUE;
hr = D3D::device->CreateBlendState(&blenddesc, &m_clear_blend_states[1]);
CHECK(hr == S_OK, "Create blend state for Renderer::ClearScreen");
blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALPHA;
hr = D3D::device->CreateBlendState(&blenddesc, &m_clear_blend_states[2]);
CHECK(hr == S_OK, "Create blend state for Renderer::ClearScreen");
blenddesc.RenderTarget[0].RenderTargetWriteMask = 0;
hr = D3D::device->CreateBlendState(&blenddesc, &m_clear_blend_states[3]);
CHECK(hr == S_OK, "Create blend state for Renderer::ClearScreen");
ddesc.DepthEnable = FALSE;
ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
ddesc.DepthFunc = D3D11_COMPARISON_LESS;
ddesc.StencilEnable = FALSE;
ddesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
ddesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
hr = D3D::device->CreateDepthStencilState(&ddesc, &m_reset_depth_state);
CHECK(hr == S_OK, "Create depth state for Renderer::ResetAPIState");
D3D::SetDebugObjectName(m_reset_depth_state, "depth stencil state for Renderer::ResetAPIState");
D3D11_RASTERIZER_DESC rastdesc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, D3D11_CULL_NONE, false,
0, 0.f, 0.f, false, false, false, false);
hr = D3D::device->CreateRasterizerState(&rastdesc, &m_reset_rast_state);
CHECK(hr == S_OK, "Create rasterizer state for Renderer::ResetAPIState");
D3D::SetDebugObjectName(m_reset_rast_state, "rasterizer state for Renderer::ResetAPIState");
m_screenshot_texture = nullptr;
}
// Kill off all device objects
void Renderer::TeardownDeviceObjects()
{
g_framebuffer_manager.reset();
SAFE_RELEASE(m_clear_blend_states[0]);
SAFE_RELEASE(m_clear_blend_states[1]);
SAFE_RELEASE(m_clear_blend_states[2]);
SAFE_RELEASE(m_clear_blend_states[3]);
SAFE_RELEASE(m_clear_depth_states[0]);
SAFE_RELEASE(m_clear_depth_states[1]);
SAFE_RELEASE(m_clear_depth_states[2]);
SAFE_RELEASE(m_reset_blend_state);
SAFE_RELEASE(m_reset_depth_state);
SAFE_RELEASE(m_reset_rast_state);
SAFE_RELEASE(m_screenshot_texture);
SAFE_RELEASE(m_3d_vision_texture);
}
Renderer::~Renderer() = default;
void Renderer::Create3DVisionTexture(int width, int height)
{
@ -200,9 +77,17 @@ void Renderer::Create3DVisionTexture(int width, int height)
sys_data.SysMemPitch = pitch;
sys_data.pSysMem = memory.get();
m_3d_vision_texture =
D3DTexture2D::Create(width * 2, height + 1, D3D11_BIND_RENDER_TARGET, D3D11_USAGE_DEFAULT,
DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, &sys_data);
CD3D11_TEXTURE2D_DESC texture_desc(DXGI_FORMAT_R8G8B8A8_UNORM, width * 2, height + 1, 1, 1,
D3D11_BIND_RENDER_TARGET, D3D11_USAGE_DEFAULT, 0, 1, 0, 0);
ID3D11Texture2D* texture;
HRESULT hr = D3D::device->CreateTexture2D(&texture_desc, &sys_data, &texture);
CHECK(SUCCEEDED(hr), "Create 3D Vision Texture");
m_3d_vision_texture = std::make_unique<DXTexture>(TextureConfig(width * 2, height + 1, 1, 1, 1,
AbstractTextureFormat::RGBA8,
AbstractTextureFlag_RenderTarget),
texture, nullptr, nullptr);
m_3d_vision_framebuffer =
DXFramebuffer::Create(static_cast<DXTexture*>(m_3d_vision_texture.get()), nullptr);
}
bool Renderer::IsHeadless() const
@ -212,7 +97,7 @@ bool Renderer::IsHeadless() const
std::unique_ptr<AbstractTexture> Renderer::CreateTexture(const TextureConfig& config)
{
return std::make_unique<DXTexture>(config);
return DXTexture::Create(config);
}
std::unique_ptr<AbstractStagingTexture> Renderer::CreateStagingTexture(StagingTextureType type,
@ -221,12 +106,11 @@ std::unique_ptr<AbstractStagingTexture> Renderer::CreateStagingTexture(StagingTe
return DXStagingTexture::Create(type, config);
}
std::unique_ptr<AbstractFramebuffer>
Renderer::CreateFramebuffer(const AbstractTexture* color_attachment,
const AbstractTexture* depth_attachment)
std::unique_ptr<AbstractFramebuffer> Renderer::CreateFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment)
{
return DXFramebuffer::Create(static_cast<const DXTexture*>(color_attachment),
static_cast<const DXTexture*>(depth_attachment));
return DXFramebuffer::Create(static_cast<DXTexture*>(color_attachment),
static_cast<DXTexture*>(depth_attachment));
}
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromSource(ShaderStage stage,
@ -249,220 +133,44 @@ std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelin
void Renderer::SetPipeline(const AbstractPipeline* pipeline)
{
const DXPipeline* dx_pipeline = static_cast<const DXPipeline*>(pipeline);
if (!dx_pipeline)
if (m_current_pipeline == dx_pipeline)
return;
D3D::stateman->SetRasterizerState(dx_pipeline->GetRasterizerState());
D3D::stateman->SetDepthState(dx_pipeline->GetDepthState());
D3D::stateman->SetBlendState(dx_pipeline->GetBlendState());
D3D::stateman->SetPrimitiveTopology(dx_pipeline->GetPrimitiveTopology());
D3D::stateman->SetInputLayout(dx_pipeline->GetInputLayout());
D3D::stateman->SetVertexShader(dx_pipeline->GetVertexShader());
D3D::stateman->SetGeometryShader(dx_pipeline->GetGeometryShader());
D3D::stateman->SetPixelShader(dx_pipeline->GetPixelShader());
}
TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc)
{
TargetRectangle result;
result.left = EFBToScaledX(rc.left);
result.top = EFBToScaledY(rc.top);
result.right = EFBToScaledX(rc.right);
result.bottom = EFBToScaledY(rc.bottom);
return result;
if (dx_pipeline)
{
D3D::stateman->SetRasterizerState(dx_pipeline->GetRasterizerState());
D3D::stateman->SetDepthState(dx_pipeline->GetDepthState());
D3D::stateman->SetBlendState(dx_pipeline->GetBlendState());
D3D::stateman->SetPrimitiveTopology(dx_pipeline->GetPrimitiveTopology());
D3D::stateman->SetInputLayout(dx_pipeline->GetInputLayout());
D3D::stateman->SetVertexShader(dx_pipeline->GetVertexShader());
D3D::stateman->SetGeometryShader(dx_pipeline->GetGeometryShader());
D3D::stateman->SetPixelShader(dx_pipeline->GetPixelShader());
D3D::stateman->SetIntegerRTV(dx_pipeline->UseLogicOp());
}
else
{
// These will be destroyed at pipeline destruction.
D3D::stateman->SetInputLayout(nullptr);
D3D::stateman->SetVertexShader(nullptr);
D3D::stateman->SetGeometryShader(nullptr);
D3D::stateman->SetPixelShader(nullptr);
}
}
void Renderer::SetScissorRect(const MathUtil::Rectangle<int>& rc)
{
const RECT rect = {rc.left, rc.top, rc.right, rc.bottom};
// TODO: Move to stateman
const CD3D11_RECT rect(rc.left, rc.top, std::max(rc.right, rc.left + 1),
std::max(rc.bottom, rc.top + 1));
D3D::context->RSSetScissorRects(1, &rect);
}
// This function allows the CPU to directly access the EFB.
// There are EFB peeks (which will read the color or depth of a pixel)
// and EFB pokes (which will change the color or depth of a pixel).
//
// The behavior of EFB peeks can only be modified by:
// - GX_PokeAlphaRead
// The behavior of EFB pokes can be modified by:
// - GX_PokeAlphaMode (TODO)
// - GX_PokeAlphaUpdate (TODO)
// - GX_PokeBlendMode (TODO)
// - GX_PokeColorUpdate (TODO)
// - GX_PokeDither (TODO)
// - GX_PokeDstAlpha (TODO)
// - GX_PokeZMode (TODO)
u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data)
{
// Convert EFB dimensions to the ones of our render target
EFBRectangle efbPixelRc;
efbPixelRc.left = x;
efbPixelRc.top = y;
efbPixelRc.right = x + 1;
efbPixelRc.bottom = y + 1;
TargetRectangle targetPixelRc = Renderer::ConvertEFBRectangle(efbPixelRc);
// Take the mean of the resulting dimensions; TODO: Don't use the center pixel, compute the
// average color instead
D3D11_RECT RectToLock;
if (type == EFBAccessType::PeekColor || type == EFBAccessType::PeekZ)
{
RectToLock.left = (targetPixelRc.left + targetPixelRc.right) / 2;
RectToLock.top = (targetPixelRc.top + targetPixelRc.bottom) / 2;
RectToLock.right = RectToLock.left + 1;
RectToLock.bottom = RectToLock.top + 1;
}
else
{
RectToLock.left = targetPixelRc.left;
RectToLock.right = targetPixelRc.right;
RectToLock.top = targetPixelRc.top;
RectToLock.bottom = targetPixelRc.bottom;
}
// Reset any game specific settings.
ResetAPIState();
D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, 1.f, 1.f);
D3D::context->RSSetViewports(1, &vp);
D3D::SetPointCopySampler();
// Select copy and read textures depending on if we are doing a color or depth read (since they
// are different formats).
D3DTexture2D* source_tex;
D3DTexture2D* read_tex;
ID3D11Texture2D* staging_tex;
if (type == EFBAccessType::PeekColor)
{
source_tex = FramebufferManager::GetEFBColorTexture();
read_tex = FramebufferManager::GetEFBColorReadTexture();
staging_tex = FramebufferManager::GetEFBColorStagingBuffer();
}
else
{
source_tex = FramebufferManager::GetEFBDepthTexture();
read_tex = FramebufferManager::GetEFBDepthReadTexture();
staging_tex = FramebufferManager::GetEFBDepthStagingBuffer();
}
// Select pixel shader (we don't want to average depth samples, instead select the minimum).
ID3D11PixelShader* copy_pixel_shader;
if (type == EFBAccessType::PeekZ && g_ActiveConfig.iMultisamples > 1)
copy_pixel_shader = PixelShaderCache::GetDepthResolveProgram();
else
copy_pixel_shader = PixelShaderCache::GetColorCopyProgram(true);
// Draw a quad to grab the texel we want to read.
D3D::context->OMSetRenderTargets(1, &read_tex->GetRTV(), nullptr);
D3D::drawShadedTexQuad(source_tex->GetSRV(), &RectToLock, Renderer::GetTargetWidth(),
Renderer::GetTargetHeight(), copy_pixel_shader,
VertexShaderCache::GetSimpleVertexShader(),
VertexShaderCache::GetSimpleInputLayout());
// Restore expected game state.
RestoreAPIState();
// Copy the pixel from the renderable to cpu-readable buffer.
D3D11_BOX box = CD3D11_BOX(0, 0, 0, 1, 1, 1);
D3D::context->CopySubresourceRegion(staging_tex, 0, 0, 0, 0, read_tex->GetTex(), 0, &box);
D3D11_MAPPED_SUBRESOURCE map;
CHECK(D3D::context->Map(staging_tex, 0, D3D11_MAP_READ, 0, &map) == S_OK,
"Map staging buffer failed");
// Convert the framebuffer data to the format the game is expecting to receive.
u32 ret;
if (type == EFBAccessType::PeekColor)
{
u32 val;
memcpy(&val, map.pData, sizeof(val));
// our buffers are RGBA, yet a BGRA value is expected
val = ((val & 0xFF00FF00) | ((val >> 16) & 0xFF) | ((val << 16) & 0xFF0000));
// check what to do with the alpha channel (GX_PokeAlphaRead)
PixelEngine::UPEAlphaReadReg alpha_read_mode = PixelEngine::GetAlphaReadMode();
if (bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24)
{
val = RGBA8ToRGBA6ToRGBA8(val);
}
else if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16)
{
val = RGBA8ToRGB565ToRGBA8(val);
}
if (bpmem.zcontrol.pixel_format != PEControl::RGBA6_Z24)
{
val |= 0xFF000000;
}
if (alpha_read_mode.ReadMode == 2)
ret = val; // GX_READ_NONE
else if (alpha_read_mode.ReadMode == 1)
ret = (val | 0xFF000000); // GX_READ_FF
else /*if(alpha_read_mode.ReadMode == 0)*/
ret = (val & 0x00FFFFFF); // GX_READ_00
}
else // type == EFBAccessType::PeekZ
{
float val;
memcpy(&val, map.pData, sizeof(val));
// depth buffer is inverted in the d3d backend
val = 1.0f - val;
if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16)
{
// if Z is in 16 bit format you must return a 16 bit integer
ret = MathUtil::Clamp<u32>(static_cast<u32>(val * 65536.0f), 0, 0xFFFF);
}
else
{
ret = MathUtil::Clamp<u32>(static_cast<u32>(val * 16777216.0f), 0, 0xFFFFFF);
}
}
D3D::context->Unmap(staging_tex, 0);
return ret;
}
void Renderer::PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points)
{
ResetAPIState();
if (type == EFBAccessType::PokeColor)
{
D3D11_VIEWPORT vp =
CD3D11_VIEWPORT(0.0f, 0.0f, (float)GetTargetWidth(), (float)GetTargetHeight());
D3D::context->RSSetViewports(1, &vp);
}
else // if (type == EFBAccessType::PokeZ)
{
D3D::stateman->SetBlendState(m_clear_blend_states[3]);
D3D::stateman->SetDepthState(m_clear_depth_states[1]);
D3D11_VIEWPORT vp =
CD3D11_VIEWPORT(0.0f, 0.0f, (float)GetTargetWidth(), (float)GetTargetHeight());
D3D::context->RSSetViewports(1, &vp);
}
D3D::DrawEFBPokeQuads(type, points, num_points);
RestoreAPIState();
}
void Renderer::SetViewport(float x, float y, float width, float height, float near_depth,
float far_depth)
{
// In D3D, the viewport rectangle must fit within the render target.
D3D11_VIEWPORT vp;
vp.TopLeftX = MathUtil::Clamp(x, 0.0f, static_cast<float>(m_current_framebuffer_width - 1));
vp.TopLeftY = MathUtil::Clamp(y, 0.0f, static_cast<float>(m_current_framebuffer_height - 1));
vp.Width =
MathUtil::Clamp(width, 1.0f, static_cast<float>(m_current_framebuffer_width) - vp.TopLeftX);
vp.Height =
MathUtil::Clamp(height, 1.0f, static_cast<float>(m_current_framebuffer_height) - vp.TopLeftY);
vp.MinDepth = near_depth;
vp.MaxDepth = far_depth;
// TODO: Move to stateman
const CD3D11_VIEWPORT vp(x, y, width, height, near_depth, far_depth);
D3D::context->RSSetViewports(1, &vp);
}
@ -478,89 +186,19 @@ void Renderer::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex)
D3D::context->DrawIndexed(num_indices, base_index, base_vertex);
}
void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable,
u32 color, u32 z)
void Renderer::DispatchComputeShader(const AbstractShader* shader, u32 groups_x, u32 groups_y,
u32 groups_z)
{
ResetAPIState();
if (colorEnable && alphaEnable)
D3D::stateman->SetBlendState(m_clear_blend_states[0]);
else if (colorEnable)
D3D::stateman->SetBlendState(m_clear_blend_states[1]);
else if (alphaEnable)
D3D::stateman->SetBlendState(m_clear_blend_states[2]);
else
D3D::stateman->SetBlendState(m_clear_blend_states[3]);
// TODO: Should we enable Z testing here?
// if (!bpmem.zmode.testenable) D3D::stateman->PushDepthState(s_clear_depth_states[0]);
// else
if (zEnable)
D3D::stateman->SetDepthState(m_clear_depth_states[1]);
else /*if (!zEnable)*/
D3D::stateman->SetDepthState(m_clear_depth_states[2]);
// Update the view port for clearing the picture
TargetRectangle targetRc = Renderer::ConvertEFBRectangle(rc);
D3D11_VIEWPORT vp =
CD3D11_VIEWPORT((float)targetRc.left, (float)targetRc.top, (float)targetRc.GetWidth(),
(float)targetRc.GetHeight(), 0.f, 1.f);
D3D::context->RSSetViewports(1, &vp);
FramebufferManager::SetIntegerEFBRenderTarget(false);
// Color is passed in bgra mode so we need to convert it to rgba
u32 rgbaColor = (color & 0xFF00FF00) | ((color >> 16) & 0xFF) | ((color << 16) & 0xFF0000);
D3D::drawClearQuad(rgbaColor, 1.0f - (z & 0xFFFFFF) / 16777216.0f);
RestoreAPIState();
}
void Renderer::ReinterpretPixelData(unsigned int convtype)
{
// TODO: MSAA support..
D3D11_RECT source = CD3D11_RECT(0, 0, GetTargetWidth(), GetTargetHeight());
ID3D11PixelShader* pixel_shader;
if (convtype == 0)
pixel_shader = PixelShaderCache::ReinterpRGB8ToRGBA6(true);
else if (convtype == 2)
pixel_shader = PixelShaderCache::ReinterpRGBA6ToRGB8(true);
else
{
ERROR_LOG(VIDEO, "Trying to reinterpret pixel data with unsupported conversion type %d",
convtype);
return;
}
// convert data and set the target texture as our new EFB
ResetAPIState();
D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, static_cast<float>(GetTargetWidth()),
static_cast<float>(GetTargetHeight()));
D3D::context->RSSetViewports(1, &vp);
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTempTexture()->GetRTV(),
nullptr);
D3D::SetPointCopySampler();
D3D::drawShadedTexQuad(
FramebufferManager::GetEFBColorTexture()->GetSRV(), &source, GetTargetWidth(),
GetTargetHeight(), pixel_shader, VertexShaderCache::GetSimpleVertexShader(),
VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader());
FramebufferManager::SwapReinterpretTexture();
RestoreAPIState();
D3D::stateman->SetComputeShader(static_cast<const DXShader*>(shader)->GetD3DComputeShader());
D3D::stateman->SyncComputeBindings();
D3D::context->Dispatch(groups_x, groups_y, groups_z);
}
void Renderer::BindBackbuffer(const ClearColor& clear_color)
{
CheckForSurfaceChange();
CheckForSurfaceResize();
D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), nullptr);
D3D::context->ClearRenderTargetView(D3D::GetBackBuffer()->GetRTV(), clear_color.data());
m_current_framebuffer = nullptr;
m_current_framebuffer_width = m_backbuffer_width;
m_current_framebuffer_height = m_backbuffer_height;
SetAndClearFramebuffer(D3D::GetSwapChainFramebuffer(), clear_color);
}
void Renderer::PresentBackbuffer()
@ -570,14 +208,6 @@ void Renderer::PresentBackbuffer()
void Renderer::OnConfigChanged(u32 bits)
{
// Resize the back buffers NOW to avoid flickering
if (bits & (CONFIG_CHANGE_BIT_TARGET_SIZE | CONFIG_CHANGE_BIT_MULTISAMPLES |
CONFIG_CHANGE_BIT_STEREO_MODE))
{
PixelShaderCache::InvalidateMSAAShaders();
g_framebuffer_manager.reset();
g_framebuffer_manager = std::make_unique<FramebufferManager>(m_target_width, m_target_height);
}
}
void Renderer::CheckForSurfaceChange()
@ -585,8 +215,8 @@ void Renderer::CheckForSurfaceChange()
if (!m_surface_changed.TestAndClear())
return;
SAFE_RELEASE(m_screenshot_texture);
SAFE_RELEASE(m_3d_vision_texture);
m_3d_vision_framebuffer.reset();
m_3d_vision_texture.reset();
D3D::Reset(reinterpret_cast<HWND>(m_new_surface_handle));
m_new_surface_handle = nullptr;
@ -601,8 +231,9 @@ void Renderer::CheckForSurfaceResize()
if (!m_surface_resized.TestAndClear() && !exclusive_fullscreen_changed)
return;
SAFE_RELEASE(m_screenshot_texture);
SAFE_RELEASE(m_3d_vision_texture);
m_3d_vision_framebuffer.reset();
m_3d_vision_texture.reset();
m_last_fullscreen_state = fullscreen_state;
if (D3D::swapchain)
D3D::ResizeSwapChain();
@ -625,43 +256,38 @@ void Renderer::UpdateBackbufferSize()
}
}
// ALWAYS call RestoreAPIState for each ResetAPIState call you're doing
void Renderer::ResetAPIState()
void Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer)
{
D3D::stateman->SetBlendState(m_reset_blend_state);
D3D::stateman->SetDepthState(m_reset_depth_state);
D3D::stateman->SetRasterizerState(m_reset_rast_state);
}
if (m_current_framebuffer == framebuffer)
return;
void Renderer::RestoreAPIState()
{
// Gets us back into a more game-like state.
m_current_framebuffer = nullptr;
m_current_framebuffer_width = m_target_width;
m_current_framebuffer_height = m_target_height;
FramebufferManager::BindEFBRenderTarget();
BPFunctions::SetViewport();
BPFunctions::SetScissor();
}
// We can't leave the framebuffer bound as a texture and a render target.
DXFramebuffer* fb = static_cast<DXFramebuffer*>(framebuffer);
if ((fb->GetColorAttachment() &&
D3D::stateman->UnsetTexture(
static_cast<DXTexture*>(fb->GetColorAttachment())->GetD3DSRV()) != 0) ||
(fb->GetDepthAttachment() &&
D3D::stateman->UnsetTexture(
static_cast<DXTexture*>(fb->GetDepthAttachment())->GetD3DSRV()) != 0))
{
D3D::stateman->ApplyTextures();
}
void Renderer::SetFramebuffer(const AbstractFramebuffer* framebuffer)
{
const DXFramebuffer* fb = static_cast<const DXFramebuffer*>(framebuffer);
D3D::context->OMSetRenderTargets(fb->GetNumRTVs(), fb->GetRTVArray(), fb->GetDSV());
D3D::stateman->SetFramebuffer(fb);
m_current_framebuffer = fb;
m_current_framebuffer_width = fb->GetWidth();
m_current_framebuffer_height = fb->GetHeight();
}
void Renderer::SetAndDiscardFramebuffer(const AbstractFramebuffer* framebuffer)
void Renderer::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
{
SetFramebuffer(framebuffer);
}
void Renderer::SetAndClearFramebuffer(const AbstractFramebuffer* framebuffer,
void Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
const ClearColor& color_value, float depth_value)
{
SetFramebuffer(framebuffer);
D3D::stateman->Apply();
if (framebuffer->GetColorFormat() != AbstractTextureFormat::Undefined)
{
D3D::context->ClearRenderTargetView(
@ -676,9 +302,8 @@ void Renderer::SetAndClearFramebuffer(const AbstractFramebuffer* framebuffer,
void Renderer::SetTexture(u32 index, const AbstractTexture* texture)
{
D3D::stateman->SetTexture(
index,
texture ? static_cast<const DXTexture*>(texture)->GetRawTexIdentifier()->GetSRV() : nullptr);
D3D::stateman->SetTexture(index, texture ? static_cast<const DXTexture*>(texture)->GetD3DSRV() :
nullptr);
}
void Renderer::SetSamplerState(u32 index, const SamplerState& state)
@ -686,15 +311,15 @@ void Renderer::SetSamplerState(u32 index, const SamplerState& state)
D3D::stateman->SetSampler(index, m_state_cache.Get(state));
}
void Renderer::UnbindTexture(const AbstractTexture* texture)
void Renderer::SetComputeImageTexture(AbstractTexture* texture, bool read, bool write)
{
D3D::stateman->UnsetTexture(
static_cast<const DXTexture*>(texture)->GetRawTexIdentifier()->GetSRV());
D3D::stateman->SetComputeUAV(texture ? static_cast<DXTexture*>(texture)->GetD3DUAV() : nullptr);
}
void Renderer::SetInterlacingMode()
void Renderer::UnbindTexture(const AbstractTexture* texture)
{
// TODO
if (D3D::stateman->UnsetTexture(static_cast<const DXTexture*>(texture)->GetD3DSRV()) != 0)
D3D::stateman->ApplyTextures();
}
u16 Renderer::BBoxRead(int index)
@ -736,93 +361,43 @@ void Renderer::BBoxWrite(int index, u16 _value)
BBox::Set(index, value);
}
void Renderer::Flush()
{
D3D::context->Flush();
}
void Renderer::WaitForGPUIdle()
{
// There is no glFinish() equivalent in D3D.
D3D::context->Flush();
}
void Renderer::RenderXFBToScreen(const AbstractTexture* texture, const EFBRectangle& rc)
{
const CD3D11_RECT source_rc(rc.left, rc.top, rc.right, rc.bottom);
const TargetRectangle target_rc = GetTargetRectangle();
if (g_ActiveConfig.stereo_mode != StereoMode::Nvidia3DVision)
return ::Renderer::RenderXFBToScreen(texture, rc);
// activate linear filtering for the buffer copies
D3D::SetLinearCopySampler();
if (!m_3d_vision_texture)
Create3DVisionTexture(m_backbuffer_width, m_backbuffer_height);
if (g_ActiveConfig.stereo_mode == StereoMode::SBS ||
g_ActiveConfig.stereo_mode == StereoMode::TAB)
{
TargetRectangle left_rc, right_rc;
std::tie(left_rc, right_rc) = ConvertStereoRectangle(target_rc);
// Render to staging texture which is double the width of the backbuffer
SetAndClearFramebuffer(m_3d_vision_framebuffer.get());
SetViewport(static_cast<float>(left_rc.left), static_cast<float>(left_rc.top),
static_cast<float>(left_rc.GetWidth()), static_cast<float>(right_rc.GetHeight()),
0.0f, 1.0f);
D3D::drawShadedTexQuad(static_cast<const DXTexture*>(texture)->GetRawTexIdentifier()->GetSRV(),
&source_rc, texture->GetWidth(), texture->GetHeight(),
PixelShaderCache::GetColorCopyProgram(false),
VertexShaderCache::GetSimpleVertexShader(),
VertexShaderCache::GetSimpleInputLayout(), nullptr, 0);
const auto target_rc = GetTargetRectangle();
m_post_processor->BlitFromTexture(target_rc, rc, texture, 0);
m_post_processor->BlitFromTexture(
MathUtil::Rectangle<int>(target_rc.left + m_backbuffer_width, target_rc.top,
target_rc.right + m_backbuffer_width, target_rc.bottom),
rc, texture, 1);
SetViewport(static_cast<float>(right_rc.left), static_cast<float>(right_rc.top),
static_cast<float>(right_rc.GetWidth()), static_cast<float>(right_rc.GetHeight()),
0.0f, 1.0f);
D3D::drawShadedTexQuad(static_cast<const DXTexture*>(texture)->GetRawTexIdentifier()->GetSRV(),
&source_rc, texture->GetWidth(), texture->GetHeight(),
PixelShaderCache::GetColorCopyProgram(false),
VertexShaderCache::GetSimpleVertexShader(),
VertexShaderCache::GetSimpleInputLayout(), nullptr, 1);
}
else if (g_ActiveConfig.stereo_mode == StereoMode::Nvidia3DVision)
{
if (!m_3d_vision_texture)
Create3DVisionTexture(m_backbuffer_width, m_backbuffer_height);
// Copy the left eye to the backbuffer, if Nvidia 3D Vision is enabled it should
// recognize the signature and automatically include the right eye frame.
const CD3D11_BOX box(0, 0, 0, m_backbuffer_width, m_backbuffer_height, 1);
D3D::context->CopySubresourceRegion(D3D::GetSwapChainTexture()->GetD3DTexture(), 0, 0, 0, 0,
m_3d_vision_texture->GetD3DTexture(), 0, &box);
const CD3D11_VIEWPORT left_vp(
static_cast<float>(target_rc.left), static_cast<float>(target_rc.top),
static_cast<float>(target_rc.GetWidth()), static_cast<float>(target_rc.GetHeight()));
const CD3D11_VIEWPORT right_vp(
static_cast<float>(target_rc.left + m_backbuffer_width), static_cast<float>(target_rc.top),
static_cast<float>(target_rc.GetWidth()), static_cast<float>(target_rc.GetHeight()));
// Render to staging texture which is double the width of the backbuffer
D3D::context->OMSetRenderTargets(1, &m_3d_vision_texture->GetRTV(), nullptr);
D3D::context->RSSetViewports(1, &left_vp);
D3D::drawShadedTexQuad(static_cast<const DXTexture*>(texture)->GetRawTexIdentifier()->GetSRV(),
&source_rc, texture->GetWidth(), texture->GetHeight(),
PixelShaderCache::GetColorCopyProgram(false),
VertexShaderCache::GetSimpleVertexShader(),
VertexShaderCache::GetSimpleInputLayout(), nullptr, 0);
D3D::context->RSSetViewports(1, &right_vp);
D3D::drawShadedTexQuad(static_cast<const DXTexture*>(texture)->GetRawTexIdentifier()->GetSRV(),
&source_rc, texture->GetWidth(), texture->GetHeight(),
PixelShaderCache::GetColorCopyProgram(false),
VertexShaderCache::GetSimpleVertexShader(),
VertexShaderCache::GetSimpleInputLayout(), nullptr, 1);
// Copy the left eye to the backbuffer, if Nvidia 3D Vision is enabled it should
// recognize the signature and automatically include the right eye frame.
const CD3D11_BOX box(0, 0, 0, m_backbuffer_width, m_backbuffer_height, 1);
D3D::context->CopySubresourceRegion(D3D::GetBackBuffer()->GetTex(), 0, 0, 0, 0,
m_3d_vision_texture->GetTex(), 0, &box);
// Restore render target to backbuffer
D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), nullptr);
}
else
{
SetViewport(static_cast<float>(target_rc.left), static_cast<float>(target_rc.top),
static_cast<float>(target_rc.GetWidth()), static_cast<float>(target_rc.GetHeight()),
0.0f, 1.0f);
ID3D11PixelShader* pixelShader = (g_Config.stereo_mode == StereoMode::Anaglyph) ?
PixelShaderCache::GetAnaglyphProgram() :
PixelShaderCache::GetColorCopyProgram(false);
ID3D11GeometryShader* geomShader = (g_ActiveConfig.stereo_mode == StereoMode::QuadBuffer) ?
GeometryShaderCache::GetCopyGeometryShader() :
nullptr;
D3D::drawShadedTexQuad(static_cast<const DXTexture*>(texture)->GetRawTexIdentifier()->GetSRV(),
&source_rc, texture->GetWidth(), texture->GetHeight(), pixelShader,
VertexShaderCache::GetSimpleVertexShader(),
VertexShaderCache::GetSimpleInputLayout(), geomShader);
}
// Restore render target to backbuffer
SetFramebuffer(D3D::GetSwapChainFramebuffer());
}
void Renderer::SetFullscreen(bool enable_fullscreen)

View File

@ -9,11 +9,10 @@
#include "VideoBackends/D3D/D3DState.h"
#include "VideoCommon/RenderBase.h"
enum class EFBAccessType;
namespace DX11
{
class D3DTexture2D;
class DXTexture;
class DXFramebuffer;
class Renderer : public ::Renderer
{
@ -32,53 +31,43 @@ public:
size_t length) override;
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
size_t length) override;
std::unique_ptr<NativeVertexFormat>
CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override;
std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config) override;
std::unique_ptr<AbstractFramebuffer>
CreateFramebuffer(const AbstractTexture* color_attachment,
const AbstractTexture* depth_attachment) override;
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
void SetPipeline(const AbstractPipeline* pipeline) override;
void SetFramebuffer(const AbstractFramebuffer* framebuffer) override;
void SetAndDiscardFramebuffer(const AbstractFramebuffer* framebuffer) override;
void SetAndClearFramebuffer(const AbstractFramebuffer* framebuffer,
const ClearColor& color_value = {},
void SetFramebuffer(AbstractFramebuffer* framebuffer) override;
void SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer) override;
void SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearColor& color_value = {},
float depth_value = 0.0f) override;
void SetScissorRect(const MathUtil::Rectangle<int>& rc) override;
void SetTexture(u32 index, const AbstractTexture* texture) override;
void SetSamplerState(u32 index, const SamplerState& state) override;
void SetComputeImageTexture(AbstractTexture* texture, bool read, bool write) override;
void UnbindTexture(const AbstractTexture* texture) override;
void SetInterlacingMode() override;
void SetViewport(float x, float y, float width, float height, float near_depth,
float far_depth) override;
void Draw(u32 base_vertex, u32 num_vertices) override;
void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) override;
void DispatchComputeShader(const AbstractShader* shader, u32 groups_x, u32 groups_y,
u32 groups_z) override;
void BindBackbuffer(const ClearColor& clear_color = {}) override;
void PresentBackbuffer() override;
void SetFullscreen(bool enable_fullscreen) override;
bool IsFullscreen() const override;
u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override;
void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override;
u16 BBoxRead(int index) override;
void BBoxWrite(int index, u16 value) override;
void ResetAPIState() override;
void RestoreAPIState() override;
TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override;
void Flush() override;
void WaitForGPUIdle() override;
void RenderXFBToScreen(const AbstractTexture* texture, const EFBRectangle& rc) override;
void OnConfigChanged(u32 bits) override;
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable,
u32 color, u32 z) override;
void ReinterpretPixelData(unsigned int convtype) override;
private:
void SetupDeviceObjects();
void TeardownDeviceObjects();
void Create3DVisionTexture(int width, int height);
void CheckForSurfaceChange();
void CheckForSurfaceResize();
@ -86,15 +75,9 @@ private:
StateCache m_state_cache;
std::array<ID3D11BlendState*, 4> m_clear_blend_states{};
std::array<ID3D11DepthStencilState*, 3> m_clear_depth_states{};
ID3D11BlendState* m_reset_blend_state = nullptr;
ID3D11DepthStencilState* m_reset_depth_state = nullptr;
ID3D11RasterizerState* m_reset_rast_state = nullptr;
ID3D11Texture2D* m_screenshot_texture = nullptr;
D3DTexture2D* m_3d_vision_texture = nullptr;
std::unique_ptr<DXTexture> m_3d_vision_texture;
std::unique_ptr<DXFramebuffer> m_3d_vision_framebuffer;
bool m_last_fullscreen_state = false;
};
}
} // namespace DX11

View File

@ -1,318 +0,0 @@
// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "VideoBackends/D3D/TextureCache.h"
#include <algorithm>
#include <memory>
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DShader.h"
#include "VideoBackends/D3D/D3DState.h"
#include "VideoBackends/D3D/D3DTexture.h"
#include "VideoBackends/D3D/D3DUtil.h"
#include "VideoBackends/D3D/DXTexture.h"
#include "VideoBackends/D3D/FramebufferManager.h"
#include "VideoBackends/D3D/GeometryShaderCache.h"
#include "VideoBackends/D3D/PSTextureEncoder.h"
#include "VideoBackends/D3D/PixelShaderCache.h"
#include "VideoBackends/D3D/VertexShaderCache.h"
#include "VideoCommon/ImageWrite.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/TextureConfig.h"
#include "VideoCommon/VideoConfig.h"
namespace DX11
{
static std::unique_ptr<PSTextureEncoder> g_encoder;
void TextureCache::CopyEFB(AbstractStagingTexture* dst, const EFBCopyParams& params,
u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
const EFBRectangle& src_rect, bool scale_by_half, float y_scale,
float gamma, bool clamp_top, bool clamp_bottom,
const CopyFilterCoefficientArray& filter_coefficients)
{
g_encoder->Encode(dst, params, native_width, bytes_per_row, num_blocks_y, memory_stride, src_rect,
scale_by_half, y_scale, gamma, clamp_top, clamp_bottom, filter_coefficients);
}
const char palette_shader[] =
R"HLSL(
sampler samp0 : register(s0);
Texture2DArray Tex0 : register(t0);
Buffer<uint> Tex1 : register(t1);
uniform float Multiply;
uint Convert3To8(uint v)
{
// Swizzle bits: 00000123 -> 12312312
return (v << 5) | (v << 2) | (v >> 1);
}
uint Convert4To8(uint v)
{
// Swizzle bits: 00001234 -> 12341234
return (v << 4) | v;
}
uint Convert5To8(uint v)
{
// Swizzle bits: 00012345 -> 12345123
return (v << 3) | (v >> 2);
}
uint Convert6To8(uint v)
{
// Swizzle bits: 00123456 -> 12345612
return (v << 2) | (v >> 4);
}
float4 DecodePixel_RGB5A3(uint val)
{
int r,g,b,a;
if ((val&0x8000))
{
r=Convert5To8((val>>10) & 0x1f);
g=Convert5To8((val>>5 ) & 0x1f);
b=Convert5To8((val ) & 0x1f);
a=0xFF;
}
else
{
a=Convert3To8((val>>12) & 0x7);
r=Convert4To8((val>>8 ) & 0xf);
g=Convert4To8((val>>4 ) & 0xf);
b=Convert4To8((val ) & 0xf);
}
return float4(r, g, b, a) / 255;
}
float4 DecodePixel_RGB565(uint val)
{
int r, g, b, a;
r = Convert5To8((val >> 11) & 0x1f);
g = Convert6To8((val >> 5) & 0x3f);
b = Convert5To8((val) & 0x1f);
a = 0xFF;
return float4(r, g, b, a) / 255;
}
float4 DecodePixel_IA8(uint val)
{
int i = val & 0xFF;
int a = val >> 8;
return float4(i, i, i, a) / 255;
}
void main(
out float4 ocol0 : SV_Target,
in float4 pos : SV_Position,
in float3 uv0 : TEXCOORD0)
{
uint src = round(Tex0.Sample(samp0,uv0) * Multiply).r;
src = Tex1.Load(src);
src = ((src << 8) & 0xFF00) | (src >> 8);
ocol0 = DECODE(src);
}
)HLSL";
void TextureCache::ConvertTexture(TCacheEntry* destination, TCacheEntry* source,
const void* palette, TLUTFormat format)
{
DXTexture* source_texture = static_cast<DXTexture*>(source->texture.get());
DXTexture* destination_texture = static_cast<DXTexture*>(destination->texture.get());
g_renderer->ResetAPIState();
// stretch picture with increased internal resolution
const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, static_cast<float>(source->GetWidth()),
static_cast<float>(source->GetHeight()));
D3D::context->RSSetViewports(1, &vp);
D3D11_BOX box{0, 0, 0, 512, 1, 1};
D3D::context->UpdateSubresource(palette_buf, 0, &box, palette, 0, 0);
D3D::stateman->SetTexture(1, palette_buf_srv);
// TODO: Add support for C14X2 format. (Different multiplier, more palette entries.)
float params[8] = {source->format == TextureFormat::I4 ? 15.f : 255.f};
D3D::context->UpdateSubresource(uniform_buffer, 0, nullptr, &params, 0, 0);
D3D::stateman->SetPixelConstants(uniform_buffer);
const D3D11_RECT sourcerect = CD3D11_RECT(0, 0, source->GetWidth(), source->GetHeight());
D3D::SetPointCopySampler();
// Make sure we don't draw with the texture set as both a source and target.
// (This can happen because we don't unbind textures when we free them.)
D3D::stateman->UnsetTexture(destination_texture->GetRawTexIdentifier()->GetSRV());
D3D::stateman->Apply();
D3D::context->OMSetRenderTargets(1, &destination_texture->GetRawTexIdentifier()->GetRTV(),
nullptr);
// Create texture copy
D3D::drawShadedTexQuad(
source_texture->GetRawTexIdentifier()->GetSRV(), &sourcerect, source->GetWidth(),
source->GetHeight(), palette_pixel_shader[static_cast<int>(format)],
VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(),
GeometryShaderCache::GetCopyGeometryShader());
g_renderer->RestoreAPIState();
}
ID3D11PixelShader* GetConvertShader(const char* Type)
{
std::string shader = "#define DECODE DecodePixel_";
shader.append(Type);
shader.append("\n");
shader.append(palette_shader);
return D3D::CompileAndCreatePixelShader(shader);
}
TextureCache::TextureCache()
{
// FIXME: Is it safe here?
g_encoder = std::make_unique<PSTextureEncoder>();
g_encoder->Init();
palette_buf = nullptr;
palette_buf_srv = nullptr;
uniform_buffer = nullptr;
palette_pixel_shader[static_cast<int>(TLUTFormat::IA8)] = GetConvertShader("IA8");
palette_pixel_shader[static_cast<int>(TLUTFormat::RGB565)] = GetConvertShader("RGB565");
palette_pixel_shader[static_cast<int>(TLUTFormat::RGB5A3)] = GetConvertShader("RGB5A3");
auto lutBd = CD3D11_BUFFER_DESC(sizeof(u16) * 256, D3D11_BIND_SHADER_RESOURCE);
HRESULT hr = D3D::device->CreateBuffer(&lutBd, nullptr, &palette_buf);
CHECK(SUCCEEDED(hr), "create palette decoder lut buffer");
D3D::SetDebugObjectName(palette_buf, "texture decoder lut buffer");
// TODO: C14X2 format.
auto outlutUavDesc =
CD3D11_SHADER_RESOURCE_VIEW_DESC(palette_buf, DXGI_FORMAT_R16_UINT, 0, 256, 0);
hr = D3D::device->CreateShaderResourceView(palette_buf, &outlutUavDesc, &palette_buf_srv);
CHECK(SUCCEEDED(hr), "create palette decoder lut srv");
D3D::SetDebugObjectName(palette_buf_srv, "texture decoder lut srv");
const D3D11_BUFFER_DESC cbdesc =
CD3D11_BUFFER_DESC(sizeof(float) * 8, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DEFAULT);
hr = D3D::device->CreateBuffer(&cbdesc, nullptr, &uniform_buffer);
CHECK(SUCCEEDED(hr), "Create palette decoder constant buffer");
D3D::SetDebugObjectName(uniform_buffer,
"a constant buffer used in TextureCache::CopyRenderTargetToTexture");
}
TextureCache::~TextureCache()
{
g_encoder->Shutdown();
g_encoder.reset();
SAFE_RELEASE(palette_buf);
SAFE_RELEASE(palette_buf_srv);
SAFE_RELEASE(uniform_buffer);
for (auto*& shader : palette_pixel_shader)
SAFE_RELEASE(shader);
for (auto& iter : m_efb_to_tex_pixel_shaders)
SAFE_RELEASE(iter.second);
}
void TextureCache::CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy,
const EFBRectangle& src_rect, bool scale_by_half,
EFBCopyFormat dst_format, bool is_intensity, float gamma,
bool clamp_top, bool clamp_bottom,
const CopyFilterCoefficientArray& filter_coefficients)
{
auto* destination_texture = static_cast<DXTexture*>(entry->texture.get());
bool multisampled = g_ActiveConfig.iMultisamples > 1;
ID3D11ShaderResourceView* efb_tex_srv;
if (multisampled)
{
efb_tex_srv = is_depth_copy ? FramebufferManager::GetResolvedEFBDepthTexture()->GetSRV() :
FramebufferManager::GetResolvedEFBColorTexture()->GetSRV();
}
else
{
efb_tex_srv = is_depth_copy ? FramebufferManager::GetEFBDepthTexture()->GetSRV() :
FramebufferManager::GetEFBColorTexture()->GetSRV();
}
auto uid = TextureConversionShaderGen::GetShaderUid(dst_format, is_depth_copy, is_intensity,
scale_by_half,
NeedsCopyFilterInShader(filter_coefficients));
ID3D11PixelShader* pixel_shader = GetEFBToTexPixelShader(uid);
if (!pixel_shader)
return;
g_renderer->ResetAPIState();
// stretch picture with increased internal resolution
const D3D11_VIEWPORT vp =
CD3D11_VIEWPORT(0.f, 0.f, static_cast<float>(destination_texture->GetConfig().width),
static_cast<float>(destination_texture->GetConfig().height));
D3D::context->RSSetViewports(1, &vp);
const TargetRectangle targetSource = g_renderer->ConvertEFBRectangle(src_rect);
// TODO: try targetSource.asRECT();
const D3D11_RECT sourcerect =
CD3D11_RECT(targetSource.left, targetSource.top, targetSource.right, targetSource.bottom);
// Use linear filtering if (bScaleByHalf), use point filtering otherwise
if (scale_by_half)
D3D::SetLinearCopySampler();
else
D3D::SetPointCopySampler();
struct PixelConstants
{
float filter_coefficients[3];
float gamma_rcp;
float clamp_top;
float clamp_bottom;
float pixel_height;
u32 padding;
};
PixelConstants constants;
for (size_t i = 0; i < filter_coefficients.size(); i++)
constants.filter_coefficients[i] = filter_coefficients[i];
constants.gamma_rcp = 1.0f / gamma;
constants.clamp_top = clamp_top ? src_rect.top / float(EFB_HEIGHT) : 0.0f;
constants.clamp_bottom = clamp_bottom ? src_rect.bottom / float(EFB_HEIGHT) : 1.0f;
constants.pixel_height =
g_ActiveConfig.bCopyEFBScaled ? 1.0f / g_renderer->GetTargetHeight() : 1.0f / EFB_HEIGHT;
constants.padding = 0;
D3D::context->UpdateSubresource(uniform_buffer, 0, nullptr, &constants, 0, 0);
D3D::stateman->SetPixelConstants(uniform_buffer);
// Make sure we don't draw with the texture set as both a source and target.
// (This can happen because we don't unbind textures when we free them.)
D3D::stateman->UnsetTexture(destination_texture->GetRawTexIdentifier()->GetSRV());
D3D::stateman->Apply();
D3D::context->OMSetRenderTargets(1, &destination_texture->GetRawTexIdentifier()->GetRTV(),
nullptr);
// Create texture copy
D3D::drawShadedTexQuad(
efb_tex_srv, &sourcerect, g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight(),
pixel_shader, VertexShaderCache::GetSimpleVertexShader(),
VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader());
g_renderer->RestoreAPIState();
}
ID3D11PixelShader*
TextureCache::GetEFBToTexPixelShader(const TextureConversionShaderGen::TCShaderUid& uid)
{
auto iter = m_efb_to_tex_pixel_shaders.find(uid);
if (iter != m_efb_to_tex_pixel_shaders.end())
return iter->second;
ShaderCode code = TextureConversionShaderGen::GenerateShader(APIType::D3D, uid.GetUidData());
ID3D11PixelShader* shader = D3D::CompileAndCreatePixelShader(code.GetBuffer());
m_efb_to_tex_pixel_shaders.emplace(uid, shader);
return shader;
}
} // namespace DX11

View File

@ -1,49 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <map>
#include "VideoBackends/D3D/D3DTexture.h"
#include "VideoCommon/TextureCacheBase.h"
#include "VideoCommon/TextureConverterShaderGen.h"
class AbstractTexture;
struct TextureConfig;
namespace DX11
{
class TextureCache : public TextureCacheBase
{
public:
TextureCache();
~TextureCache();
private:
void ConvertTexture(TCacheEntry* destination, TCacheEntry* source, const void* palette,
TLUTFormat format) override;
void CopyEFB(AbstractStagingTexture* dst, const EFBCopyParams& params, u32 native_width,
u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect,
bool scale_by_half, float y_scale, float gamma, bool clamp_top, bool clamp_bottom,
const CopyFilterCoefficientArray& filter_coefficients) override;
void CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, const EFBRectangle& src_rect,
bool scale_by_half, EFBCopyFormat dst_format, bool is_intensity,
float gamma, bool clamp_top, bool clamp_bottom,
const CopyFilterCoefficientArray& filter_coefficients) override;
bool CompileShaders() override { return true; }
void DeleteShaders() override {}
ID3D11PixelShader* GetEFBToTexPixelShader(const TextureConversionShaderGen::TCShaderUid& uid);
ID3D11Buffer* palette_buf;
ID3D11ShaderResourceView* palette_buf_srv;
ID3D11Buffer* uniform_buffer;
ID3D11PixelShader* palette_pixel_shader[3];
std::map<TextureConversionShaderGen::TCShaderUid, ID3D11PixelShader*> m_efb_to_tex_pixel_shaders;
};
}

View File

@ -7,24 +7,19 @@
#include <d3d11.h>
#include "Common/Align.h"
#include "Common/Assert.h"
#include "Common/CommonTypes.h"
#include "VideoBackends/D3D/BoundingBox.h"
#include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DState.h"
#include "VideoBackends/D3D/FramebufferManager.h"
#include "VideoBackends/D3D/GeometryShaderCache.h"
#include "VideoBackends/D3D/PixelShaderCache.h"
#include "VideoBackends/D3D/Render.h"
#include "VideoBackends/D3D/VertexShaderCache.h"
#include "VideoCommon/BoundingBox.h"
#include "VideoCommon/Debugger.h"
#include "VideoCommon/GeometryShaderManager.h"
#include "VideoCommon/IndexGenerator.h"
#include "VideoCommon/NativeVertexFormat.h"
#include "VideoCommon/PixelShaderManager.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/Statistics.h"
#include "VideoCommon/VertexLoaderManager.h"
#include "VideoCommon/VertexShaderManager.h"
@ -32,11 +27,6 @@
namespace DX11
{
// TODO: Find sensible values for these two
const u32 MAX_IBUFFER_SIZE = VertexManager::MAXIBUFFERSIZE * sizeof(u16) * 8;
const u32 MAX_VBUFFER_SIZE = VertexManager::MAXVBUFFERSIZE;
const u32 MAX_BUFFER_SIZE = MAX_IBUFFER_SIZE + MAX_VBUFFER_SIZE;
static ID3D11Buffer* AllocateConstantBuffer(u32 size)
{
const u32 cbsize = Common::AlignUp(size, 16u); // must be a multiple of 16
@ -59,71 +49,172 @@ static void UpdateConstantBuffer(ID3D11Buffer* const buffer, const void* data, u
ADDSTAT(stats.thisFrame.bytesUniformStreamed, data_size);
}
void VertexManager::CreateDeviceObjects()
static ID3D11ShaderResourceView*
CreateTexelBufferView(ID3D11Buffer* buffer, TexelBufferFormat format, DXGI_FORMAT srv_format)
{
D3D11_BUFFER_DESC bufdesc =
CD3D11_BUFFER_DESC(MAX_BUFFER_SIZE, D3D11_BIND_INDEX_BUFFER | D3D11_BIND_VERTEX_BUFFER,
D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
ID3D11ShaderResourceView* srv;
CD3D11_SHADER_RESOURCE_VIEW_DESC srv_desc(buffer, srv_format, 0,
VertexManager::TEXEL_STREAM_BUFFER_SIZE /
VertexManager::GetTexelBufferElementSize(format));
CHECK(SUCCEEDED(D3D::device->CreateShaderResourceView(buffer, &srv_desc, &srv)),
"Create SRV for texel buffer");
return srv;
}
for (int i = 0; i < MAX_BUFFER_COUNT; i++)
VertexManager::VertexManager() = default;
VertexManager::~VertexManager()
{
for (auto& srv_ptr : m_texel_buffer_views)
SAFE_RELEASE(srv_ptr);
SAFE_RELEASE(m_texel_buffer);
SAFE_RELEASE(m_pixel_constant_buffer);
SAFE_RELEASE(m_geometry_constant_buffer);
SAFE_RELEASE(m_vertex_constant_buffer);
for (auto& buffer : m_buffers)
SAFE_RELEASE(buffer);
}
bool VertexManager::Initialize()
{
if (!VertexManagerBase::Initialize())
return false;
CD3D11_BUFFER_DESC bufdesc((VERTEX_STREAM_BUFFER_SIZE + INDEX_STREAM_BUFFER_SIZE) / BUFFER_COUNT,
D3D11_BIND_INDEX_BUFFER | D3D11_BIND_VERTEX_BUFFER,
D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
for (int i = 0; i < BUFFER_COUNT; i++)
{
m_buffers[i] = nullptr;
CHECK(SUCCEEDED(D3D::device->CreateBuffer(&bufdesc, nullptr, &m_buffers[i])),
"Failed to create buffer.");
D3D::SetDebugObjectName(m_buffers[i], "Buffer of VertexManager");
}
m_buffer_cursor = MAX_BUFFER_SIZE;
m_vertex_constant_buffer = AllocateConstantBuffer(sizeof(VertexShaderConstants));
m_geometry_constant_buffer = AllocateConstantBuffer(sizeof(GeometryShaderConstants));
m_pixel_constant_buffer = AllocateConstantBuffer(sizeof(PixelShaderConstants));
}
if (!m_vertex_constant_buffer || !m_geometry_constant_buffer || !m_pixel_constant_buffer)
return false;
void VertexManager::DestroyDeviceObjects()
{
SAFE_RELEASE(m_pixel_constant_buffer);
SAFE_RELEASE(m_geometry_constant_buffer);
SAFE_RELEASE(m_vertex_constant_buffer);
for (int i = 0; i < MAX_BUFFER_COUNT; i++)
CD3D11_BUFFER_DESC texel_buf_desc(TEXEL_STREAM_BUFFER_SIZE, D3D11_BIND_SHADER_RESOURCE,
D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
CHECK(SUCCEEDED(D3D::device->CreateBuffer(&texel_buf_desc, nullptr, &m_texel_buffer)),
"Creating texel buffer failed");
if (!m_texel_buffer)
return false;
static constexpr std::array<std::pair<TexelBufferFormat, DXGI_FORMAT>, NUM_TEXEL_BUFFER_FORMATS>
format_mapping = {{
{TEXEL_BUFFER_FORMAT_R8_UINT, DXGI_FORMAT_R8_UINT},
{TEXEL_BUFFER_FORMAT_R16_UINT, DXGI_FORMAT_R16_UINT},
{TEXEL_BUFFER_FORMAT_RGBA8_UINT, DXGI_FORMAT_R8G8B8A8_UNORM},
{TEXEL_BUFFER_FORMAT_R32G32_UINT, DXGI_FORMAT_R32G32_UINT},
}};
for (const auto& it : format_mapping)
{
SAFE_RELEASE(m_buffers[i]);
m_texel_buffer_views[it.first] = CreateTexelBufferView(m_texel_buffer, it.first, it.second);
if (!m_texel_buffer_views[it.first])
return false;
}
}
VertexManager::VertexManager()
{
m_staging_vertex_buffer.resize(MAXVBUFFERSIZE);
m_cur_buffer_pointer = m_base_buffer_pointer = &m_staging_vertex_buffer[0];
m_end_buffer_pointer = m_base_buffer_pointer + m_staging_vertex_buffer.size();
m_staging_index_buffer.resize(MAXIBUFFERSIZE);
CreateDeviceObjects();
}
VertexManager::~VertexManager()
{
DestroyDeviceObjects();
return true;
}
void VertexManager::UploadUtilityUniforms(const void* uniforms, u32 uniforms_size)
{
// Just use the one buffer for all three.
InvalidateConstants();
UpdateConstantBuffer(m_vertex_constant_buffer, uniforms, uniforms_size);
D3D::stateman->SetVertexConstants(m_vertex_constant_buffer);
D3D::stateman->SetGeometryConstants(m_vertex_constant_buffer);
D3D::stateman->SetPixelConstants(m_vertex_constant_buffer);
VertexShaderManager::dirty = true;
GeometryShaderManager::dirty = true;
PixelShaderManager::dirty = true;
}
void VertexManager::ResetBuffer(u32 vertex_stride, bool cull_all)
bool VertexManager::MapTexelBuffer(u32 required_size, D3D11_MAPPED_SUBRESOURCE& sr)
{
if ((m_texel_buffer_offset + required_size) > TEXEL_STREAM_BUFFER_SIZE)
{
// Restart buffer.
HRESULT hr = D3D::context->Map(m_texel_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &sr);
CHECK(SUCCEEDED(hr), "Map texel buffer");
if (FAILED(hr))
return false;
m_texel_buffer_offset = 0;
}
else
{
// Don't overwrite the earlier-used space.
HRESULT hr = D3D::context->Map(m_texel_buffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &sr);
CHECK(SUCCEEDED(hr), "Map texel buffer");
if (FAILED(hr))
return false;
}
return true;
}
bool VertexManager::UploadTexelBuffer(const void* data, u32 data_size, TexelBufferFormat format,
u32* out_offset)
{
if (data_size > TEXEL_STREAM_BUFFER_SIZE)
return false;
const u32 elem_size = GetTexelBufferElementSize(format);
m_texel_buffer_offset = Common::AlignUp(m_texel_buffer_offset, elem_size);
D3D11_MAPPED_SUBRESOURCE sr;
if (!MapTexelBuffer(data_size, sr))
return false;
*out_offset = m_texel_buffer_offset / elem_size;
std::memcpy(static_cast<u8*>(sr.pData) + m_texel_buffer_offset, data, data_size);
ADDSTAT(stats.thisFrame.bytesUniformStreamed, data_size);
m_texel_buffer_offset += data_size;
D3D::context->Unmap(m_texel_buffer, 0);
D3D::stateman->SetTexture(0, m_texel_buffer_views[static_cast<size_t>(format)]);
return true;
}
bool VertexManager::UploadTexelBuffer(const void* data, u32 data_size, TexelBufferFormat format,
u32* out_offset, const void* palette_data, u32 palette_size,
TexelBufferFormat palette_format, u32* out_palette_offset)
{
const u32 elem_size = GetTexelBufferElementSize(format);
const u32 palette_elem_size = GetTexelBufferElementSize(palette_format);
const u32 reserve_size = data_size + palette_size + palette_elem_size;
if (reserve_size > TEXEL_STREAM_BUFFER_SIZE)
return false;
m_texel_buffer_offset = Common::AlignUp(m_texel_buffer_offset, elem_size);
D3D11_MAPPED_SUBRESOURCE sr;
if (!MapTexelBuffer(reserve_size, sr))
return false;
const u32 palette_byte_offset = Common::AlignUp(data_size, palette_elem_size);
std::memcpy(static_cast<u8*>(sr.pData) + m_texel_buffer_offset, data, data_size);
std::memcpy(static_cast<u8*>(sr.pData) + m_texel_buffer_offset + palette_byte_offset,
palette_data, palette_size);
ADDSTAT(stats.thisFrame.bytesUniformStreamed, palette_byte_offset + palette_size);
*out_offset = m_texel_buffer_offset / elem_size;
*out_palette_offset = (m_texel_buffer_offset + palette_byte_offset) / palette_elem_size;
m_texel_buffer_offset += palette_byte_offset + palette_size;
D3D::context->Unmap(m_texel_buffer, 0);
D3D::stateman->SetTexture(0, m_texel_buffer_views[static_cast<size_t>(format)]);
D3D::stateman->SetTexture(1, m_texel_buffer_views[static_cast<size_t>(palette_format)]);
return true;
}
void VertexManager::ResetBuffer(u32 vertex_stride)
{
m_base_buffer_pointer = m_cpu_vertex_buffer.data();
m_cur_buffer_pointer = m_base_buffer_pointer;
IndexGenerator::Start(m_staging_index_buffer.data());
m_end_buffer_pointer = m_base_buffer_pointer + m_cpu_vertex_buffer.size();
IndexGenerator::Start(m_cpu_index_buffer.data());
}
void VertexManager::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices,
@ -143,10 +234,10 @@ void VertexManager::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_in
}
D3D11_MAP MapType = D3D11_MAP_WRITE_NO_OVERWRITE;
if (cursor + totalBufferSize >= MAX_BUFFER_SIZE)
if (cursor + totalBufferSize >= BUFFER_SIZE)
{
// Wrap around
m_current_buffer = (m_current_buffer + 1) % MAX_BUFFER_COUNT;
m_current_buffer = (m_current_buffer + 1) % BUFFER_COUNT;
cursor = 0;
MapType = D3D11_MAP_WRITE_DISCARD;
}
@ -159,8 +250,7 @@ void VertexManager::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_in
if (vertexBufferSize > 0)
std::memcpy(mappedData + cursor, m_base_buffer_pointer, vertexBufferSize);
if (indexBufferSize > 0)
std::memcpy(mappedData + cursor + vertexBufferSize, m_staging_index_buffer.data(),
indexBufferSize);
std::memcpy(mappedData + cursor + vertexBufferSize, m_cpu_index_buffer.data(), indexBufferSize);
D3D::context->Unmap(m_buffers[m_current_buffer], 0);
m_buffer_cursor = cursor + totalBufferSize;
@ -172,7 +262,7 @@ void VertexManager::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_in
D3D::stateman->SetIndexBuffer(m_buffers[m_current_buffer]);
}
void VertexManager::UploadConstants()
void VertexManager::UploadUniforms()
{
if (VertexShaderManager::dirty)
{
@ -199,20 +289,4 @@ void VertexManager::UploadConstants()
D3D::stateman->SetVertexConstants(m_vertex_constant_buffer);
D3D::stateman->SetGeometryConstants(m_geometry_constant_buffer);
}
void VertexManager::DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_vertex)
{
FramebufferManager::SetIntegerEFBRenderTarget(
m_current_pipeline_config.blending_state.logicopenable);
if (g_ActiveConfig.backend_info.bSupportsBBox && BoundingBox::active)
{
D3D::context->OMSetRenderTargetsAndUnorderedAccessViews(
D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr, 2, 1, &BBox::GetUAV(),
nullptr);
}
D3D::stateman->Apply();
D3D::context->DrawIndexed(num_indices, base_index, base_vertex);
}
} // namespace DX11

View File

@ -18,13 +18,12 @@ struct ID3D11Buffer;
namespace DX11
{
class D3DBlob;
class D3DVertexFormat : public NativeVertexFormat
{
public:
D3DVertexFormat(const PortableVertexDeclaration& vtx_decl);
~D3DVertexFormat();
ID3D11InputLayout* GetInputLayout(D3DBlob* vs_bytecode);
ID3D11InputLayout* GetInputLayout(const void* vs_bytecode, size_t vs_bytecode_size);
private:
std::array<D3D11_INPUT_ELEMENT_DESC, 32> m_elems{};
@ -39,35 +38,39 @@ public:
VertexManager();
~VertexManager();
std::unique_ptr<NativeVertexFormat>
CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override;
bool Initialize();
void UploadUtilityUniforms(const void* uniforms, u32 uniforms_size) override;
bool UploadTexelBuffer(const void* data, u32 data_size, TexelBufferFormat format,
u32* out_offset) override;
bool UploadTexelBuffer(const void* data, u32 data_size, TexelBufferFormat format, u32* out_offset,
const void* palette_data, u32 palette_size,
TexelBufferFormat palette_format, u32* out_palette_offset) override;
protected:
void CreateDeviceObjects() override;
void DestroyDeviceObjects() override;
void ResetBuffer(u32 vertex_stride, bool cull_all) override;
void ResetBuffer(u32 vertex_stride) override;
void CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices, u32* out_base_vertex,
u32* out_base_index) override;
void UploadConstants() override;
void DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_vertex) override;
void UploadUniforms() override;
private:
enum
{
MAX_BUFFER_COUNT = 2
};
ID3D11Buffer* m_buffers[MAX_BUFFER_COUNT] = {};
static constexpr u32 BUFFER_COUNT = 2;
static constexpr u32 BUFFER_SIZE =
(VERTEX_STREAM_BUFFER_SIZE + INDEX_STREAM_BUFFER_SIZE) / BUFFER_COUNT;
bool MapTexelBuffer(u32 required_size, D3D11_MAPPED_SUBRESOURCE& sr);
ID3D11Buffer* m_buffers[BUFFER_COUNT] = {};
u32 m_current_buffer = 0;
u32 m_buffer_cursor = 0;
std::vector<u8> m_staging_vertex_buffer;
std::vector<u16> m_staging_index_buffer;
ID3D11Buffer* m_vertex_constant_buffer = nullptr;
ID3D11Buffer* m_geometry_constant_buffer = nullptr;
ID3D11Buffer* m_pixel_constant_buffer = nullptr;
ID3D11Buffer* m_texel_buffer = nullptr;
std::array<ID3D11ShaderResourceView*, NUM_TEXEL_BUFFER_FORMATS> m_texel_buffer_views;
u32 m_texel_buffer_offset = 0;
};
} // namespace DX11

View File

@ -1,136 +0,0 @@
// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <string>
#include "Common/CommonTypes.h"
#include "Common/FileUtil.h"
#include "Common/MsgHandler.h"
#include "Common/StringUtil.h"
#include "Core/ConfigManager.h"
#include "Core/Host.h"
#include "VideoBackends/D3D/D3DShader.h"
#include "VideoBackends/D3D/D3DState.h"
#include "VideoBackends/D3D/VertexManager.h"
#include "VideoBackends/D3D/VertexShaderCache.h"
#include "VideoCommon/Debugger.h"
#include "VideoCommon/Statistics.h"
#include "VideoCommon/UberShaderVertex.h"
#include "VideoCommon/VertexLoaderManager.h"
#include "VideoCommon/VertexShaderGen.h"
namespace DX11
{
static ID3D11VertexShader* SimpleVertexShader = nullptr;
static ID3D11VertexShader* ClearVertexShader = nullptr;
static ID3D11InputLayout* SimpleLayout = nullptr;
static ID3D11InputLayout* ClearLayout = nullptr;
ID3D11VertexShader* VertexShaderCache::GetSimpleVertexShader()
{
return SimpleVertexShader;
}
ID3D11VertexShader* VertexShaderCache::GetClearVertexShader()
{
return ClearVertexShader;
}
ID3D11InputLayout* VertexShaderCache::GetSimpleInputLayout()
{
return SimpleLayout;
}
ID3D11InputLayout* VertexShaderCache::GetClearInputLayout()
{
return ClearLayout;
}
// this class will load the precompiled shaders into our cache
template <typename UidType>
class VertexShaderCacheInserter : public LinearDiskCacheReader<UidType, u8>
{
public:
void Read(const UidType& key, const u8* value, u32 value_size)
{
D3DBlob* blob = new D3DBlob(value_size, value);
VertexShaderCache::InsertByteCode(key, blob);
blob->Release();
}
};
const char simple_shader_code[] = {
"struct VSOUTPUT\n"
"{\n"
"float4 vPosition : POSITION;\n"
"float3 vTexCoord : TEXCOORD0;\n"
"};\n"
"VSOUTPUT main(float4 inPosition : POSITION,float3 inTEX0 : TEXCOORD0)\n"
"{\n"
"VSOUTPUT OUT;\n"
"OUT.vPosition = inPosition;\n"
"OUT.vTexCoord = inTEX0;\n"
"return OUT;\n"
"}\n"};
const char clear_shader_code[] = {
"struct VSOUTPUT\n"
"{\n"
"float4 vPosition : POSITION;\n"
"float4 vColor0 : COLOR0;\n"
"};\n"
"VSOUTPUT main(float4 inPosition : POSITION,float4 inColor0: COLOR0)\n"
"{\n"
"VSOUTPUT OUT;\n"
"OUT.vPosition = inPosition;\n"
"OUT.vColor0 = inColor0;\n"
"return OUT;\n"
"}\n"};
void VertexShaderCache::Init()
{
const D3D11_INPUT_ELEMENT_DESC simpleelems[2] = {
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
};
const D3D11_INPUT_ELEMENT_DESC clearelems[2] = {
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
};
D3DBlob* blob;
D3D::CompileVertexShader(simple_shader_code, &blob);
D3D::device->CreateInputLayout(simpleelems, 2, blob->Data(), blob->Size(), &SimpleLayout);
SimpleVertexShader = D3D::CreateVertexShaderFromByteCode(blob);
if (SimpleLayout == nullptr || SimpleVertexShader == nullptr)
PanicAlert("Failed to create simple vertex shader or input layout at %s %d\n", __FILE__,
__LINE__);
blob->Release();
D3D::SetDebugObjectName(SimpleVertexShader, "simple vertex shader");
D3D::SetDebugObjectName(SimpleLayout, "simple input layout");
D3D::CompileVertexShader(clear_shader_code, &blob);
D3D::device->CreateInputLayout(clearelems, 2, blob->Data(), blob->Size(), &ClearLayout);
ClearVertexShader = D3D::CreateVertexShaderFromByteCode(blob);
if (ClearLayout == nullptr || ClearVertexShader == nullptr)
PanicAlert("Failed to create clear vertex shader or input layout at %s %d\n", __FILE__,
__LINE__);
blob->Release();
D3D::SetDebugObjectName(ClearVertexShader, "clear vertex shader");
D3D::SetDebugObjectName(ClearLayout, "clear input layout");
SETSTAT(stats.numVertexShadersCreated, 0);
SETSTAT(stats.numVertexShadersAlive, 0);
}
void VertexShaderCache::Shutdown()
{
SAFE_RELEASE(SimpleVertexShader);
SAFE_RELEASE(ClearVertexShader);
SAFE_RELEASE(SimpleLayout);
SAFE_RELEASE(ClearLayout);
}
} // namespace DX11

View File

@ -1,32 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <map>
#include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DBlob.h"
#include "VideoCommon/AsyncShaderCompiler.h"
#include "VideoCommon/UberShaderVertex.h"
#include "VideoCommon/VertexShaderGen.h"
namespace DX11
{
class D3DVertexFormat;
class VertexShaderCache
{
public:
static void Init();
static void Shutdown();
static ID3D11VertexShader* GetSimpleVertexShader();
static ID3D11VertexShader* GetClearVertexShader();
static ID3D11InputLayout* GetSimpleInputLayout();
static ID3D11InputLayout* GetClearInputLayout();
};
} // namespace DX11

View File

@ -12,17 +12,14 @@
#include "VideoBackends/D3D/BoundingBox.h"
#include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DUtil.h"
#include "VideoBackends/D3D/GeometryShaderCache.h"
#include "VideoBackends/D3D/PerfQuery.h"
#include "VideoBackends/D3D/PixelShaderCache.h"
#include "VideoBackends/D3D/Render.h"
#include "VideoBackends/D3D/TextureCache.h"
#include "VideoBackends/D3D/VertexManager.h"
#include "VideoBackends/D3D/VertexShaderCache.h"
#include "VideoBackends/D3D/VideoBackend.h"
#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/ShaderCache.h"
#include "VideoCommon/TextureCacheBase.h"
#include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoConfig.h"
@ -51,6 +48,7 @@ void VideoBackend::InitBackendInfo()
g_Config.backend_info.api_type = APIType::D3D;
g_Config.backend_info.MaxTextureSize = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
g_Config.backend_info.bUsesLowerLeftOrigin = false;
g_Config.backend_info.bSupportsExclusiveFullscreen = true;
g_Config.backend_info.bSupportsDualSourceBlend = true;
g_Config.backend_info.bSupportsPrimitiveRestart = true;
@ -58,16 +56,17 @@ void VideoBackend::InitBackendInfo()
g_Config.backend_info.bSupportsGeometryShaders = true;
g_Config.backend_info.bSupportsComputeShaders = false;
g_Config.backend_info.bSupports3DVision = true;
g_Config.backend_info.bSupportsPostProcessing = false;
g_Config.backend_info.bSupportsPostProcessing = true;
g_Config.backend_info.bSupportsPaletteConversion = true;
g_Config.backend_info.bSupportsClipControl = true;
g_Config.backend_info.bSupportsDepthClamp = true;
g_Config.backend_info.bSupportsReversedDepthRange = false;
g_Config.backend_info.bSupportsLogicOp = true;
g_Config.backend_info.bSupportsMultithreading = false;
g_Config.backend_info.bSupportsGPUTextureDecoding = false;
g_Config.backend_info.bSupportsGPUTextureDecoding = true;
g_Config.backend_info.bSupportsST3CTextures = false;
g_Config.backend_info.bSupportsCopyToVram = true;
g_Config.backend_info.bSupportsLargePoints = false;
g_Config.backend_info.bSupportsBitfield = false;
g_Config.backend_info.bSupportsDynamicSamplerIndexing = false;
g_Config.backend_info.bSupportsBPTCTextures = false;
@ -149,21 +148,20 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
// internal interfaces
g_renderer =
std::make_unique<Renderer>(backbuffer_width, backbuffer_height, wsi.render_surface_scale);
g_shader_cache = std::make_unique<VideoCommon::ShaderCache>();
g_texture_cache = std::make_unique<TextureCache>();
g_vertex_manager = std::make_unique<VertexManager>();
g_shader_cache = std::make_unique<VideoCommon::ShaderCache>();
g_framebuffer_manager = std::make_unique<FramebufferManager>();
g_texture_cache = std::make_unique<TextureCacheBase>();
g_perf_query = std::make_unique<PerfQuery>();
VertexShaderCache::Init();
PixelShaderCache::Init();
GeometryShaderCache::Init();
if (!g_renderer->Initialize() || !g_shader_cache->Initialize())
if (!g_renderer->Initialize() || !g_vertex_manager->Initialize() ||
!g_shader_cache->Initialize() || !g_framebuffer_manager->Initialize() ||
!g_texture_cache->Initialize())
{
return false;
}
D3D::InitUtils();
BBox::Init();
g_shader_cache->InitializeShaderCache();
return true;
}
@ -172,16 +170,13 @@ void VideoBackend::Shutdown()
g_shader_cache->Shutdown();
g_renderer->Shutdown();
D3D::ShutdownUtils();
PixelShaderCache::Shutdown();
VertexShaderCache::Shutdown();
GeometryShaderCache::Shutdown();
BBox::Shutdown();
g_perf_query.reset();
g_vertex_manager.reset();
g_texture_cache.reset();
g_framebuffer_manager.reset();
g_shader_cache.reset();
g_vertex_manager.reset();
g_renderer.reset();
ShutdownShared();